Compare commits

...

2 Commits

Author SHA1 Message Date
d2ac82b478 新增和修正部分数据包 2024-12-11 03:39:12 +08:00
37106641a7 物品读取修正
移除部分DEBUG信息
2024-12-11 02:24:51 +08:00
31 changed files with 736 additions and 251 deletions

View File

@ -104,7 +104,7 @@ namespace PSO2SERVER
}
// Display all settings
DisplaySettings();
//DisplaySettings();
// Some settings require manual refreshing
SettingsChanged();

View File

@ -41,13 +41,6 @@ namespace PSO2SERVER.Models
public StorageInventory Extend1;
}
/// Player equiped item.
public struct EquipedItem
{
public PSO2Items item;
public uint unk;
}
internal class Inventory
{
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PSO2SERVER.Models
{
public enum ItemTypes
{
NoItem,
Weapon,
Clothing,
Consumable,
Camo,
Unit,
Unknown
}
[Flags]
public enum ItemFlags
{
Locked = 0x01,
BoundToOwner = 0x02
}
public enum ItemElement
{
None,
Fire,
Ice,
Lightning,
Wind,
Light,
Dark
}
}

View File

@ -12,8 +12,13 @@ namespace PSO2SERVER.Models
}
public class Mission
public struct Mission
{
/*5 - main
1 - daily
2 - weekly
7 - tier */
/// Mission type.
public uint MissionType; // Mission type.
public uint StartDate; // Mission start timestamp.
public uint EndDate; // Mission end timestamp.

View File

@ -1,5 +1,6 @@
using PSO2SERVER.Protocol;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
@ -246,77 +247,171 @@ namespace PSO2SERVER.Models
}
}
public enum ItemTypes
[StructLayout(LayoutKind.Sequential)]
public struct NamedId
{
NoItem,
Weapon,
Clothing,
Consumable,
Camo,
Unit,
Unknown
public string Name { get; set; }
public ItemId Id { get; set; }
}
[Flags]
public enum ItemFlags
[StructLayout(LayoutKind.Sequential)]
public struct CampaignItemDefinition
{
Locked = 0x01,
BoundToOwner = 0x02
/// <summary>
/// Campaign ID.
/// </summary>
public uint CampaignId; // Equivalent to u32
/// <summary>
/// Number of items in the following array.
/// </summary>
public uint ItemAmount; // Equivalent to u32
/// <summary>
/// Campaign items.
/// </summary>
public List<CampaignItem> Items; // Using List instead of fixed-size array
}
public enum ItemElement
[StructLayout(LayoutKind.Sequential)]
public struct CampaignItem
{
None,
Fire,
Ice,
Lightning,
Wind,
Light,
Dark
/// <summary>
/// Item ID.
/// </summary>
public ItemId Id; // Assuming ItemId is a type, use it as-is
/// <summary>
/// Item amount.
/// </summary>
public uint Amount; // Equivalent to u32
/// <summary>
/// Unknown field.
/// </summary>
public uint Unk; // Equivalent to u32
}
[StructLayout(LayoutKind.Sequential)]
public struct StorageInfo
{
/// <summary>
/// Total space in the storage.
/// </summary>
public uint TotalSpace; // Equivalent to u32
/// <summary>
/// Used space in the storage.
/// </summary>
public uint UsedSpace; // Equivalent to u32
/// <summary>
/// Storage ID.
/// </summary>
public byte StorageId; // Equivalent to u8
/// <summary>
/// Storage type (?).
/// </summary>
public byte StorageType; // Equivalent to u8
/// <summary>
/// Is the storage locked (?).
/// </summary>
public byte IsLocked; // Equivalent to u8
/// <summary>
/// Is the storage enabled (?).
/// </summary>
public byte IsEnabled; // Equivalent to u8
}
[StructLayout(LayoutKind.Sequential)]
public struct MaterialStorageItem
{
/// <summary>
/// Item category.
/// </summary>
public ushort Id; // Equivalent to u16
/// <summary>
/// Item ID.
/// </summary>
public ushort Subid; // Equivalent to u16
/// <summary>
/// Item amount.
/// </summary>
public ushort Amount; // Equivalent to u16
/// <summary>
/// Unknown field.
/// </summary>
public ushort Unk4; // Equivalent to u16
}
[StructLayout(LayoutKind.Sequential)]
public struct UUIDAmount
{
public ulong Uuid { get; set; }
public ushort Amount { get; set; }
public ushort Unk { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct EquipedItem
{
public PSO2Items Item { get; set; }
public uint Unk { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct MoveStorageItemRequest
{
public ulong Uuid { get; set; }
public byte Amount { get; set; }
public byte Unk { get; set; }
public ushort StorageId { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct NewStorageItem
{
public PSO2Items Item { get; set; }
public uint StorageId { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct NewInventoryItem
{
public PSO2Items Item { get; set; }
public ushort Amount { get; set; }
public ushort IsNew { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct UpdatedItem
{
public ulong Uuid { get; set; }
public uint NewAmount { get; set; }
public uint StorageId { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct UpdatedInventoryItem
{
public ulong Uuid { get; set; }
public ushort NewAmount { get; set; }
public ushort Moved { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct UpdatedStorageItem
{
public ulong Uuid { get; set; }
public ushort NewAmount { get; set; }
public ushort Moved { get; set; }
public uint StorageId { get; set; }
}
}
public static class AffixUtils
{
public static ushort[] ReadPackedAffixes(Stream reader)
{
byte[] packed = new byte[12];
reader.Read(packed, 0, packed.Length);
ushort[] affixes = new ushort[8];
for (int i = 0; i < 4; i++)
{
affixes[i * 2] = BitConverter.ToUInt16(new byte[] { packed[i * 3], (byte)((packed[i * 3 + 2] & 0xF0) >> 4) }, 0);
affixes[i * 2 + 1] = BitConverter.ToUInt16(new byte[] { packed[i * 3 + 1], (byte)(packed[i * 3 + 2] & 0xF) }, 0);
}
return affixes;
}
public static void WritePackedAffixes(ushort[] affixes, Stream writer)
{
byte[] packed = new byte[12];
for (int i = 0; i < 4; i++)
{
byte[] affix1 = BitConverter.GetBytes(affixes[i * 2]);
byte[] affix2 = BitConverter.GetBytes(affixes[i * 2 + 1]);
packed[i * 3] = affix1[0];
packed[i * 3 + 1] = affix2[0];
packed[i * 3 + 2] = (byte)((affix1[1] << 4) | (affix2[1] & 0xF));
}
writer.Write(packed, 0, packed.Length);
}
}
public class PacketError : Exception
{
public string PacketName { get; }
public string FieldName { get; }
public PacketError(string packetName, string fieldName, Exception innerException)
: base($"Error in packet '{packetName}', field '{fieldName}'", innerException)
{
PacketName = packetName;
FieldName = fieldName;
}
}

View File

@ -29,64 +29,36 @@ namespace PSO2SERVER.Models
}
// 对象头部结构体
public class ObjectHeader
public struct ObjectHeader
{
/// 对象的ID。
[JsonProperty("id")]
public uint ID { get; set; } = 0;
public uint ID { get; set; }
[JsonProperty("unk")]
public uint Padding { get; set; } = 0;
public uint Padding { get; set; }
/// 对象的类型。
[JsonProperty("entity_type")]
[JsonConverter(typeof(ObjectTypeConverter))]
/// 对象的类型。
public ObjectType ObjectType { get; set; } = ObjectType.Unknown;
public ObjectType ObjectType { get; set; }
/// 对象所在的区域ID。玩家对象没有设置这个字段。
[JsonProperty("map_id")]
public ushort MapID { get; set; } = 0;
//初始化结构体
public ObjectHeader()
{;
}
public struct ObjHeaderStruct
{
public uint ID { get; set; }
public uint Padding { get; set; }
public ObjectType ObjectType { get; set; }
public ushort MapID { get; set; }
// 结构体构造函数
public ObjHeaderStruct(uint id, uint padding, ObjectType objectType, ushort mapID)
{
ID = id;
Padding = padding;
ObjectType = objectType;
MapID = mapID;
}
// 结构体构造函数
public ObjHeaderStruct(uint id, ObjectType objectType)
{
ID = id;
Padding = 0;
ObjectType = objectType;
MapID = 0;
}
}
public ushort MapID { get; set; }
// 只包含ID和类型的构造函数
public ObjectHeader(uint id, ObjectType type)
public ObjectHeader(uint id, ObjectType objectType)
{
ID = id;
ObjectType = type;
Padding = 0;
ObjectType = objectType;
MapID = 0;
}
// 包含ID、类型和区域ID的构造函数
public ObjectHeader(uint id, ObjectType type, ushort mapid)
public ObjectHeader(uint id, ObjectType objectType, ushort mapid)
{
ID = id;
ObjectType = type;
Padding = 0;
ObjectType = objectType;
MapID = mapid;
}
@ -108,18 +80,6 @@ namespace PSO2SERVER.Models
writer.Write(MapID); // 写入区域ID
}
// 获取ObjHeaderStruct结构体
public ObjHeaderStruct ToObjHeaderStruct()
{
return new ObjHeaderStruct(ID, Padding, ObjectType, MapID);
}
// 从ObjHeaderStruct结构体构造ObjectHeader
public static ObjectHeader FromObjHeaderStruct(ObjHeaderStruct objHeaderStruct)
{
return new ObjectHeader(objHeaderStruct.ID, objHeaderStruct.ObjectType, objHeaderStruct.MapID);
}
// ToString 方法,用来返回 ObjectHeader 的字符串表示
public override string ToString()
{

View File

@ -92,7 +92,7 @@ namespace PSO2SERVER
Console.CancelKeyPress += Exit;
AppDomain.CurrentDomain.ProcessExit += Exit;
JsonTest.JsonReadTest();
//JsonTest.JsonReadTest();
try
{

View File

@ -15,7 +15,7 @@ namespace PSO2SERVER.Protocol.Handlers
public unsafe struct MapLoadedPacket
{
/// Loaded zone object.
public ObjectHeader.ObjHeaderStruct MapObject;
public ObjectHeader MapObject;
/// Unknown data, 32 bytes.
public fixed byte Unk[0x20];
}

View File

@ -0,0 +1,37 @@
using System;
using PSO2SERVER.Models;
using PSO2SERVER.Protocol.Packets;
namespace PSO2SERVER.Protocol.Handlers
{
[PacketHandlerAttr(0x0F, 0x01)]
public class ItemPickupRequest : PacketHandler
{
public struct ItemPickupRequestPacket
{
/// Item drop ID.
public uint DropId { get; set; }
/// Unknown field.
public uint Unk { get; set; }
// Constructor for convenience
public ItemPickupRequestPacket(uint dropId, uint unk)
{
DropId = dropId;
Unk = unk;
}
}
public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
{
var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
Logger.WriteHex(info, data);
var reader = new PacketReader(data, position, size);
var pkt = reader.ReadStruct<ItemPickupRequestPacket>();
context.SendPacket(new ItemPickupResponsePacket(context._account.AccountId, pkt.DropId, 1, pkt.Unk));
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using PSO2SERVER.Models;
using PSO2SERVER.Protocol.Packets;
namespace PSO2SERVER.Protocol.Handlers
{
[PacketHandlerAttr(0x0F, 0xE0)]
public class MoveToMatStorageRequest : PacketHandler
{
public struct MoveToMatStorageRequestPacket
{
/// Information about items being moved.
public List<MaterialStorageItem> Items;
}
public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
{
var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
Logger.WriteHex(info, data);
var reader = new PacketReader(data, position, size);
var items_count = reader.ReadMagic(0x9087, 0xEA);
var pkt = new MoveToMatStorageRequestPacket();
for (int i = 0; i < items_count; i++)
{
var item = reader.ReadStruct<MaterialStorageItem>();
pkt.Items.Add(item);
}
//TODO
var newinv = new List<UpdatedInventoryItem>();
context.SendPacket(new MoveToMatStoragePacket(newinv, pkt.Items));
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using PSO2SERVER.Models;
using PSO2SERVER.Protocol.Packets;
@ -12,12 +13,34 @@ namespace PSO2SERVER.Protocol.Handlers
if(context.Character == null)
return;
//var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
//Logger.WriteHex(info, data);
var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
Logger.WriteHex(info, data);
//Mission mission = new Mission();
var mission = new Mission
{
MissionType = 5,
StartDate = 0,
EndDate = 0,
Id = 6040309,
Unk5 = 0,
CompletionDate = 1615045153,
Unk7 = 0,
Unk8 = 0,
Unk9 = 0,
Unk10 = 1,
Unk11 = 1023,
Unk12 = 0,
Unk13 = 0,
Unk14 = 1,
Unk15 = 0,
};
//context.SendPacket(new ARKSMissionListPacket(mission));
List<Mission> Missions = new List<Mission>
{
mission
};
context.SendPacket(new ARKSMissionListPacket(Missions));
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using PSO2SERVER.Models;
using PSO2SERVER.Protocol.Packets;
namespace PSO2SERVER.Protocol.Handlers
{
[PacketHandlerAttr(0x4A, 0x0C)]
public class SetTrackedMission : PacketHandler
{
public struct SetTrackedMissionPacket
{
/// Mission ID or [`u32::MAX`] if no mission is selected.
public uint Id { get; set; }
}
public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
{
if(context.Character == null)
return;
var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
Logger.WriteHex(info, data);
var reader = new PacketReader(data, position, size);
var pkt = reader.ReadStruct<SetTrackedMissionPacket>();
Logger.Write($"pkt.id:{pkt.Id}");
}
}
}

View File

@ -1,4 +1,5 @@
using PSO2SERVER.Models;
using System;
using System.Collections.Generic;
namespace PSO2SERVER.Protocol
@ -29,4 +30,17 @@ namespace PSO2SERVER.Protocol
return totalPacket.ToArray(); // 返回整个数据包字节数组
}
}
public class PacketError : Exception
{
public string PacketName { get; }
public string FieldName { get; }
public PacketError(string packetName, string fieldName, Exception innerException)
: base($"Error in packet '{packetName}', field '{fieldName}'", innerException)
{
PacketName = packetName;
FieldName = fieldName;
}
}
}

View File

@ -26,6 +26,12 @@ namespace PSO2SERVER.Protocol
Write(encoded);
}
public void WriteMagic(int magic, uint xor, uint sub)
{
uint newmagic = (uint)magic;
WriteMagic(newmagic, xor, sub);
}
public void WriteAscii(string str, uint xor, uint sub)
{
if((str == null) || (str == "") || (str.Length == 0))

View File

@ -40,9 +40,9 @@ namespace PSO2SERVER.Protocol.Packets
public struct FullMovementData
{
[FieldOffset(0x0)]
public ObjectHeader.ObjHeaderStruct entity1;
public ObjectHeader entity1;
[FieldOffset(0xC)]
public ObjectHeader.ObjHeaderStruct entity2;
public ObjectHeader entity2;
[FieldOffset(0x18)]
public UInt32 timestamp;
[FieldOffset(0x1C)]

View File

@ -84,7 +84,7 @@ namespace PSO2SERVER.Protocol.Packets
{
var pkt = new PacketWriter();
// Accounts header
ObjHeader.WriteObjectHeaderToStream(pkt);
pkt.WriteObjectHeader(ObjHeader);
// Spawn position
pkt.WritePosition(ObjPosition);
pkt.Write(Unk1);

View File

@ -6,6 +6,7 @@ using PSO2SERVER.Models;
using System.Runtime.InteropServices;
using System.IO;
using PSO2SERVER.Json;
using PSO2SERVER.Database;
namespace PSO2SERVER.Protocol.Packets
{
@ -202,14 +203,46 @@ namespace PSO2SERVER.Protocol.Packets
else
{
// 可以在此处处理未定义的 QuestType例如记录警告或错误
Logger.WriteWarning($"Unknown QuestType {questType} at index {i}. Skipping.");
Logger.WriteWarning($"未知 QuestType {questType} 索引 {i}. 跳过.");
}
}
}
//public short[] amount = new short[Enum.GetValues(typeof(QuestType)).Length];
public override byte[] Build()
{
PacketWriter pkt = new PacketWriter();
//// 使用反射获取所有枚举值,并合并它们
//ulong combinedFlags = 0;
//foreach (var value in Enum.GetValues(typeof(AvailableQuestType)))
//{
// combinedFlags |= (ulong)value;
//}
//// Filler/Padding?
//pkt.Write((UInt16)0);
//// Amounts
//for (int i = 0; i < amount.Length; i++)
//{
// amount[i] = 1; // Just for testing
// pkt.Write(amount[i]);
//}
//// Padding/Blank entries?
//for (int i = 0; i < 2; i++)
// pkt.Write((int)0);
//// Available Bitfield
//pkt.Write((UInt64)combinedFlags);
//// Filler/Padding?
//for (int i = 0; i < 2; i++)
// pkt.Write((int)0);
//return pkt.ToArray();
pkt.Write(Unk1);
pkt.Write(ExtremeCount);
pkt.Write(Unk2);
@ -298,28 +331,6 @@ namespace PSO2SERVER.Protocol.Packets
pkt.Write(RoundBoost);
pkt.Write(Unk21);
//// Filler/Padding?
//pkt.Write((UInt16)0);
//// Amounts
//for (int i = 0; i < amount.Length; i++)
//{
// amount[i] = 1; // Just for testing
// pkt.Write(amount[i]);
//}
//// Padding/Blank entries?
//for (int i = 0; i < 2; i++)
// pkt.Write((int)0);
//// Available Bitfield
//pkt.Write((UInt64)available);
//// Filler/Padding?
//for (int i = 0; i < 2; i++)
// pkt.Write((int)0);
return pkt.ToArray();
}

View File

@ -20,7 +20,6 @@ namespace PSO2SERVER.Protocol.Packets
pkt.WriteMagic((uint)questdefs.Count, 0x1DB0, 0xC5);
foreach (QuestData d in questdefs)
{
//pkt.WriteStruct(d.QuestDefiniton);
var qd = d.QuestDefiniton;
pkt.WriteFixedLengthASCII(qd.Date, 0x20);
pkt.WriteObjectHeader(qd.QuestObj);
@ -56,22 +55,5 @@ namespace PSO2SERVER.Protocol.Packets
{
return new PacketHeader(0x0B, 0x18, PacketFlags.PACKED);
}
// Hoo boy, this is 468 bytes!
// TODO: Map out this struct.
// Most of this is WRONG!!! Needs serious investigation.
/*
[K873] What I've currently mapped out
24 -> Start
38 -> PartyQuest name/Type Index?
100 -> Bitfield 1
102 -> Estimated Play Time
103 -> Party Type
104 -> Difficulties Available
105 -> Difficulties Completed
108 -> Starting Level
120 -> Item Data 1?
12C -> Item Data 2?
*/
}
}

View File

@ -10,7 +10,7 @@ namespace PSO2SERVER.Protocol.Packets
public unsafe struct PartyEntry
{
/// 玩家对象的头部信息包含ID、类型、区域ID等
public ObjectHeader.ObjHeaderStruct id;
public ObjectHeader id;
/// 玩家昵称。
public string nickname;
@ -94,7 +94,7 @@ namespace PSO2SERVER.Protocol.Packets
// 队伍结构数据
for (int i = 0; i < players.Length; i++)
{
entries[i].id = new ObjectHeader.ObjHeaderStruct((uint)players[i].Account.AccountId, ObjectType.Player); // Header of player
entries[i].id = new ObjectHeader((uint)players[i].Account.AccountId, ObjectType.Player); // Header of player
entries[i].nickname = players[i].Account.Nickname;
entries[i].char_name = players[i].Name;
entries[i].level = (byte)players[i].Jobs.entries.hunter.level;
@ -116,12 +116,12 @@ namespace PSO2SERVER.Protocol.Packets
// xor: 0xD863, sub: 0xA9
PacketWriter pkt = new PacketWriter();
party_object.WriteObjectHeaderToStream(pkt);
leader.WriteObjectHeaderToStream(pkt); // Accounts receiving the thing
pkt.WriteObjectHeader(party_object);
pkt.WriteObjectHeader(leader); // Accounts receiving the thing
pkt.Write(people_amount); // Likely partymembercount
for (int i = 0; i < 4; i++)
{
pkt.WriteStruct(entries[i].id);
pkt.WriteObjectHeader(entries[i].id);
pkt.WriteUtf16(entries[i].nickname, 0xD863, 0xA9);
pkt.WriteUtf16(entries[i].char_name, 0xD863, 0xA9);
pkt.Write(entries[i].level); // Active class level

View File

@ -0,0 +1,31 @@
using PSO2SERVER.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PSO2SERVER.Protocol.Packets
{
public class Unk0FPacket : Packet
{
public Unk0FPacket()
{
}
#region implemented abstract members of Packet
public override byte[] Build()
{
var pkt = new PacketWriter();
return pkt.ToArray();
}
public override PacketHeader GetHeader()
{
return new PacketHeader(0x0F, 0x0, PacketFlags.None);
}
#endregion
}
}

View File

@ -0,0 +1,52 @@
using PSO2SERVER.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PSO2SERVER.Protocol.Packets
{
public class ItemAttributesPacket : Packet
{
/// Attribute ID (?) (seen only 0 or 1).
public ushort Id { get; set; }
/// Segment ID.
public ushort Segment { get; set; }
/// Total data size.
public uint TotalSize { get; set; }
/// ICE archive data segment.
public byte[] Data { get; set; }
// Constructor for convenience
public ItemAttributesPacket(ushort id, ushort segment, uint totalSize, byte[] data)
{
Id = id;
Segment = segment;
TotalSize = totalSize;
Data = data;
}
#region implemented abstract members of Packet
public override byte[] Build()
{
var pkt = new PacketWriter();
pkt.Write(Id);
pkt.Write(Segment);
pkt.Write(TotalSize);
pkt.Write(Data);
return pkt.ToArray();
}
public override PacketHeader GetHeader()
{
return new PacketHeader(0x0F, 0x00, PacketFlags.PACKED);
}
#endregion
}
}

View File

@ -0,0 +1,46 @@
using PSO2SERVER.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PSO2SERVER.Protocol.Packets
{
public class ItemPickupResponsePacket : Packet
{
/// Packet receiver object (? or player, who picked up the item, unsure)
public ObjectHeader Target { get; set; } = new ObjectHeader();
/// Item drop ID.
public uint Drop_id { get; set; } = new uint();
/// Was the item actually picked up.
public uint Was_pickedup { get; set; } = new uint();
public uint Unk { get; set; } = new uint();
public ItemPickupResponsePacket(int player_id, uint drop_id, uint was_pickedup, uint unk)
{
Target = new ObjectHeader((uint)player_id, ObjectType.Player);
Drop_id = drop_id;
Was_pickedup = was_pickedup;
Unk = unk;
}
#region implemented abstract members of Packet
public override byte[] Build()
{
var pkt = new PacketWriter();
pkt.WriteObjectHeader(Target);
pkt.Write(Drop_id);
pkt.Write(Was_pickedup);
pkt.Write(Unk);
return pkt.ToArray();
}
public override PacketHeader GetHeader()
{
return new PacketHeader(0x0F, 0x02, PacketFlags.None);
}
#endregion
}
}

View File

@ -7,6 +7,11 @@ namespace PSO2SERVER.Protocol.Packets
{
public Int64 NewAmount = 0;
public SetMesetaPacket(long newAmount)
{
NewAmount = newAmount;
}
#region implemented abstract members of Packet
public override byte[] Build()

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using PSO2SERVER.Models;
namespace PSO2SERVER.Protocol.Packets
{
public class ChangeWeaponPalettePacket : Packet
{
/// Player switching the palette.
public ObjectHeader Player { get; set; } = new ObjectHeader();
public FixedList<ushort> unk { get; set; } = new FixedList<ushort>(0x12, 0);
public uint Unk1 { get; set; } = 0;
/// New palette ID.
public uint cur_palette { get; set; } = 0;
#region implemented abstract members of Packet
public ChangeWeaponPalettePacket(Client client)
{
Player = new ObjectHeader((uint)client._account.AccountId, ObjectType.Player);
cur_palette = client.Palette.CurPalette;
}
public override byte[] Build()
{
var pkt = new PacketWriter();
pkt.WriteObjectHeader(Player);
pkt.WriteList(unk);
pkt.Write(Unk1);
pkt.Write(cur_palette);
return pkt.ToArray();
}
public override PacketHeader GetHeader()
{
return new PacketHeader(0x0F, 0xBC, PacketFlags.None);
}
#endregion
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using PSO2SERVER.Models;
namespace PSO2SERVER.Protocol.Packets
{
public class LoadMaterialStoragePacket : Packet
{
public uint player_id { get; set; } = new uint();
public List<MaterialStorageItem> items { get; set; } = new List<MaterialStorageItem> ();
public StorageInfo info { get; set; } = new StorageInfo ();
#region implemented abstract members of Packet
public LoadMaterialStoragePacket(Client client)
{
player_id = (uint)client._account.AccountId;
}
public override byte[] Build()
{
var pkt = new PacketWriter();
pkt.Write(player_id);
pkt.WriteMagic((uint)items.Count, 0xAC9, 0x9F);
foreach (var item in items) {pkt.WriteStruct(item);}
pkt.WriteStruct(info);
return pkt.ToArray();
}
public override PacketHeader GetHeader()
{
return new PacketHeader(0x0F, 0xDF, PacketFlags.PACKED);
}
#endregion
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using PSO2SERVER.Models;
namespace PSO2SERVER.Protocol.Packets
{
public class MoveToMatStoragePacket : Packet
{
/// <summary>
/// Items updated in the inventory.
/// </summary>
public List<UpdatedInventoryItem> UpdatedInventory; // Equivalent to Vec<UpdatedInventoryItem>
/// <summary>
/// Items updated in the material storage.
/// </summary>
public List<MaterialStorageItem> UpdatedMaterialStorage; // Assuming this exists
#region implemented abstract members of Packet
public MoveToMatStoragePacket(List<UpdatedInventoryItem> updatedInventoryItems, List<MaterialStorageItem> materialStorageItems)
{
this.UpdatedInventory = updatedInventoryItems;
this.UpdatedMaterialStorage = materialStorageItems;
}
public override byte[] Build()
{
var pkt = new PacketWriter();
pkt.WriteMagic(UpdatedInventory.Count, 0x1644, 0x35);
foreach (var item in UpdatedInventory) {pkt.WriteStruct(item);}
pkt.WriteMagic(UpdatedMaterialStorage.Count, 0x1644, 0x35);
foreach(var item in UpdatedMaterialStorage) {pkt.WriteStruct(item);}
return pkt.ToArray();
}
public override PacketHeader GetHeader()
{
return new PacketHeader(0x0F, 0xE1, PacketFlags.PACKED);
}
#endregion
}
}

View File

@ -8,69 +8,39 @@ namespace PSO2SERVER.Protocol.Packets
{
public class ARKSMissionListPacket : Packet
{
public struct MissionListPacket
public uint Unk1 { get; set; } = new uint();
public List<Mission> Missions { get; set; } = new List<Mission>();
public uint DailyUpdate { get; set; } = new uint();
public uint WeeklyUpdate { get; set; } = new uint();
public uint TierUpdate { get; set; } = new uint();
public ARKSMissionListPacket(List<Mission> mission)
{
public uint Unk1; // 对应 Rust 的 u32
public List<Mission> Missions; // 使用 List 替代 Vec
public uint DailyUpdate; // 对应 Rust 的 u32
public uint WeeklyUpdate; // 对应 Rust 的 u32
public uint TierUpdate; // 对应 Rust 的 u32
Unk1 = 0;
Missions = mission;
DailyUpdate = 1689272266;
WeeklyUpdate = 1689273267;
TierUpdate = 1689273267;
// 不使用构造函数,而是使用默认值
public static MissionListPacket Create()
{
return new MissionListPacket
{
Missions = new List<Mission>(),
Unk1 = 0,
DailyUpdate = 0,
WeeklyUpdate = 0,
TierUpdate = 0
};
}
}
MissionListPacket pkt { get; set; }
public ARKSMissionListPacket(Mission mission)
{
pkt = MissionListPacket.Create(); // 使用工厂方法初始化 pkt
// 初始化 pkt 或添加初始任务
pkt.Missions.Add(mission);
}
// 增加任务
public void AddMission(Mission mission)
{
pkt.Missions.Add(mission);
}
// 删除任务
public bool RemoveMission(Mission mission)
{
return pkt.Missions.Remove(mission);
}
// 更新任务
public void UpdateMission(int index, Mission mission)
{
if (index >= 0 && index < pkt.Missions.Count)
{
pkt.Missions[index] = mission;
}
}
#region implemented abstract members of Packet
public override byte[] Build()
{
var writer = new PacketWriter();
return writer.ToArray();
var pkt = new PacketWriter();
pkt.Write(Unk1);
pkt.WriteMagic(Missions.Count, 0xC691, 0x47);
foreach (var mission in Missions) {pkt.WriteStruct(mission);}
pkt.Write(DailyUpdate);
pkt.Write(WeeklyUpdate);
pkt.Write(TierUpdate);
return pkt.ToArray();
}
public override PacketHeader GetHeader()
{
return new PacketHeader(0x4A, 0x01, PacketFlags.None);
return new PacketHeader(0x4A, 0x01, PacketFlags.PACKED);
}
#endregion

View File

@ -8,35 +8,43 @@ namespace PSO2SERVER.Protocol.Packets
{
public class Unk4A03Packet : Packet
{
public struct Unk4A03Packet_t
{
public uint Unk1; // 对应 Rust 的 u32
public List<Mission> Unk2; // 使用 List 替代 Vec
public List<uint> Unk3; // 使用 List 替代 Vec
public List<Unk2Struct> Unk4; // 使用 List 替代 Vec
public uint Unk5; // 对应 Rust 的 u32
}
public uint Unk1; // 对应 Rust 的 u32
public List<Mission> Unk2; // 使用 List 替代 Vec
public List<uint> Unk3; // 使用 List 替代 Vec
public List<Unk2Struct> Unk4; // 使用 List 替代 Vec
public uint Unk5; // 对应 Rust 的 u32
Unk4A03Packet_t pkt = new Unk4A03Packet_t();
public Unk4A03Packet(Mission mission, uint unk3, Unk2Struct unk4)
public Unk4A03Packet(uint unk1, List<Mission> unk2, List<uint> unk3, List<Unk2Struct> unk4, uint unk5)
{
pkt.Unk2.Add(mission);
pkt.Unk3.Add(unk3);
pkt.Unk4.Add(unk4);
Unk1 = unk1;
Unk2 = unk2;
Unk3 = unk3;
Unk4 = unk4;
Unk5 = unk5;
}
#region implemented abstract members of Packet
public override byte[] Build()
{
var writer = new PacketWriter();
return writer.ToArray();
var pkt = new PacketWriter();
pkt.Write(Unk1);
pkt.WriteMagic(Unk2.Count, 0xD20D, 0xDD);
foreach (var mission in Unk2) {pkt.WriteStruct(mission);}
pkt.WriteMagic(Unk3.Count, 0xD20D, 0xDD);
foreach (var unk3 in Unk3) { pkt.WriteStruct(unk3); }
pkt.WriteMagic(Unk4.Count, 0xD20D, 0xDD);
foreach (var unk2 in Unk4) { pkt.WriteStruct(unk2); }
pkt.Write(Unk5);
return pkt.ToArray();
}
public override PacketHeader GetHeader()
{
return new PacketHeader(0x4A, 0x03, PacketFlags.None);
return new PacketHeader(0x4A, 0x03, PacketFlags.PACKED);
}
#endregion

View File

@ -32,7 +32,7 @@ namespace PSO2SERVER
_port = port;
var queryTask = Task.Run(() => RunAsync());
RunningServers.Add(queryTask);
Logger.WriteInternal("[监听] 监听" + desc + "端口 " + port);
//Logger.WriteInternal("[监听] 监听" + desc + "端口 " + port);
}
private async Task RunAsync()

View File

@ -104,6 +104,9 @@
<Reference Include="K4os.Hash.xxHash, Version=1.0.8.0, Culture=neutral, PublicKeyToken=32cd54395057cec3, processorArchitecture=MSIL">
<HintPath>..\packages\K4os.Hash.xxHash.1.0.8\lib\net462\K4os.Hash.xxHash.dll</HintPath>
</Reference>
<Reference Include="KeraLua, Version=1.4.1.0, Culture=neutral, PublicKeyToken=6a194c04b9c89217, processorArchitecture=MSIL">
<HintPath>..\packages\KeraLua.1.4.1\lib\net46\KeraLua.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
@ -122,6 +125,9 @@
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLua, Version=1.7.3.0, Culture=neutral, PublicKeyToken=6a194c04b9c89217, processorArchitecture=MSIL">
<HintPath>..\packages\NLua.1.7.3\lib\net46\NLua.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.AppContext, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll</HintPath>
@ -314,6 +320,7 @@
<Compile Include="Models\Flags.cs" />
<Compile Include="Models\Inventory.cs" />
<Compile Include="Models\ItemAttributes.cs" />
<Compile Include="Models\ItemsAdditional.cs" />
<Compile Include="Models\Mission.cs" />
<Compile Include="Models\NetInterface.cs" />
<Compile Include="Models\Orders.cs" />
@ -332,6 +339,8 @@
<Compile Include="Protocol\Handlers\04-ObjectHandler\04-75-ActionEnd.cs" />
<Compile Include="Protocol\Handlers\06-PlayerStatusHandler\06-01-DealDamage.cs" />
<Compile Include="Protocol\Handlers\0B-QuestHandler\0B-20-AcceptQuest.cs" />
<Compile Include="Protocol\Handlers\0F-ItemHandler\0F-01-ItemPickupRequest.cs" />
<Compile Include="Protocol\Handlers\0F-ItemHandler\0F-E0-MoveToMatStorageRequest.cs" />
<Compile Include="Protocol\Handlers\0F-ItemHandler\0F-28-UNK.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-14-BlockLogin.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-90-CharacterUndeletionRequest.cs" />
@ -405,11 +414,18 @@
<Compile Include="Protocol\Handlers\34-UNK\34-72-UNK.cs" />
<Compile Include="Protocol\Handlers\48-UNK\48-16-UNK4816.cs" />
<Compile Include="Protocol\Handlers\49-UNK\49-00-UNK4900.cs" />
<Compile Include="Protocol\Handlers\4A-ARKSMisionsHandler\4A-0C-SetTrackedMission.cs" />
<Compile Include="Protocol\Handlers\4A-ARKSMisionsHandler\4A-00-MissionListRequest.cs" />
<Compile Include="Protocol\Handlers\4D-ClassicMissionPassHandler\4D-02-MissionPassRequest.cs" />
<Compile Include="Protocol\Handlers\4D-ClassicMissionPassHandler\4D-00-MissionPassInfoRequest.cs" />
<Compile Include="Protocol\Packets\04-ObjectRelatedPacket\04-75-ActionEndPacket.cs" />
<Compile Include="Protocol\Packets\0B-QuestPacket\0B-1B-QuestCategoryStopperPacket.cs" />
<Compile Include="Protocol\Packets\0F-ItemPacket\00 - 复制.cs" />
<Compile Include="Protocol\Packets\0F-ItemPacket\0F-00-ItemAttributesPacket.cs" />
<Compile Include="Protocol\Packets\0F-ItemPacket\0F-02-ItemPickupResponsePacket.cs" />
<Compile Include="Protocol\Packets\0F-ItemPacket\0F-BC-ChangeWeaponPalettePacket.cs" />
<Compile Include="Protocol\Packets\0F-ItemPacket\0F-DF-LoadMaterialStoragePacket.cs" />
<Compile Include="Protocol\Packets\0F-ItemPacket\0F-E1-MoveToMatStoragePacket.cs" />
<Compile Include="Protocol\Packets\0F-ItemPacket\0F-0D-LoadPlayerInventoryPacket.cs" />
<Compile Include="Protocol\Packets\11-ClientPacket\11-0A-Unk110A.cs" />
<Compile Include="Protocol\Packets\19-LobbyPacket\19-08-SendSystemMessagePacket.cs" />
@ -650,6 +666,8 @@
</PropertyGroup>
<Error Condition="!Exists('..\packages\EntityFramework.6.5.1\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.5.1\build\EntityFramework.props'))" />
<Error Condition="!Exists('..\packages\EntityFramework.6.5.1\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.5.1\build\EntityFramework.targets'))" />
<Error Condition="!Exists('..\packages\KeraLua.1.4.1\build\net46\KeraLua.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\KeraLua.1.4.1\build\net46\KeraLua.targets'))" />
</Target>
<Import Project="..\packages\EntityFramework.6.5.1\build\EntityFramework.targets" Condition="Exists('..\packages\EntityFramework.6.5.1\build\EntityFramework.targets')" />
<Import Project="..\packages\KeraLua.1.4.1\build\net46\KeraLua.targets" Condition="Exists('..\packages\KeraLua.1.4.1\build\net46\KeraLua.targets')" />
</Project>

View File

@ -8,6 +8,7 @@
<package id="K4os.Compression.LZ4" version="1.3.8" targetFramework="net48" />
<package id="K4os.Compression.LZ4.Streams" version="1.3.8" targetFramework="net48" />
<package id="K4os.Hash.xxHash" version="1.0.8" targetFramework="net48" />
<package id="KeraLua" version="1.4.1" targetFramework="net48" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net48" />
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net48" />
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net48" />
@ -15,6 +16,7 @@
<package id="MySql.Data.EntityFramework" version="9.0.0" targetFramework="net48" />
<package id="NETStandard.Library" version="1.6.1" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
<package id="NLua" version="1.7.3" targetFramework="net48" />
<package id="System.AppContext" version="4.3.0" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Collections" version="4.3.0" targetFramework="net48" />