diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
index c645651e..ea355218 100644
--- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
+++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
@@ -81,6 +81,7 @@
+
@@ -89,8 +90,16 @@
+
+
+
+
+
+
+
+
@@ -188,10 +197,20 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/FFXIVClassic Map Server/actors/group/ContentWork.cs b/FFXIVClassic Map Server/actors/group/ContentWork.cs
new file mode 100644
index 00000000..a8a3ccd7
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/ContentWork.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class ContentWork
+ {
+ public GroupGlobalTemp _globalTemp = new GroupGlobalTemp();
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/group/Group.cs b/FFXIVClassic Map Server/actors/group/Group.cs
new file mode 100644
index 00000000..2446fd8a
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/Group.cs
@@ -0,0 +1,141 @@
+using FFXIVClassic_Lobby_Server.common;
+using FFXIVClassic_Lobby_Server.packets;
+using FFXIVClassic_Map_Server.Actors;
+using FFXIVClassic_Map_Server.packets.send.actor;
+using FFXIVClassic_Map_Server.packets.send.group;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class Group
+ {
+ public const uint PlayerPartyGroup = 10001;
+ public const uint CompanyGroup = 20001;
+
+ public const uint GroupInvitationRelationGroup = 50001;
+ public const uint TradeRelationGroup = 50002;
+ public const uint BazaarBuyItemRelationGroup = 50009;
+
+ public const uint RetainerGroup = 80001;
+
+ public ulong groupId;
+ public uint groupTypeId;
+ public int localizedNamed = -1;
+ public string groupName = "";
+
+ public PartyWork partyGroupWork; //For party group types
+ public Object work; //For the rest
+
+ public List members = new List();
+
+ public Group(ulong id, uint typeId, object work)
+ {
+ groupId = id;
+ groupTypeId = typeId;
+
+ if (work is PartyWork)
+ partyGroupWork = (PartyWork)work;
+ else
+ this.work = work;
+ }
+
+ public Group(ulong id, uint typeId, int nameId, object work)
+ {
+ groupId = id;
+ groupTypeId = typeId;
+ localizedNamed = nameId;
+
+ if (work is PartyWork)
+ partyGroupWork = (PartyWork)work;
+ else
+ this.work = (PartyWork)work;
+ }
+
+ public Group(ulong id, uint typeId, string name, object work)
+ {
+ groupId = id;
+ groupTypeId = typeId;
+ groupName = name;
+ localizedNamed = -1;
+
+ if (work is PartyWork)
+ partyGroupWork = (PartyWork)work;
+ else
+ this.work = work;
+ }
+
+ public void add(Actor actor)
+ {
+ GroupMember member = new GroupMember(actor.actorId, (int)actor.displayNameId, 0, false, true, actor.customDisplayName);
+ members.Add(member);
+ }
+
+ public void sendMemberPackets(Player toPlayer)
+ {
+ ulong time = Utils.MilisUnixTimeStampUTC();
+
+ toPlayer.queuePacket(GroupHeaderPacket.buildPacket(toPlayer.actorId, toPlayer.zoneId, time, this));
+ toPlayer.queuePacket(GroupMembersBeginPacket.buildPacket(toPlayer.actorId, toPlayer.zoneId, time, this));
+
+ int currentIndex = 0;
+
+ while (true)
+ {
+ if (members.Count - currentIndex >= 64)
+ toPlayer.queuePacket(GroupMembersX64Packet.buildPacket(toPlayer.actorId, toPlayer.zoneId, time, members, ref currentIndex));
+ else if (members.Count - currentIndex >= 32)
+ toPlayer.queuePacket(GroupMembersX32Packet.buildPacket(toPlayer.actorId, toPlayer.zoneId, time, members, ref currentIndex));
+ else if (members.Count - currentIndex >= 16)
+ toPlayer.queuePacket(GroupMembersX16Packet.buildPacket(toPlayer.actorId, toPlayer.zoneId, time, members, ref currentIndex));
+ else if (members.Count - currentIndex > 0)
+ toPlayer.queuePacket(GroupMembersX08Packet.buildPacket(toPlayer.actorId, toPlayer.zoneId, time, members, ref currentIndex));
+ else
+ break;
+ }
+
+
+ toPlayer.queuePacket(GroupMembersEndPacket.buildPacket(toPlayer.actorId, toPlayer.zoneId, time, this));
+
+ }
+
+ public void sendWorkValues(Player player)
+ {
+ if (groupTypeId == PlayerPartyGroup)
+ {
+ SetGroupWorkValuesPacket groupWork = new SetGroupWorkValuesPacket(groupId);
+ groupWork.addProperty(this, "partyGroupWork._globalTemp.owner");
+ groupWork.setTarget("/_init");
+
+ SubPacket test = groupWork.buildPacket(player.actorId, player.actorId);
+ player.queuePacket(test);
+ }
+ else if (groupTypeId == GroupInvitationRelationGroup)
+ {
+ SetGroupWorkValuesPacket groupWork = new SetGroupWorkValuesPacket(groupId);
+ groupWork.addProperty(this, "work._globalTemp.host");
+ groupWork.addProperty(this, "work._globalTemp.variableCommand");
+ groupWork.setTarget("/_init");
+
+ SubPacket test = groupWork.buildPacket(player.actorId, player.actorId);
+ test.debugPrintSubPacket();
+ player.queuePacket(test);
+ }
+ else if (groupTypeId == RetainerGroup)
+ {
+ SetGroupWorkValuesPacket groupWork = new SetGroupWorkValuesPacket(groupId);
+ groupWork.addProperty(this, "work._memberSave[0].cdIDOffset");
+ groupWork.addProperty(this, "work._memberSave[0].placeName");
+ groupWork.addProperty(this, "work._memberSave[0].conditions");
+ groupWork.addProperty(this, "work._memberSave[0].level");
+ groupWork.setTarget("/_init");
+
+ SubPacket test = groupWork.buildPacket(player.actorId, player.actorId);
+ player.queuePacket(test);
+ }
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/group/GroupGlobalSave.cs b/FFXIVClassic Map Server/actors/group/GroupGlobalSave.cs
new file mode 100644
index 00000000..1231f117
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/GroupGlobalSave.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class GroupGlobalSave
+ {
+ public ulong master;
+ public byte[] crestIcon = new byte[4];
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/group/GroupGlobalTemp.cs b/FFXIVClassic Map Server/actors/group/GroupGlobalTemp.cs
new file mode 100644
index 00000000..2a831dce
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/GroupGlobalTemp.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class GroupGlobalTemp
+ {
+ public ulong owner;
+
+ //For content group
+ public ulong director;
+
+ //For relation group
+ public ulong host;
+ public uint variableCommand;
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/group/GroupMemberSave.cs b/FFXIVClassic Map Server/actors/group/GroupMemberSave.cs
new file mode 100644
index 00000000..4b6160a0
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/GroupMemberSave.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class GroupMemberSave
+ {
+ //For LS
+ public byte rank;
+
+ //For Retainers
+ public byte cdIDOffset;
+ public ushort placeName;
+ public byte conditions;
+ public byte level;
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/group/LinkshellWork.cs b/FFXIVClassic Map Server/actors/group/LinkshellWork.cs
new file mode 100644
index 00000000..d2e5d6ce
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/LinkshellWork.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class LinkshellWork
+ {
+ public GroupGlobalSave _globalSave = new GroupGlobalSave();
+ public GroupMemberSave[] _memberSave = new GroupMemberSave[128];
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/group/PartyWork.cs b/FFXIVClassic Map Server/actors/group/PartyWork.cs
new file mode 100644
index 00000000..c45a89a4
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/PartyWork.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class PartyWork
+ {
+ public GroupGlobalTemp _globalTemp = new GroupGlobalTemp();
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/group/RelationWork.cs b/FFXIVClassic Map Server/actors/group/RelationWork.cs
new file mode 100644
index 00000000..e0094492
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/RelationWork.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class RelationWork
+ {
+ public GroupGlobalTemp _globalTemp = new GroupGlobalTemp();
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/group/RetainerWork.cs b/FFXIVClassic Map Server/actors/group/RetainerWork.cs
new file mode 100644
index 00000000..49e1c7df
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/group/RetainerWork.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.group
+{
+ class RetainerWork
+ {
+ public GroupMemberSave[] _memberSave = new GroupMemberSave[128];
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/CreateNamedGroup.cs b/FFXIVClassic Map Server/packets/send/groups/CreateNamedGroup.cs
new file mode 100644
index 00000000..eaeb6279
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/CreateNamedGroup.cs
@@ -0,0 +1,41 @@
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.actors.group;
+using FFXIVClassic_Map_Server.dataobjects;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class CreateNamedGroup
+ {
+ public const ushort OPCODE = 0x0188;
+ public const uint PACKET_SIZE = 0x60;
+
+ public static SubPacket buildPacket(uint playerActorID, Group group)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ binWriter.Write((UInt64)group.groupId);
+ binWriter.Write((UInt32)group.groupTypeId);
+ binWriter.Write((Int32)group.localizedNamed);
+
+ binWriter.Write((UInt16)0x121C);
+
+ binWriter.Seek(0x20, SeekOrigin.Begin);
+
+ binWriter.Write(Encoding.ASCII.GetBytes(group.groupName), 0, Encoding.ASCII.GetByteCount(group.groupName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.groupName));
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/CreateNamedGroupMultiple.cs b/FFXIVClassic Map Server/packets/send/groups/CreateNamedGroupMultiple.cs
new file mode 100644
index 00000000..2946f653
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/CreateNamedGroupMultiple.cs
@@ -0,0 +1,55 @@
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.actors.group;
+using FFXIVClassic_Map_Server.dataobjects;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class CreateNamedGroupMultiple
+ {
+ public const ushort OPCODE = 0x0189;
+ public const uint PACKET_SIZE = 0x228;
+
+ public static SubPacket buildPacket(uint playerActorID, Group[] groups, ref int offset)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ int max = 8;
+ if (groups.Length - offset <= 8)
+ max = groups.Length - offset;
+
+ for (int i = 0; i < max; i++)
+ {
+ binWriter.Seek(i * 0x40, SeekOrigin.Begin);
+
+ Group group = groups[offset+i];
+
+ binWriter.Write((UInt64)group.groupId);
+ binWriter.Write((UInt32)group.groupTypeId);
+ binWriter.Write((Int32)group.localizedNamed);
+
+ binWriter.Write((UInt16)0x121C);
+
+ binWriter.Seek(0x20, SeekOrigin.Begin);
+
+ binWriter.Write(Encoding.ASCII.GetBytes(group.groupName), 0, Encoding.ASCII.GetByteCount(group.groupName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.groupName));
+ }
+
+ binWriter.Seek(0x200, SeekOrigin.Begin);
+ binWriter.Write((Byte)max);
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupHeaderPacket.cs b/FFXIVClassic Map Server/packets/send/groups/GroupHeaderPacket.cs
new file mode 100644
index 00000000..2a04dca6
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/GroupHeaderPacket.cs
@@ -0,0 +1,62 @@
+using FFXIVClassic_Lobby_Server.packets;
+using FFXIVClassic_Map_Server.actors.group;
+using FFXIVClassic_Map_Server.dataobjects;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class GroupHeaderPacket
+ {
+ public const uint TYPEID_RETAINER = 0x13881;
+ public const uint TYPEID_PARTY = 0x2711;
+ public const uint TYPEID_LINKSHELL = 0x4E22;
+
+ public const ushort OPCODE = 0x017C;
+ public const uint PACKET_SIZE = 0x98;
+
+ public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, Group group)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ //Write list header
+ binWriter.Write((UInt64)locationCode);
+ binWriter.Write((UInt64)sequenceId);
+
+ //Write list id
+ binWriter.Write((UInt64)3);
+ binWriter.Write((UInt64)group.groupId);
+ binWriter.Write((UInt64)0);
+ binWriter.Write((UInt64)group.groupId);
+
+ //This seems to change depending on what the list is for
+ binWriter.Write((UInt32)group.groupTypeId);
+ binWriter.Seek(0x40, SeekOrigin.Begin);
+
+ //This is for Linkshell
+ binWriter.Write((UInt32)group.localizedNamed);
+ binWriter.Write(Encoding.ASCII.GetBytes(group.groupName), 0, Encoding.ASCII.GetByteCount(group.groupName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.groupName));
+
+ binWriter.Seek(0x64, SeekOrigin.Begin);
+
+ binWriter.Write((UInt32)0x6D);
+ binWriter.Write((UInt32)0x6D);
+ binWriter.Write((UInt32)0x6D);
+ binWriter.Write((UInt32)0x6D);
+
+ binWriter.Write((UInt32)group.members.Count);
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupMember.cs b/FFXIVClassic Map Server/packets/send/groups/GroupMember.cs
new file mode 100644
index 00000000..1a00c38f
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/GroupMember.cs
@@ -0,0 +1,24 @@
+using FFXIVClassic.Common;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class GroupMember
+ {
+ public uint actorId;
+ public int localizedName;
+ public uint unknown2;
+ public bool flag1;
+ public bool isOnline;
+ public string name;
+
+ public GroupMember(uint actorId, int localizedName, uint unknown2, bool flag1, bool isOnline, string name)
+ {
+ this.actorId = actorId;
+ this.localizedName = localizedName;
+ this.unknown2 = unknown2;
+ this.flag1 = flag1;
+ this.isOnline = isOnline;
+ this.name = name;
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupMembersBeginPacket.cs b/FFXIVClassic Map Server/packets/send/groups/GroupMembersBeginPacket.cs
new file mode 100644
index 00000000..981dd031
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/GroupMembersBeginPacket.cs
@@ -0,0 +1,38 @@
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.actors.group;
+using FFXIVClassic_Map_Server.dataobjects;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class GroupMembersBeginPacket
+ {
+ public const ushort OPCODE = 0x017D;
+ public const uint PACKET_SIZE = 0x40;
+
+ public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, Group group)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ //Write List Header
+ binWriter.Write((UInt64)locationCode);
+ binWriter.Write((UInt64)sequenceId);
+ //Write List Info
+ binWriter.Write((UInt64)group.groupId);
+ binWriter.Write((UInt32)group.members.Count);
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupMembersEndPacket.cs b/FFXIVClassic Map Server/packets/send/groups/GroupMembersEndPacket.cs
new file mode 100644
index 00000000..fdf24e21
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/GroupMembersEndPacket.cs
@@ -0,0 +1,38 @@
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.actors.group;
+using FFXIVClassic_Map_Server.dataobjects;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class GroupMembersEndPacket
+ {
+ public const ushort OPCODE = 0x017E;
+ public const uint PACKET_SIZE = 0x38;
+
+ public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, Group group)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ //Write List Header
+ binWriter.Write((UInt64)locationCode);
+ binWriter.Write((UInt64)sequenceId);
+ //Write List Info
+ binWriter.Write((UInt64)group.groupId);
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupMembersX08Packet.cs b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX08Packet.cs
new file mode 100644
index 00000000..e5272adb
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX08Packet.cs
@@ -0,0 +1,54 @@
+using FFXIVClassic.Common;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class GroupMembersX08Packet
+ {
+ public const ushort OPCODE = 0x017F;
+ public const uint PACKET_SIZE = 0x1B8;
+
+ public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, List entries, ref int offset)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ //Write List Header
+ binWriter.Write((UInt64)locationCode);
+ binWriter.Write((UInt64)sequenceId);
+ //Write Entries
+ int max = 8;
+ if (entries.Count-offset < 8)
+ max = entries.Count - offset;
+ for (int i = 0; i < max; i++)
+ {
+ binWriter.Seek(0x10 + (0x30 * i), SeekOrigin.Begin);
+
+ GroupMember entry = entries[i];
+ binWriter.Write((UInt32)entry.actorId);
+ binWriter.Write((Int32)entry.localizedName);
+ binWriter.Write((UInt32)entry.unknown2);
+ binWriter.Write((Byte)(entry.flag1? 1 : 0));
+ binWriter.Write((Byte)(entry.isOnline? 1 : 0));
+ binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name));
+
+ offset++;
+ }
+ //Write Count
+ binWriter.Seek(0x10 + (0x30 * 8), SeekOrigin.Begin);
+ binWriter.Write(max);
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupMembersX16Packet.cs b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX16Packet.cs
new file mode 100644
index 00000000..e2b1ca13
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX16Packet.cs
@@ -0,0 +1,51 @@
+using FFXIVClassic.Common;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class GroupMembersX16Packet
+ {
+ public const ushort OPCODE = 0x0180;
+ public const uint PACKET_SIZE = 0x330;
+
+ public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, List entries, ref int offset)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ //Write List Header
+ binWriter.Write((UInt64)locationCode);
+ binWriter.Write((UInt64)sequenceId);
+ //Write Entries
+ int max = 16;
+ if (entries.Count-offset < 16)
+ max = entries.Count - offset;
+ for (int i = 0; i < max; i++)
+ {
+ binWriter.Seek(0x10 + (0x30 * i), SeekOrigin.Begin);
+
+ GroupMember entry = entries[i];
+ binWriter.Write((UInt32)entry.actorId);
+ binWriter.Write((Int32)entry.localizedName);
+ binWriter.Write((UInt32)entry.unknown2);
+ binWriter.Write((Byte)(entry.flag1? 1 : 0));
+ binWriter.Write((Byte)(entry.isOnline? 1 : 0));
+ binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name));
+
+ offset++;
+ }
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupMembersX32Packet.cs b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX32Packet.cs
new file mode 100644
index 00000000..923e5019
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX32Packet.cs
@@ -0,0 +1,51 @@
+using FFXIVClassic.Common;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class GroupMembersX32Packet
+ {
+ public const ushort OPCODE = 0x0181;
+ public const uint PACKET_SIZE = 0x630;
+
+ public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, List entries, ref int offset)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ //Write List Header
+ binWriter.Write((UInt64)locationCode);
+ binWriter.Write((UInt64)sequenceId);
+ //Write Entries
+ int max = 32;
+ if (entries.Count-offset < 32)
+ max = entries.Count - offset;
+ for (int i = 0; i < max; i++)
+ {
+ binWriter.Seek(0x10 + (0x30 * i), SeekOrigin.Begin);
+
+ GroupMember entry = entries[i];
+ binWriter.Write((UInt32)entry.actorId);
+ binWriter.Write((Int32)entry.localizedName);
+ binWriter.Write((UInt32)entry.unknown2);
+ binWriter.Write((Byte)(entry.flag1? 1 : 0));
+ binWriter.Write((Byte)(entry.isOnline? 1 : 0));
+ binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name));
+
+ offset++;
+ }
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/packets/send/groups/GroupMembersX64Packet.cs b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX64Packet.cs
new file mode 100644
index 00000000..05535081
--- /dev/null
+++ b/FFXIVClassic Map Server/packets/send/groups/GroupMembersX64Packet.cs
@@ -0,0 +1,51 @@
+using FFXIVClassic.Common;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.packets.send.group
+{
+ class GroupMembersX64Packet
+ {
+ public const ushort OPCODE = 0x0182;
+ public const uint PACKET_SIZE = 0xC30;
+
+ public static SubPacket buildPacket(uint playerActorID, uint locationCode, ulong sequenceId, List entries, ref int offset)
+ {
+ byte[] data = new byte[PACKET_SIZE - 0x20];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ //Write List Header
+ binWriter.Write((UInt64)locationCode);
+ binWriter.Write((UInt64)sequenceId);
+ //Write Entries
+ int max = 64;
+ if (entries.Count - offset < 64)
+ max = entries.Count - offset;
+ for (int i = 0; i < max; i++)
+ {
+ binWriter.Seek(0x10 + (0x30 * i), SeekOrigin.Begin);
+
+ GroupMember entry = entries[i];
+ binWriter.Write((UInt32)entry.actorId);
+ binWriter.Write((Int32)entry.localizedName);
+ binWriter.Write((UInt32)entry.unknown2);
+ binWriter.Write((Byte)(entry.flag1? 1 : 0));
+ binWriter.Write((Byte)(entry.isOnline? 1 : 0));
+ binWriter.Write(Encoding.ASCII.GetBytes(entry.name), 0, Encoding.ASCII.GetByteCount(entry.name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(entry.name));
+
+ offset++;
+ }
+ }
+ }
+
+ return new SubPacket(OPCODE, playerActorID, playerActorID, data);
+ }
+ }
+}