using PSO2SERVER.Database; using PSO2SERVER.Models; using static PSO2SERVER.Models.CharacterStruct; using static PSO2SERVER.Party.Party; namespace PSO2SERVER.Protocol.Packets { class PartyInitPacket : Packet { public unsafe struct PartyEntry { /// 玩家对象的头部信息(包含ID、类型、区域ID等)。 public ObjectHeader id; /// 玩家昵称。 public string nickname; /// 玩家角色名称。 public string char_name; /// 主职业的等级。 public byte level; /// 副职业的等级。 public byte sublevel; /// 玩家主职业类型(`ClassType` 枚举类型)。 public ClassType mainClass; /// 玩家副职业类型(`ClassType` 枚举类型)。 public ClassType subClass; /// 玩家在队伍中的颜色标识。 public PartyColor color; /// 7字节的未知数据(通常是填充或者未定义用途)。 public fixed byte unk1[7]; /// 一个未知的 uint 类型数据,具体用途不明。 public uint unk2; /// 玩家HP(体力)的三个数值。具体原因为什么有三个值目前不明。 public fixed uint hp[3]; /// 玩家所在的地图ID。 public ushort mapid; /// 另一个未知的 ushort 类型数据。 public ushort unk3; /// 12字节的未知数据。 public fixed byte unk4[0x0C]; /// 3个未知的 uint 数组数据。 public fixed uint unk5[3]; /// 未知的字符串,可能是其他信息(如玩家状态或其他描述信息)。 public string unk6; /// PSO VITA(PlayStation Vita)相关字段,已注释掉,可能与Vita版本相关。 /// public string unk10; /// 玩家角色的 ASCII 字符串相关数据,已注释掉。 /// public AsciiString unk7; // ASCII 字符串 /// 玩家语言设置(`ShortLanguage` 枚举类型),已注释掉。 /// public ShortLanguage lang; /// 3字节的未知数据,已注释掉。 /// public fixed byte unk9[3]; } /// 队伍实例. private ObjectHeader party_object; /// 队伍队长实例. private ObjectHeader leader; /// 队伍人数. private uint people_amount; /// 队伍成员. private PartyEntry[] entries = new PartyEntry[4]; // 这个是一个包含 4 个 `PartyEntry` 结构的数组,表示队伍中的4个成员。 /// /// 未知 /// private AsciiString unk2; private Character[] players; public PartyInitPacket(Character[] players) { this.players = players; party_object = new ObjectHeader((uint)players[0].Account.AccountId, ObjectType.Party); leader = new ObjectHeader((uint)players[0].Account.AccountId, ObjectType.Player); people_amount = (uint)players.Length; // 队伍结构数据 for (int i = 0; i < players.Length; i++) { 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; entries[i].sublevel = (byte)players[i].Jobs.entries.hunter.level2; entries[i].mainClass = players[i].Jobs.mainClass; entries[i].subClass = players[i].Jobs.subClass; entries[i].color = (PartyColor)i; entries[i].unk2 = 0; entries[i].mapid = 0; entries[i].unk3 = 0; entries[i].unk6 = players[i].Name; } } public override byte[] Build() { if (players.Length < 1) return new byte[0]; // xor: 0xD863, sub: 0xA9 PacketWriter writer = new PacketWriter(); writer.WriteStruct(party_object); writer.WriteStruct(leader); // Accounts receiving the thing writer.Write(people_amount); // Likely partymembercount for (int i = 0; i < 4; i++) { writer.WriteStruct(entries[i].id); // Header of player writer.WriteUtf16(entries[i].nickname, 0xD863, 0xA9); writer.WriteUtf16(entries[i].char_name, 0xD863, 0xA9); writer.Write(entries[i].level); // Active class level writer.Write(entries[i].sublevel); // idk writer.Write((byte)entries[i].mainClass); // idk writer.Write((byte)entries[i].subClass); // idk writer.Write((byte)entries[i].color); // idk writer.WriteBytes(0, 7); writer.Write(entries[i].unk2); // idk ///hp writer.Write((uint)0); writer.Write((uint)0); writer.Write((uint)0); /// 玩家所在的地图ID。 writer.Write(entries[i].mapid); writer.Write(entries[i].unk3); writer.WriteBytes(0, 12); writer.Write((uint)0); writer.Write((uint)0); writer.WriteUtf16(entries[i].unk6, 0xD863, 0xA9); } writer.WriteAscii("123456", 0xD863, 0xA9); //// 队伍结构数据 //for(int i = 0; i < players.Length; i++) //{ // PartyEntry pe = new PartyEntry(); // writer.WriteStruct(new ObjectHeader((uint)players[i].Accounts.AccountId, ObjectType.Player)); // Header of player // writer.WriteUtf16(players[i].Name, 0xD863, 0xA9); // writer.WriteUtf16(players[i].Accounts.Nickname, 0xD863, 0xA9); // writer.Write((byte)players[i].Jobs.entries.hunter.level); // Active class level // writer.Write((byte)players[i].Jobs.entries.hunter.level2); // idk // writer.Write((byte)players[i].Jobs.mainClass); // idk // writer.Write((byte)players[i].Jobs.subClass); // idk // writer.Write((byte)i); // idk // writer.WriteBytes(0, 7); // writer.Write((uint)0); // idk // ///hp // writer.Write((uint)0); // writer.Write((uint)0); // writer.Write((uint)0); // /// 玩家所在的地图ID。 // writer.Write(pe.mapid); // writer.Write(pe.unk3); // writer.WriteBytes(0, 12); // writer.Write((uint)0); // writer.Write((uint)0); // writer.Write((uint)0); //} //for(int i = 0; i < 4 - players.Length; i++) // Empty entries //{ // writer.WriteStruct(new ObjectHeader(0, 0)); // Header of player // writer.WriteMagic(0, 0xD863, 0xA9); // writer.WriteMagic(0, 0xD863, 0xA9); // writer.Write((byte)0); // Active class level // writer.Write((byte)0); // idk // writer.Write((byte)0); // idk // writer.Write((byte)0); // idk // writer.Write((byte)0); // idk // writer.WriteBytes(0, 7); // writer.Write((uint)0); // idk // ///hp // writer.Write((uint)0); // writer.Write((uint)0); // writer.Write((uint)0); // /// 玩家所在的地图ID。 // writer.Write((ushort)0); // writer.Write((ushort)0); // writer.WriteBytes(0, 12); // writer.Write((uint)0); // writer.Write((uint)0); // writer.Write((uint)0); //} return writer.ToArray(); } public override PacketHeader GetHeader() { return new PacketHeader(0x0E, 0x02, PacketFlags.PACKED); } } }