From 4eda13501c803b95a835968ea4286c997e7407a2 Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Sun, 6 Dec 2015 20:23:34 -0500 Subject: [PATCH] Added receiving packets for GM stuff. Started implementing the recruitment packets. --- .../FFXIVClassic Map Server.csproj | 9 +++ FFXIVClassic Map Server/PacketProcessor.cs | 48 +++++++++++++--- .../dataobjects/RecruitmentDetails.cs | 26 +++++++++ .../dataobjects/SearchEntry.cs | 39 +++++++++++++ .../RecruitmentSearchRequestPacket.cs | 49 ++++++++++++++++ .../StartRecruitingRequestPacket.cs | 56 +++++++++++++++++++ .../supportdesk/FaqBodyRequestPacket.cs | 34 +++++++++++ .../supportdesk/FaqListRequestPacket.cs | 33 +++++++++++ .../GMTicketIssuesRequestPacket.cs | 31 ++++++++++ .../CurrentRecruitmentDetailsPacket.cs | 56 +++++++++++++++++++ .../recruitment/StartRecruitingResponse.cs | 24 ++++++++ 11 files changed, 396 insertions(+), 9 deletions(-) create mode 100644 FFXIVClassic Map Server/dataobjects/RecruitmentDetails.cs create mode 100644 FFXIVClassic Map Server/dataobjects/SearchEntry.cs create mode 100644 FFXIVClassic Map Server/packets/receive/recruitment/RecruitmentSearchRequestPacket.cs create mode 100644 FFXIVClassic Map Server/packets/receive/recruitment/StartRecruitingRequestPacket.cs create mode 100644 FFXIVClassic Map Server/packets/receive/supportdesk/FaqBodyRequestPacket.cs create mode 100644 FFXIVClassic Map Server/packets/receive/supportdesk/FaqListRequestPacket.cs create mode 100644 FFXIVClassic Map Server/packets/receive/supportdesk/GMTicketIssuesRequestPacket.cs create mode 100644 FFXIVClassic Map Server/packets/send/recruitment/CurrentRecruitmentDetailsPacket.cs create mode 100644 FFXIVClassic Map Server/packets/send/recruitment/StartRecruitingResponse.cs diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj index 393f317c..80e19018 100644 --- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj +++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj @@ -86,9 +86,13 @@ + + + + @@ -96,6 +100,9 @@ + + + @@ -133,6 +140,8 @@ + + diff --git a/FFXIVClassic Map Server/PacketProcessor.cs b/FFXIVClassic Map Server/PacketProcessor.cs index de1346bf..73ba9557 100644 --- a/FFXIVClassic Map Server/PacketProcessor.cs +++ b/FFXIVClassic Map Server/PacketProcessor.cs @@ -24,6 +24,9 @@ using FFXIVClassic_Map_Server.dataobjects.chara; using FFXIVClassic_Map_Server.packets.send.supportdesk; using FFXIVClassic_Map_Server.packets.receive.social; using FFXIVClassic_Map_Server.packets.send.social; +using FFXIVClassic_Map_Server.packets.receive.supportdesk; +using FFXIVClassic_Map_Server.packets.receive.recruitment; +using FFXIVClassic_Map_Server.packets.send.recruitment; namespace FFXIVClassic_Lobby_Server { @@ -338,6 +341,35 @@ namespace FFXIVClassic_Lobby_Server case 0x012F: subpacket.debugPrintSubPacket(); break; + /* RECRUITMENT */ + //Start Recruiting + case 0x01C3: + StartRecruitingRequestPacket recruitRequestPacket = new StartRecruitingRequestPacket(subpacket.data); + client.queuePacket(BasePacket.createPacket(StartRecruitingResponse.buildPacket(player.actorID, true), true, false)); + break; + case 0x01C7: + subpacket.debugPrintSubPacket(); + RecruitmentSearchRequestPacket recruitSearchPacket = new RecruitmentSearchRequestPacket(subpacket.data); + break; + //Current Recruitment Details + case 0x01C8: + subpacket.debugPrintSubPacket(); + //CurrentRecruitmentDetailsPacket currentRecruitDetailsPacket = new CurrentRecruitmentDetailsPacket(subpacket.data); + RecruitmentDetails details = new RecruitmentDetails(); + details.recruiterName = "Localhost Character"; + details.purposeId = 2; + details.locationId = 1; + details.subTaskId = 1; + details.comment = "This is a test details packet sent by the server. No implementation has been created yet..."; + details.num[0] = 1; + client.queuePacket(BasePacket.createPacket(CurrentRecruitmentDetailsPacket.buildPacket(player.actorID, details), true, false)); + break; + //Party Window Opened, Request State + case 0x01C5: + case 0x01C4: + case 0x01C6: + subpacket.debugPrintSubPacket(); + break; /* SOCIAL STUFF */ case 0x01C9: AddRemoveSocialPacket addBlackList = new AddRemoveSocialPacket(subpacket.data); @@ -349,7 +381,7 @@ namespace FFXIVClassic_Lobby_Server break; case 0x01CC: AddRemoveSocialPacket addFriendList = new AddRemoveSocialPacket(subpacket.data); - client.queuePacket(BasePacket.createPacket(FriendlistAddedPacket.buildPacket(player.actorID, true, (uint)10, true, addFriendList.name), true, false)); + client.queuePacket(BasePacket.createPacket(FriendlistAddedPacket.buildPacket(player.actorID, true, (uint)addFriendList.name.GetHashCode(), true, addFriendList.name), true, false)); break; case 0x01CD: AddRemoveSocialPacket removeFriendList = new AddRemoveSocialPacket(subpacket.data); @@ -360,29 +392,27 @@ namespace FFXIVClassic_Lobby_Server break; /* SUPPORT DESK STUFF */ //Request for FAQ/Info List - case 0x01D0: - subpacket.debugPrintSubPacket(); + case 0x01D0: + FaqListRequestPacket faqRequest = new FaqListRequestPacket(subpacket.data); client.queuePacket(BasePacket.createPacket(FaqListResponsePacket.buildPacket(player.actorID, new string[]{"Testing FAQ1", "Coded style!"}), true, false)); break; //Request for body of a faq/info selection case 0x01D1: - client.queuePacket(BasePacket.createPacket(FaqBodyResponsePacket.buildPacket(player.actorID, "HERE IS A GIANT BODY. Nothing else to say!"), true, false)); - subpacket.debugPrintSubPacket(); + FaqBodyRequestPacket faqBodyRequest = new FaqBodyRequestPacket(subpacket.data); + client.queuePacket(BasePacket.createPacket(FaqBodyResponsePacket.buildPacket(player.actorID, "HERE IS A GIANT BODY. Nothing else to say!"), true, false)); break; //Request issue list case 0x01D2: - client.queuePacket(BasePacket.createPacket(IssueListResponsePacket.buildPacket(player.actorID, new string[] { "Test1", "Test2", "Test3", "Test4", "Test5"}), true, false)); - subpacket.debugPrintSubPacket(); + GMTicketIssuesRequestPacket issuesRequest = new GMTicketIssuesRequestPacket(subpacket.data); + client.queuePacket(BasePacket.createPacket(IssueListResponsePacket.buildPacket(player.actorID, new string[] { "Test1", "Test2", "Test3", "Test4", "Test5"}), true, false)); break; //Request for GM response message case 0x01D4: client.queuePacket(BasePacket.createPacket(GMTicketPacket.buildPacket(player.actorID, "This is a GM Ticket Title", "This is a GM Ticket Body."), true, false)); - subpacket.debugPrintSubPacket(); break; //Request to end ticket case 0x01D6: client.queuePacket(BasePacket.createPacket(EndGMTicketPacket.buildPacket(player.actorID), true, false)); - subpacket.debugPrintSubPacket(); break; default: Log.debug(String.Format("Unknown command 0x{0:X} received.", subpacket.gameMessage.opcode)); diff --git a/FFXIVClassic Map Server/dataobjects/RecruitmentDetails.cs b/FFXIVClassic Map Server/dataobjects/RecruitmentDetails.cs new file mode 100644 index 00000000..9acc647b --- /dev/null +++ b/FFXIVClassic Map Server/dataobjects/RecruitmentDetails.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.dataobjects +{ + class RecruitmentDetails + { + public string recruiterName; + public string comment; + + public uint purposeId; + public uint locationId; + public uint subTaskId; + public uint timeSinceStart; + + public uint[] discipleId = new uint[4]; + public uint[] classjobId = new uint[4]; + public byte[] minLvl = new byte[4]; + public byte[] maxLvl = new byte[4]; + public byte[] num = new byte[4]; + + } +} diff --git a/FFXIVClassic Map Server/dataobjects/SearchEntry.cs b/FFXIVClassic Map Server/dataobjects/SearchEntry.cs new file mode 100644 index 00000000..ad94a040 --- /dev/null +++ b/FFXIVClassic Map Server/dataobjects/SearchEntry.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.dataobjects +{ + class SearchEntry + { + public ushort preferredClass; + public ushort langauges; + public ushort location; + public ushort grandCompany; + public ushort status; + public ushort currentClass; + public string name; + public ushort[] classes = new ushort[2 * 20]; + public ushort[] jobs = new ushort[8]; + + public void writeSearchEntry(BinaryWriter writer) + { + writer.Write((UInt16)preferredClass); + writer.Write((UInt16)langauges); + writer.Write((UInt16)location); + writer.Write((UInt16)grandCompany); + writer.Write((UInt16)status); + writer.Write((UInt16)currentClass); + + writer.Write(Encoding.ASCII.GetBytes(name), 0, Encoding.ASCII.GetByteCount(name) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(name)); + + for (int i = 0; i < classes.Length; i++) + writer.Write((UInt16)classes[i]); + for (int i = 0; i < jobs.Length; i++) + writer.Write((UInt16)jobs[i]); + } + } +} diff --git a/FFXIVClassic Map Server/packets/receive/recruitment/RecruitmentSearchRequestPacket.cs b/FFXIVClassic Map Server/packets/receive/recruitment/RecruitmentSearchRequestPacket.cs new file mode 100644 index 00000000..07f55b10 --- /dev/null +++ b/FFXIVClassic Map Server/packets/receive/recruitment/RecruitmentSearchRequestPacket.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.packets.receive.recruitment +{ + class RecruitmentSearchRequestPacket + { + public bool invalidPacket = false; + + public uint purposeId; + public uint locationId; + + public uint discipleId; + public uint classjobId; + + public byte unknown1; + public byte unknown2; + + public string text; + + public RecruitmentSearchRequestPacket(byte[] data) + { + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryReader binReader = new BinaryReader(mem)) + { + try{ + purposeId = binReader.ReadUInt32(); + locationId = binReader.ReadUInt32(); + discipleId = binReader.ReadUInt32(); + classjobId = binReader.ReadUInt32(); + + unknown1 = binReader.ReadByte(); + unknown2 = binReader.ReadByte(); + + text = Encoding.ASCII.GetString(binReader.ReadBytes(0x20)); + } + catch (Exception){ + invalidPacket = true; + } + } + } + } + } +} diff --git a/FFXIVClassic Map Server/packets/receive/recruitment/StartRecruitingRequestPacket.cs b/FFXIVClassic Map Server/packets/receive/recruitment/StartRecruitingRequestPacket.cs new file mode 100644 index 00000000..154bbb7e --- /dev/null +++ b/FFXIVClassic Map Server/packets/receive/recruitment/StartRecruitingRequestPacket.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.packets.receive.recruitment +{ + class StartRecruitingRequestPacket + { + public bool invalidPacket = false; + + public uint purposeId; + public uint locationId; + public uint subTaskId; + + public uint[] discipleId = new uint[4]; + public uint[] classjobId = new uint[4]; + public byte[] minLvl = new byte[4]; + public byte[] maxLvl = new byte[4]; + public byte[] num = new byte[4]; + + public string comment; + + public StartRecruitingRequestPacket(byte[] data) + { + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryReader binReader = new BinaryReader(mem)) + { + try{ + purposeId = binReader.ReadUInt32(); + locationId = binReader.ReadUInt32(); + subTaskId = binReader.ReadUInt32(); + + for (int i = 0; i < 4; i++) + { + discipleId[i] = binReader.ReadUInt32(); + classjobId[i] = binReader.ReadUInt32(); + minLvl[i] = binReader.ReadByte(); + maxLvl[i] = binReader.ReadByte(); + num[i] = binReader.ReadByte(); + binReader.ReadByte(); + } + + comment = Encoding.ASCII.GetString(binReader.ReadBytes(0x168)); + } + catch (Exception){ + invalidPacket = true; + } + } + } + } + } +} diff --git a/FFXIVClassic Map Server/packets/receive/supportdesk/FaqBodyRequestPacket.cs b/FFXIVClassic Map Server/packets/receive/supportdesk/FaqBodyRequestPacket.cs new file mode 100644 index 00000000..bcf2a398 --- /dev/null +++ b/FFXIVClassic Map Server/packets/receive/supportdesk/FaqBodyRequestPacket.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.packets.receive.supportdesk +{ + class FaqBodyRequestPacket + { + public bool invalidPacket = false; + public uint faqIndex; + public uint langCode; + + public FaqBodyRequestPacket(byte[] data) + { + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryReader binReader = new BinaryReader(mem)) + { + try + { + faqIndex = binReader.ReadUInt32(); + langCode = binReader.ReadUInt32(); + } + catch (Exception){ + invalidPacket = true; + } + } + } + } + } +} diff --git a/FFXIVClassic Map Server/packets/receive/supportdesk/FaqListRequestPacket.cs b/FFXIVClassic Map Server/packets/receive/supportdesk/FaqListRequestPacket.cs new file mode 100644 index 00000000..2bb1376a --- /dev/null +++ b/FFXIVClassic Map Server/packets/receive/supportdesk/FaqListRequestPacket.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.packets.receive.supportdesk +{ + class FaqListRequestPacket + { + public bool invalidPacket = false; + public uint langCode; + public uint unknown; + + public FaqListRequestPacket(byte[] data) + { + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryReader binReader = new BinaryReader(mem)) + { + try{ + langCode = binReader.ReadUInt32(); + unknown = binReader.ReadUInt32(); + } + catch (Exception){ + invalidPacket = true; + } + } + } + } + } +} diff --git a/FFXIVClassic Map Server/packets/receive/supportdesk/GMTicketIssuesRequestPacket.cs b/FFXIVClassic Map Server/packets/receive/supportdesk/GMTicketIssuesRequestPacket.cs new file mode 100644 index 00000000..e3943c90 --- /dev/null +++ b/FFXIVClassic Map Server/packets/receive/supportdesk/GMTicketIssuesRequestPacket.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.packets.receive.supportdesk +{ + class GMTicketIssuesRequestPacket + { + public bool invalidPacket = false; + public uint langCode; + + public GMTicketIssuesRequestPacket(byte[] data) + { + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryReader binReader = new BinaryReader(mem)) + { + try{ + langCode = binReader.ReadUInt32(); + } + catch (Exception){ + invalidPacket = true; + } + } + } + } + } +} diff --git a/FFXIVClassic Map Server/packets/send/recruitment/CurrentRecruitmentDetailsPacket.cs b/FFXIVClassic Map Server/packets/send/recruitment/CurrentRecruitmentDetailsPacket.cs new file mode 100644 index 00000000..fb2ca6cf --- /dev/null +++ b/FFXIVClassic Map Server/packets/send/recruitment/CurrentRecruitmentDetailsPacket.cs @@ -0,0 +1,56 @@ +using FFXIVClassic_Lobby_Server.packets; +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.recruitment +{ + class CurrentRecruitmentDetailsPacket + { + public const ushort OPCODE = 0x01C8; + public const uint PACKET_SIZE = 0x218; + + public static SubPacket buildPacket(uint playerActorID, RecruitmentDetails details) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryWriter binWriter = new BinaryWriter(mem)) + { + if (details == null) + { + return new SubPacket(OPCODE, playerActorID, playerActorID, data); + } + + binWriter.Write((UInt32)details.purposeId); + binWriter.Write((UInt32)details.locationId); + binWriter.Write((UInt32)details.subTaskId); + binWriter.Write((UInt32)details.timeSinceStart); + + for (int i = 0; i < 4; i++) + { + binWriter.Write((UInt32)details.discipleId[i]); + binWriter.Write((UInt32)details.classjobId[i]); + binWriter.Write((byte)details.minLvl[i]); + binWriter.Write((byte)details.maxLvl[i]); + binWriter.Write((byte)details.num[i]); + binWriter.Write((byte)0); + } + + binWriter.Write(Encoding.ASCII.GetBytes(details.comment), 0, Encoding.ASCII.GetByteCount(details.comment) >= 0x168 ? 0x168 : Encoding.ASCII.GetByteCount(details.comment)); + binWriter.Seek(0x1C0, SeekOrigin.Begin); + binWriter.Write(Encoding.ASCII.GetBytes(details.recruiterName), 0, Encoding.ASCII.GetByteCount(details.recruiterName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(details.recruiterName)); + binWriter.Seek(0x1E0, SeekOrigin.Begin); + binWriter.Write((byte)1); + } + } + + return new SubPacket(OPCODE, playerActorID, playerActorID, data); + } + } +} diff --git a/FFXIVClassic Map Server/packets/send/recruitment/StartRecruitingResponse.cs b/FFXIVClassic Map Server/packets/send/recruitment/StartRecruitingResponse.cs new file mode 100644 index 00000000..829b9ce2 --- /dev/null +++ b/FFXIVClassic Map Server/packets/send/recruitment/StartRecruitingResponse.cs @@ -0,0 +1,24 @@ +using FFXIVClassic_Lobby_Server.packets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.packets.send.recruitment +{ + class StartRecruitingResponse + { + public const ushort OPCODE = 0x01C3; + public const uint PACKET_SIZE = 0x28; + + public static SubPacket buildPacket(uint playerActorID, bool success) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + data[0] = (byte)(success ? 0x1 : 0x0); + + return new SubPacket(OPCODE, playerActorID, playerActorID, data); + } + } +}