From 1148619ca5df706452f954e0c2b05863201f6b9c Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Thu, 15 Dec 2016 12:19:44 -0500 Subject: [PATCH] More group work. Added packet operations to the world server so it can send global group info. --- .../Actor/Group/Work/ContentWork.cs | 13 ++ .../Actor/Group/Work/GroupGlobalSave.cs | 15 ++ .../Actor/Group/Work/GroupGlobalTemp.cs | 20 ++ .../Actor/Group/Work/GroupMemberSave.cs | 20 ++ .../Actor/Group/Work/LinkshellWork.cs | 14 ++ .../Actor/Group/Work/PartyWork.cs | 13 ++ .../Actor/Group/Work/RelationWork.cs | 13 ++ .../Actor/Group/Work/RetainerWork.cs | 8 + .../DataObjects/Group/Group.cs | 71 +++++- .../DataObjects/Group/Linkshell.cs | 62 ++++- .../DataObjects/Group/Party.cs | 49 +++- .../DataObjects/Group/Relation.cs | 22 +- .../DataObjects/Group/RetainerGroup.cs | 48 +++- .../DataObjects/Group/RetainerGroupMember.cs | 2 + FFXIVClassic World Server/Database.cs | 29 +++ .../FFXIVClassic World Server.csproj | 26 +++ .../Subpackets/Groups/CreateNamedGroup.cs | 41 ++++ .../Groups/CreateNamedGroupMultiple.cs | 55 +++++ .../Subpackets/Groups/DeleteGroupPacket.cs | 44 ++++ .../Subpackets/Groups/GroupHeaderPacket.cs | 61 +++++ .../Send/Subpackets/Groups/GroupMember.cs | 24 ++ .../Groups/GroupMembersBeginPacket.cs | 37 +++ .../Groups/GroupMembersEndPacket.cs | 38 ++++ .../Groups/GroupMembersX08Packet.cs | 54 +++++ .../Groups/GroupMembersX16Packet.cs | 51 +++++ .../Groups/GroupMembersX32Packet.cs | 51 +++++ .../Groups/GroupMembersX64Packet.cs | 51 +++++ .../Groups/SynchGroupWorkValuesPacket.cs | 211 ++++++++++++++++++ FFXIVClassic World Server/PartyManager.cs | 6 +- FFXIVClassic World Server/Server.cs | 67 ++++-- 30 files changed, 1173 insertions(+), 43 deletions(-) create mode 100644 FFXIVClassic World Server/Actor/Group/Work/ContentWork.cs create mode 100644 FFXIVClassic World Server/Actor/Group/Work/GroupGlobalSave.cs create mode 100644 FFXIVClassic World Server/Actor/Group/Work/GroupGlobalTemp.cs create mode 100644 FFXIVClassic World Server/Actor/Group/Work/GroupMemberSave.cs create mode 100644 FFXIVClassic World Server/Actor/Group/Work/LinkshellWork.cs create mode 100644 FFXIVClassic World Server/Actor/Group/Work/PartyWork.cs create mode 100644 FFXIVClassic World Server/Actor/Group/Work/RelationWork.cs create mode 100644 FFXIVClassic World Server/Actor/Group/Work/RetainerWork.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/CreateNamedGroup.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/CreateNamedGroupMultiple.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/DeleteGroupPacket.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupHeaderPacket.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMember.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersBeginPacket.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersEndPacket.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX08Packet.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX16Packet.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX32Packet.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX64Packet.cs create mode 100644 FFXIVClassic World Server/Packets/Send/Subpackets/Groups/SynchGroupWorkValuesPacket.cs diff --git a/FFXIVClassic World Server/Actor/Group/Work/ContentWork.cs b/FFXIVClassic World Server/Actor/Group/Work/ContentWork.cs new file mode 100644 index 00000000..6e7c3941 --- /dev/null +++ b/FFXIVClassic World Server/Actor/Group/Work/ContentWork.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Actor.Group.Work +{ + class ContentWork + { + public GroupGlobalTemp _globalTemp = new GroupGlobalTemp(); + } +} diff --git a/FFXIVClassic World Server/Actor/Group/Work/GroupGlobalSave.cs b/FFXIVClassic World Server/Actor/Group/Work/GroupGlobalSave.cs new file mode 100644 index 00000000..3a2ff84d --- /dev/null +++ b/FFXIVClassic World Server/Actor/Group/Work/GroupGlobalSave.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Actor.Group.Work +{ + class GroupGlobalSave + { + public ulong master; + public ushort[] crestIcon = new ushort[4]; + public byte rank = 1; + } +} diff --git a/FFXIVClassic World Server/Actor/Group/Work/GroupGlobalTemp.cs b/FFXIVClassic World Server/Actor/Group/Work/GroupGlobalTemp.cs new file mode 100644 index 00000000..f8ab5051 --- /dev/null +++ b/FFXIVClassic World Server/Actor/Group/Work/GroupGlobalTemp.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Actor.Group.Work +{ + class GroupGlobalTemp + { + public ulong owner; + + //For content group + public ulong director; + + //For relation group + public ulong host; + public uint variableCommand; + } +} diff --git a/FFXIVClassic World Server/Actor/Group/Work/GroupMemberSave.cs b/FFXIVClassic World Server/Actor/Group/Work/GroupMemberSave.cs new file mode 100644 index 00000000..f72fa714 --- /dev/null +++ b/FFXIVClassic World Server/Actor/Group/Work/GroupMemberSave.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Actor.Group.Work +{ + 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 World Server/Actor/Group/Work/LinkshellWork.cs b/FFXIVClassic World Server/Actor/Group/Work/LinkshellWork.cs new file mode 100644 index 00000000..9fca2ab7 --- /dev/null +++ b/FFXIVClassic World Server/Actor/Group/Work/LinkshellWork.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Actor.Group.Work +{ + class LinkshellWork + { + public GroupGlobalSave _globalSave = new GroupGlobalSave(); + public GroupMemberSave[] _memberSave = new GroupMemberSave[128]; + } +} diff --git a/FFXIVClassic World Server/Actor/Group/Work/PartyWork.cs b/FFXIVClassic World Server/Actor/Group/Work/PartyWork.cs new file mode 100644 index 00000000..f8bcb97a --- /dev/null +++ b/FFXIVClassic World Server/Actor/Group/Work/PartyWork.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Actor.Group.Work +{ + class PartyWork + { + public GroupGlobalTemp _globalTemp = new GroupGlobalTemp(); + } +} diff --git a/FFXIVClassic World Server/Actor/Group/Work/RelationWork.cs b/FFXIVClassic World Server/Actor/Group/Work/RelationWork.cs new file mode 100644 index 00000000..18eaab6e --- /dev/null +++ b/FFXIVClassic World Server/Actor/Group/Work/RelationWork.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Actor.Group.Work +{ + class RelationWork + { + public GroupGlobalTemp _globalTemp = new GroupGlobalTemp(); + } +} diff --git a/FFXIVClassic World Server/Actor/Group/Work/RetainerWork.cs b/FFXIVClassic World Server/Actor/Group/Work/RetainerWork.cs new file mode 100644 index 00000000..70e8fa05 --- /dev/null +++ b/FFXIVClassic World Server/Actor/Group/Work/RetainerWork.cs @@ -0,0 +1,8 @@ + +namespace FFXIVClassic_World_Server.Actor.Group.Work +{ + class RetainerWork + { + public GroupMemberSave[] _memberSave = new GroupMemberSave[128]; + } +} diff --git a/FFXIVClassic World Server/DataObjects/Group/Group.cs b/FFXIVClassic World Server/DataObjects/Group/Group.cs index 25a09d59..b87501a0 100644 --- a/FFXIVClassic World Server/DataObjects/Group/Group.cs +++ b/FFXIVClassic World Server/DataObjects/Group/Group.cs @@ -1,18 +1,79 @@ -using System; +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace FFXIVClassic_World_Server.DataObjects.Group { class Group { - public readonly ulong groupIndex; + 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 readonly ulong groupIndex; + public Group(ulong groupIndex) { this.groupIndex = groupIndex; } + + public virtual int GetMemberCount() + { + return 0; + } + + public virtual uint GetTypeId() + { + return 0; + } + + public virtual string GetGroupName() + { + return ""; + } + + public virtual int GetGroupLocalizedName() + { + return -1; + } + + public virtual List BuildMemberList() + { + return new List(); + } + + public void SendGroupPackets(Session session) + { + ulong time = Utils.MilisUnixTimeStampUTC(); + List members = BuildMemberList(); + + session.clientConnection.QueuePacket(GroupHeaderPacket.buildPacket(session.sessionId, session.currentZoneId, time, this), true, false); + session.clientConnection.QueuePacket(GroupMembersBeginPacket.buildPacket(session.sessionId, session.currentZoneId, time, this), true, false); + + int currentIndex = 0; + + while (true) + { + if (GetMemberCount() - currentIndex >= 64) + session.clientConnection.QueuePacket(GroupMembersX64Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex), true, false); + else if (GetMemberCount() - currentIndex >= 32) + session.clientConnection.QueuePacket(GroupMembersX32Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex), true, false); + else if (GetMemberCount() - currentIndex >= 16) + session.clientConnection.QueuePacket(GroupMembersX16Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex), true, false); + else if (GetMemberCount() - currentIndex > 0) + session.clientConnection.QueuePacket(GroupMembersX08Packet.buildPacket(session.sessionId, session.currentZoneId, time, members, ref currentIndex), true, false); + else + break; + } + + session.clientConnection.QueuePacket(GroupMembersEndPacket.buildPacket(session.sessionId, session.currentZoneId, time, this), true, false); + + } } } diff --git a/FFXIVClassic World Server/DataObjects/Group/Linkshell.cs b/FFXIVClassic World Server/DataObjects/Group/Linkshell.cs index 735eae36..57f06c42 100644 --- a/FFXIVClassic World Server/DataObjects/Group/Linkshell.cs +++ b/FFXIVClassic World Server/DataObjects/Group/Linkshell.cs @@ -1,8 +1,10 @@ -using System; +using FFXIVClassic_World_Server.Actor.Group.Work; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups; namespace FFXIVClassic_World_Server.DataObjects.Group { @@ -10,19 +12,63 @@ namespace FFXIVClassic_World_Server.DataObjects.Group { public ulong dbId; public string name; - public ushort crestId; - public uint master; - public ushort rank; + + public LinkshellWork linkshellWork = new LinkshellWork(); public Dictionary members = new Dictionary(); - public Linkshell(ulong dbId, ulong groupIndex, string name, ushort crestId, uint master, ushort rank) : base(groupIndex) + public Linkshell(ulong dbId, ulong groupIndex, string name, ushort crestId, uint master, byte rank) : base(groupIndex) { this.dbId = dbId; this.name = name; - this.crestId = crestId; - this.master = master; - this.rank = rank; + linkshellWork._globalSave.crestIcon[0] = crestId; + linkshellWork._globalSave.master = master; + linkshellWork._globalSave.rank = rank; + } + + public void setMaster(uint actorId) + { + linkshellWork._globalSave.master = (ulong)((0xB36F92 << 8) | actorId); + } + + public void setCrest(ushort crestId) + { + linkshellWork._globalSave.crestIcon[0] = crestId; + } + + public void setRank(byte rank = 1) + { + linkshellWork._globalSave.rank = rank; + } + + public void setMemberRank(int index, byte rank) + { + if (members.Count >= index) + return; + linkshellWork._memberSave[index].rank = rank; + } + + public override int GetMemberCount() + { + return members.Count; + } + + public override string GetGroupName() + { + return name; + } + + public override uint GetTypeId() + { + return Group.CompanyGroup; + } + + public override List BuildMemberList() + { + List groupMembers = new List(); + foreach (LinkshellMember member in members.Values) + groupMembers.Add(new GroupMember(member.charaId, -1, 0, false, Server.GetServer().GetSession(member.charaId) != null, Server.GetServer().GetNameForId(member.charaId))); + return groupMembers; } } } diff --git a/FFXIVClassic World Server/DataObjects/Group/Party.cs b/FFXIVClassic World Server/DataObjects/Group/Party.cs index 16caf573..ff0413a3 100644 --- a/FFXIVClassic World Server/DataObjects/Group/Party.cs +++ b/FFXIVClassic World Server/DataObjects/Group/Party.cs @@ -1,4 +1,6 @@ -using System; +using FFXIVClassic_World_Server.Actor.Group.Work; +using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,12 +10,53 @@ namespace FFXIVClassic_World_Server.DataObjects.Group { class Party : Group { - public uint leader; + public PartyWork partyGroupWork = new PartyWork(); public List members = new List(); public Party(ulong groupId, uint leaderCharaId) : base(groupId) { - this.leader = leaderCharaId; + partyGroupWork._globalTemp.owner = (ulong)((0xB36F92 << 8) | leaderCharaId); } + + public void SetLeader(uint actorId) + { + partyGroupWork._globalTemp.owner = (ulong)((0xB36F92 << 8) | actorId); + } + + public uint GetLeader() + { + return (uint)(partyGroupWork._globalTemp.owner & 0xFFFFFF); + } + + /* + public override void sendWorkValues(Session session) + { + SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(groupId); + groupWork.addProperty(this, "partyGroupWork._globalTemp.owner"); + groupWork.setTarget("/_init"); + + SubPacket test = groupWork.buildPacket(session.sessionId, session.sessionId); + session.clientConnection.QueuePacket(test, true, false); + } + */ + + public override int GetMemberCount() + { + return members.Count; + } + + public override uint GetTypeId() + { + return Group.PlayerPartyGroup; + } + + public override List BuildMemberList() + { + List groupMembers = new List(); + foreach (uint charaId in members) + groupMembers.Add(new GroupMember(charaId, -1, 0, false, Server.GetServer().GetSession(charaId) != null, Server.GetServer().GetNameForId(charaId))); + return groupMembers; + } + } } diff --git a/FFXIVClassic World Server/DataObjects/Group/Relation.cs b/FFXIVClassic World Server/DataObjects/Group/Relation.cs index ad74777b..aedfecac 100644 --- a/FFXIVClassic World Server/DataObjects/Group/Relation.cs +++ b/FFXIVClassic World Server/DataObjects/Group/Relation.cs @@ -1,4 +1,5 @@ -using System; +using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -17,5 +18,24 @@ namespace FFXIVClassic_World_Server.DataObjects.Group this.charaOther = other; this.command = command; } + + public override int GetMemberCount() + { + return 2; + } + + public override uint GetTypeId() + { + return Group.GroupInvitationRelationGroup; + } + + public override List BuildMemberList() + { + List groupMembers = new List(); + groupMembers.Add(new GroupMember(charaHost, -1, 0, false, Server.GetServer().GetSession(charaHost) != null, Server.GetServer().GetNameForId(charaHost))); + groupMembers.Add(new GroupMember(charaOther, -1, 0, false, Server.GetServer().GetSession(charaOther) != null, Server.GetServer().GetNameForId(charaOther))); + return groupMembers; + } + } } diff --git a/FFXIVClassic World Server/DataObjects/Group/RetainerGroup.cs b/FFXIVClassic World Server/DataObjects/Group/RetainerGroup.cs index 77e935c8..72c11616 100644 --- a/FFXIVClassic World Server/DataObjects/Group/RetainerGroup.cs +++ b/FFXIVClassic World Server/DataObjects/Group/RetainerGroup.cs @@ -1,4 +1,6 @@ -using System; +using FFXIVClassic_World_Server.Actor.Group.Work; +using FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,6 +10,7 @@ namespace FFXIVClassic_World_Server.DataObjects.Group { class RetainerGroup : Group { + public RetainerWork work = new RetainerWork(); public uint owner; public Dictionary members = new Dictionary(); @@ -15,5 +18,48 @@ namespace FFXIVClassic_World_Server.DataObjects.Group { this.owner = owner; } + + public void setRetainerProperties(int index, byte cdIDOffset, ushort placeName, byte condition, byte level) + { + if (members.Count >= index) + return; + work._memberSave[index].cdIDOffset = cdIDOffset; + work._memberSave[index].placeName = placeName; + work._memberSave[index].conditions = condition; + work._memberSave[index].level = level; + } + + /* + public override void sendWorkValues(Session session) + { + SynchGroupWorkValuesPacket groupWork = new SynchGroupWorkValuesPacket(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(session.sessionId, session.sessionId); + session.clientConnection.QueuePacket(test, true, false); + } + */ + + public override int GetMemberCount() + { + return members.Count; + } + + public override uint GetTypeId() + { + return Group.RetainerGroup; + } + + public override List BuildMemberList() + { + List groupMembers = new List(); + foreach (RetainerGroupMember member in members.Values) + groupMembers.Add(new GroupMember(member.retainerId, -1, 0, false, true, member.name)); + return groupMembers; + } } } diff --git a/FFXIVClassic World Server/DataObjects/Group/RetainerGroupMember.cs b/FFXIVClassic World Server/DataObjects/Group/RetainerGroupMember.cs index 308f263b..f410a5fd 100644 --- a/FFXIVClassic World Server/DataObjects/Group/RetainerGroupMember.cs +++ b/FFXIVClassic World Server/DataObjects/Group/RetainerGroupMember.cs @@ -8,5 +8,7 @@ namespace FFXIVClassic_World_Server.DataObjects.Group { class RetainerGroupMember { + public uint retainerId; + public string name; } } diff --git a/FFXIVClassic World Server/Database.cs b/FFXIVClassic World Server/Database.cs index e9f48004..4f8f2eed 100644 --- a/FFXIVClassic World Server/Database.cs +++ b/FFXIVClassic World Server/Database.cs @@ -50,6 +50,35 @@ namespace FFXIVClassic_World_Server return readIn; } + public static void GetAllCharaNames(Dictionary mIdToNameMap) + { + using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + { + try + { + conn.Open(); + MySqlCommand cmd = new MySqlCommand("SELECT id, name FROM characters", conn); + using (MySqlDataReader Reader = cmd.ExecuteReader()) + { + while (Reader.Read()) + { + uint id = Reader.GetUInt32("id"); + string name = Reader.GetString("name"); + mIdToNameMap.Add(id, name); + } + } + } + catch (MySqlException e) + { + Program.Log.Error(e.ToString()); + } + finally + { + conn.Dispose(); + } + } + } + public static uint GetCurrentZoneForSession(uint charId) { uint currentZone = 0; diff --git a/FFXIVClassic World Server/FFXIVClassic World Server.csproj b/FFXIVClassic World Server/FFXIVClassic World Server.csproj index 3b738158..a8cfedad 100644 --- a/FFXIVClassic World Server/FFXIVClassic World Server.csproj +++ b/FFXIVClassic World Server/FFXIVClassic World Server.csproj @@ -64,6 +64,20 @@ + + + + + + + + + + + + + + @@ -79,6 +93,18 @@ + + + + + + + + + + + + diff --git a/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/CreateNamedGroup.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/CreateNamedGroup.cs new file mode 100644 index 00000000..0e883163 --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/CreateNamedGroup.cs @@ -0,0 +1,41 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.Actor.Group; +using FFXIVClassic_World_Server.DataObjects.Group; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups +{ + class CreateNamedGroup + { + public const ushort OPCODE = 0x0188; + public const uint PACKET_SIZE = 0x60; + + public static SubPacket buildPacket(uint sessionId, 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.groupIndex); + binWriter.Write((UInt32)group.GetTypeId()); + binWriter.Write((Int32)group.GetGroupLocalizedName()); + + binWriter.Write((UInt16)0x121C); + + binWriter.Seek(0x20, SeekOrigin.Begin); + + binWriter.Write(Encoding.ASCII.GetBytes(group.GetGroupName()), 0, Encoding.ASCII.GetByteCount(group.GetGroupName()) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.GetGroupName())); + } + } + + return new SubPacket(OPCODE, sessionId, sessionId, data); + } + } +} diff --git a/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/CreateNamedGroupMultiple.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/CreateNamedGroupMultiple.cs new file mode 100644 index 00000000..c6a5f7e8 --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/CreateNamedGroupMultiple.cs @@ -0,0 +1,55 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.Actor.Group; +using FFXIVClassic_World_Server.DataObjects.Group; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups +{ + 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.groupIndex); + binWriter.Write((UInt32)group.GetTypeId()); + binWriter.Write((Int32)group.GetGroupLocalizedName()); + + binWriter.Write((UInt16)0x121C); + + binWriter.Seek(0x20, SeekOrigin.Begin); + + binWriter.Write(Encoding.ASCII.GetBytes(group.GetGroupName()), 0, Encoding.ASCII.GetByteCount(group.GetGroupName()) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.GetGroupName())); + } + + binWriter.Seek(0x200, SeekOrigin.Begin); + binWriter.Write((Byte)max); + } + } + + return new SubPacket(OPCODE, playerActorID, playerActorID, data); + } + } +} diff --git a/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/DeleteGroupPacket.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/DeleteGroupPacket.cs new file mode 100644 index 00000000..1d1f7fe9 --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/DeleteGroupPacket.cs @@ -0,0 +1,44 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.Actor.Group; +using FFXIVClassic_World_Server.DataObjects.Group; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups +{ + class DeleteGroupPacket + { + public const ushort OPCODE = 0x0143; + public const uint PACKET_SIZE = 0x40; + + public static SubPacket buildPacket(uint sessionId, Group group) + { + return buildPacket(sessionId, group.groupIndex); + } + + public static SubPacket buildPacket(uint sessionId, ulong groupId) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryWriter binWriter = new BinaryWriter(mem)) + { + //Write control num ???? + binWriter.Write((UInt64)3); + + //Write Ids + binWriter.Write((UInt64)groupId); + binWriter.Write((UInt64)0); + binWriter.Write((UInt64)groupId); + } + } + + return new SubPacket(OPCODE, sessionId, sessionId, data); + } + } +} diff --git a/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupHeaderPacket.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupHeaderPacket.cs new file mode 100644 index 00000000..0c237f5e --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupHeaderPacket.cs @@ -0,0 +1,61 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.DataObjects.Group; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups +{ + 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.groupIndex); + binWriter.Write((UInt64)0); + binWriter.Write((UInt64)group.groupIndex); + + //This seems to change depending on what the list is for + binWriter.Write((UInt32)group.GetTypeId()); + binWriter.Seek(0x40, SeekOrigin.Begin); + + //This is for Linkshell + binWriter.Write((UInt32)group.GetGroupLocalizedName()); + binWriter.Write(Encoding.ASCII.GetBytes(group.GetGroupName()), 0, Encoding.ASCII.GetByteCount(group.GetGroupName()) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(group.GetGroupName())); + + 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.GetMemberCount()); + } + } + + return new SubPacket(OPCODE, playerActorID, playerActorID, data); + } + } +} diff --git a/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMember.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMember.cs new file mode 100644 index 00000000..8c6b8944 --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMember.cs @@ -0,0 +1,24 @@ +using FFXIVClassic.Common; + +namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups +{ + 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 World Server/Packets/Send/Subpackets/Groups/GroupMembersBeginPacket.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersBeginPacket.cs new file mode 100644 index 00000000..5717d77b --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersBeginPacket.cs @@ -0,0 +1,37 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.DataObjects.Group; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups +{ + 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.groupIndex); + binWriter.Write((UInt32)group.GetMemberCount()); + } + } + + return new SubPacket(OPCODE, playerActorID, playerActorID, data); + } + } +} diff --git a/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersEndPacket.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersEndPacket.cs new file mode 100644 index 00000000..f3ed55e8 --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersEndPacket.cs @@ -0,0 +1,38 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.Actor.Group; +using FFXIVClassic_World_Server.DataObjects.Group; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups +{ + class GroupMembersEndPacket + { + public const ushort OPCODE = 0x017E; + public const uint PACKET_SIZE = 0x38; + + public static SubPacket buildPacket(uint sessionId, 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.groupIndex); + } + } + + return new SubPacket(OPCODE, sessionId, sessionId, data); + } + + } +} diff --git a/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX08Packet.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX08Packet.cs new file mode 100644 index 00000000..abc6e747 --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/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_World_Server.Packets.Send.Subpackets.Groups +{ + 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 World Server/Packets/Send/Subpackets/Groups/GroupMembersX16Packet.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX16Packet.cs new file mode 100644 index 00000000..6a12581c --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/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_World_Server.Packets.Send.Subpackets.Groups +{ + 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 World Server/Packets/Send/Subpackets/Groups/GroupMembersX32Packet.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX32Packet.cs new file mode 100644 index 00000000..1453353b --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/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_World_Server.Packets.Send.Subpackets.Groups +{ + 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 World Server/Packets/Send/Subpackets/Groups/GroupMembersX64Packet.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/GroupMembersX64Packet.cs new file mode 100644 index 00000000..6787c1fa --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/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_World_Server.Packets.Send.Subpackets.Groups +{ + 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); + } + } +} diff --git a/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/SynchGroupWorkValuesPacket.cs b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/SynchGroupWorkValuesPacket.cs new file mode 100644 index 00000000..3ff485d3 --- /dev/null +++ b/FFXIVClassic World Server/Packets/Send/Subpackets/Groups/SynchGroupWorkValuesPacket.cs @@ -0,0 +1,211 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.Actor.Group; +using FFXIVClassic_World_Server.DataObjects.Group; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.Send.Subpackets.Groups +{ + class SynchGroupWorkValuesPacket + { + public const ushort OPCODE = 0x017A; + public const uint PACKET_SIZE = 0xB0; + + private const ushort MAXBYTES = 0x98; + + private ushort runningByteTotal = 0; + private byte[] data = new byte[PACKET_SIZE - 0x20]; + private bool isMore = false; + + private MemoryStream mem; + private BinaryWriter binWriter; + + public SynchGroupWorkValuesPacket(ulong listId) + { + mem = new MemoryStream(data); + binWriter = new BinaryWriter(mem); + binWriter.Write((UInt64)listId); + binWriter.Seek(1, SeekOrigin.Current); + } + + public void closeStreams() + { + binWriter.Dispose(); + mem.Dispose(); + } + + public bool addByte(uint id, byte value) + { + if (runningByteTotal + 6 > MAXBYTES) + return false; + + binWriter.Write((byte)1); + binWriter.Write((UInt32)id); + binWriter.Write((byte)value); + runningByteTotal += 6; + + return true; + } + + public bool addShort(uint id, ushort value) + { + if (runningByteTotal + 7 > MAXBYTES) + return false; + + binWriter.Write((byte)2); + binWriter.Write((UInt32)id); + binWriter.Write((UInt16)value); + runningByteTotal += 7; + + return true; + } + + public bool addInt(uint id, uint value) + { + if (runningByteTotal + 9 > MAXBYTES) + return false; + + binWriter.Write((byte)4); + binWriter.Write((UInt32)id); + binWriter.Write((UInt32)value); + runningByteTotal += 9; + + return true; + } + + public bool addLong(uint id, ulong value) + { + if (runningByteTotal + 13 > MAXBYTES) + return false; + + binWriter.Write((byte)8); + binWriter.Write((UInt32)id); + binWriter.Write((UInt64)value); + runningByteTotal += 13; + + return true; + } + + public bool addBuffer(uint id, byte[] buffer) + { + if (runningByteTotal + 5 + buffer.Length > MAXBYTES) + return false; + + binWriter.Write((byte)buffer.Length); + binWriter.Write((UInt32)id); + binWriter.Write(buffer); + runningByteTotal += (ushort)(5 + buffer.Length); + + return true; + } + + public void addProperty(Group group, string name) + { + string[] split = name.Split('.'); + int arrayIndex = 0; + + if (!(split[0].Equals("work") || split[0].Equals("partyGroupWork"))) + return; + + Object curObj = group; + for (int i = 0; i < split.Length; i++) + { + //For arrays + if (split[i].Contains('[')) + { + if (split[i].LastIndexOf(']') - split[i].IndexOf('[') <= 0) + return; + + arrayIndex = Convert.ToInt32(split[i].Substring(split[i].IndexOf('[') + 1, split[i].Length - split[i].LastIndexOf(']'))); + + split[i] = split[i].Substring(0, split[i].IndexOf('[')); + + if (i != split.Length - 1) + { + curObj = curObj.GetType().GetField(split[i]).GetValue(curObj); + curObj = ((Array)curObj).GetValue(arrayIndex); + i++; + } + } + + FieldInfo field = curObj.GetType().GetField(split[i]); + if (field == null) + return; + + curObj = field.GetValue(curObj); + if (curObj == null) + return; + } + + if (curObj == null) + return; + else + { + //Array, we actually care whats inside + if (curObj.GetType().IsArray) + { + if (((Array)curObj).Length <= arrayIndex) + return; + curObj = ((Array)curObj).GetValue(arrayIndex); + } + + if (curObj == null) + return; + + //Cast to the proper object and add to packet + uint id = Utils.MurmurHash2(name, 0); + if (curObj is bool) + addByte(id, (byte)(((bool)curObj) ? 1 : 0)); + else if (curObj is byte) + addByte(id, (byte)curObj); + else if (curObj is ushort) + addShort(id, (ushort)curObj); + else if (curObj is short) + addShort(id, (ushort)(short)curObj); + else if (curObj is uint) + addInt(id, (uint)curObj); + else if (curObj is int) + addInt(id, (uint)(int)curObj); + else if (curObj is long) + addLong(id, (ulong)(long)curObj); + else if (curObj is ulong) + addLong(id, (ulong)curObj); + else if (curObj is float) + addBuffer(id, BitConverter.GetBytes((float)curObj)); + else + return; + } + } + + public void setIsMore(bool flag) + { + isMore = flag; + } + + public void setTarget(string target) + { + binWriter.Write((byte)(isMore ? 0x62 + target.Length : 0x82 + target.Length)); + binWriter.Write(Encoding.ASCII.GetBytes(target)); + runningByteTotal += (ushort)(1 + Encoding.ASCII.GetByteCount(target)); + + } + + public SubPacket buildPacket(uint playerActorID, uint actorID) + { + binWriter.Seek(0x8, SeekOrigin.Begin); + binWriter.Write((byte)runningByteTotal); + + closeStreams(); + + SubPacket packet = new SubPacket(OPCODE, playerActorID, actorID, data); + return packet; + } + + } +} + diff --git a/FFXIVClassic World Server/PartyManager.cs b/FFXIVClassic World Server/PartyManager.cs index 8d6a582a..b0bdb088 100644 --- a/FFXIVClassic World Server/PartyManager.cs +++ b/FFXIVClassic World Server/PartyManager.cs @@ -60,8 +60,8 @@ namespace FFXIVClassic_World_Server party.members.Remove(charaId); //If current ldr, make a new ldr if not empty pt - if (party.leader == charaId && party.members.Count != 0) - party.leader = party.members[0]; + if (party.GetLeader() == charaId && party.members.Count != 0) + party.SetLeader(party.members[0]); } return party.members.Count; } @@ -75,7 +75,7 @@ namespace FFXIVClassic_World_Server Party party = mPartyList[groupId]; if (party.members.Contains(charaId)) { - party.leader = charaId; + party.SetLeader(charaId); return true; } } diff --git a/FFXIVClassic World Server/Server.cs b/FFXIVClassic World Server/Server.cs index 41ce633d..c3ec0005 100644 --- a/FFXIVClassic World Server/Server.cs +++ b/FFXIVClassic World Server/Server.cs @@ -17,14 +17,16 @@ namespace FFXIVClassic_World_Server public const int BACKLOG = 100; private static Server mSelf; - //Connection and Session Management + //Connections private Socket mServerSocket; - WorldManager mWorldManager; PacketProcessor mPacketProcessor; - private List mConnectionList = new List(); + //Preloaded Maps + private Dictionary mIdToNameMap = new Dictionary(); + //Session Management + private List mConnectionList = new List(); private Dictionary mZoneSessionList = new Dictionary(); private Dictionary mChatSessionList = new Dictionary(); @@ -58,7 +60,7 @@ namespace FFXIVClassic_World_Server mWorldManager = new WorldManager(this); mWorldManager.LoadZoneServerList(); mWorldManager.LoadZoneEntranceList(); - mWorldManager.ConnectToZoneServers(); + mWorldManager.ConnectToZoneServers(); IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT)); @@ -91,24 +93,28 @@ namespace FFXIVClassic_World_Server Console.ForegroundColor = ConsoleColor.White; Program.Log.Info("World Server accepting connections @ {0}:{1}", (mServerSocket.LocalEndPoint as IPEndPoint).Address, (mServerSocket.LocalEndPoint as IPEndPoint).Port); Console.ForegroundColor = ConsoleColor.Gray; - + return true; - } + } public void AddSession(ClientConnection connection, Session.Channel type, uint id) { Session session = new Session(id, connection, type); - + switch (type) { case Session.Channel.ZONE: + //New character since world server loaded + if (!mIdToNameMap.ContainsKey(id)) + AddNameToMap(id, session.characterName); + if (!mZoneSessionList.ContainsKey(id)) mZoneSessionList.Add(id, session); - break; + break; case Session.Channel.CHAT: if (!mChatSessionList.ContainsKey(id)) mChatSessionList.Add(id, session); - break; + break; } } @@ -116,7 +122,7 @@ namespace FFXIVClassic_World_Server { switch (type) { - case Session.Channel.ZONE: + case Session.Channel.ZONE: if (mZoneSessionList.ContainsKey(id)) { mZoneSessionList[id].clientConnection.Disconnect(); @@ -132,7 +138,7 @@ namespace FFXIVClassic_World_Server mChatSessionList.Remove(id); } break; - } + } } public Session GetSession(uint targetSession, Session.Channel type = Session.Channel.ZONE) @@ -148,12 +154,12 @@ namespace FFXIVClassic_World_Server return mChatSessionList[targetSession]; break; } - + return null; } - + public void OnReceiveSubPacketFromZone(ZoneServer zoneServer, SubPacket subpacket) - { + { uint sessionId = subpacket.header.targetId; if (subpacket.gameMessage.opcode >= 0x1000) @@ -207,7 +213,7 @@ namespace FFXIVClassic_World_Server //Group get data request case 0x1020: GetGroupPacket getGroupPacket = new GetGroupPacket(subpacket.data); - SendGroupData(session, getGroupPacket.groupId); + SendGroupData(session, getGroupPacket.groupId); break; //Group delete request case 0x1021: @@ -226,7 +232,7 @@ namespace FFXIVClassic_World_Server break; //Group Add/Remove Member case 0x1022: - GroupMemberChangePacket gMemberChangePacket = new GroupMemberChangePacket(subpacket.data); + GroupMemberChangePacket gMemberChangePacket = new GroupMemberChangePacket(subpacket.data); break; } } @@ -236,7 +242,7 @@ namespace FFXIVClassic_World_Server conn.QueuePacket(subpacket, true, false); conn.FlushQueuedSendPackets(); } - + } public WorldManager GetWorldManager() @@ -307,7 +313,7 @@ namespace FFXIVClassic_World_Server { mConnectionList.Remove(conn); } - + return; } @@ -333,7 +339,7 @@ namespace FFXIVClassic_World_Server { mPacketProcessor.ProcessPacket(conn, basePacket); } - + } //Not all bytes consumed, transfer leftover to beginning @@ -354,7 +360,7 @@ namespace FFXIVClassic_World_Server } else { - + lock (mConnectionList) { mConnectionList.Remove(conn); @@ -365,7 +371,7 @@ namespace FFXIVClassic_World_Server { if (conn.socket != null) { - + lock (mConnectionList) { mConnectionList.Remove(conn); @@ -376,12 +382,29 @@ namespace FFXIVClassic_World_Server #endregion + public void LoadCharaNames() + { + Database.GetAllCharaNames(mIdToNameMap); + } + + public void AddNameToMap(uint charaId, string name) + { + mIdToNameMap.Add(charaId, name); + } + + public string GetNameForId(uint charaId) + { + if (mIdToNameMap.ContainsKey(charaId)) + return mIdToNameMap[charaId]; + return null; + } + private void SendGroupData(Session session, ulong groupId) { if (mCurrentWorldGroups.ContainsKey(groupId)) { Group group = mCurrentWorldGroups[groupId]; - + } }