diff --git a/FFXIVClassic Common Class Lib/SubPacket.cs b/FFXIVClassic Common Class Lib/SubPacket.cs
index 199199d0..6cd3ff27 100644
--- a/FFXIVClassic Common Class Lib/SubPacket.cs
+++ b/FFXIVClassic Common Class Lib/SubPacket.cs
@@ -72,26 +72,38 @@ namespace FFXIVClassic.Common
offset += header.subpacketSize;
}
- public SubPacket(ushort opcode, uint sourceId, uint targetId, byte[] data)
+ public SubPacket(ushort opcode, uint sourceId, uint targetId, byte[] data) : this(true, opcode, sourceId, targetId, data) { }
+
+ public SubPacket(bool isGameMessage, ushort opcode, uint sourceId, uint targetId, byte[] data)
{
header = new SubPacketHeader();
- gameMessage = new GameMessageHeader();
- gameMessage.opcode = opcode;
+ if (isGameMessage)
+ {
+ gameMessage = new GameMessageHeader();
+ gameMessage.opcode = opcode;
+ gameMessage.timestamp = Utils.UnixTimeStampUTC();
+ gameMessage.unknown4 = 0x14;
+ gameMessage.unknown5 = 0x00;
+ gameMessage.unknown6 = 0x00;
+ }
+
header.sourceId = sourceId;
header.targetId = targetId;
- gameMessage.timestamp = Utils.UnixTimeStampUTC();
+ if (isGameMessage)
+ header.type = 0x03;
+ else
+ header.type = opcode;
- header.type = 0x03;
header.unknown1 = 0x00;
- gameMessage.unknown4 = 0x14;
- gameMessage.unknown5 = 0x00;
- gameMessage.unknown6 = 0x00;
this.data = data;
- header.subpacketSize = (ushort) (SUBPACKET_SIZE + GAMEMESSAGE_SIZE + data.Length);
+ header.subpacketSize = (ushort) (SUBPACKET_SIZE + data.Length);
+
+ if (isGameMessage)
+ header.subpacketSize += GAMEMESSAGE_SIZE;
}
public SubPacket(SubPacket original, uint newTargetId)
@@ -158,6 +170,6 @@ namespace FFXIVClassic.Common
ConsoleOutputColor.DarkMagenta);
}
#endif
- }
+ }
}
}
\ No newline at end of file
diff --git a/FFXIVClassic Proxy Server/DataObjects/ZoneServer.cs b/FFXIVClassic Proxy Server/DataObjects/ZoneServer.cs
index eafe5dae..b3cf09e1 100644
--- a/FFXIVClassic Proxy Server/DataObjects/ZoneServer.cs
+++ b/FFXIVClassic Proxy Server/DataObjects/ZoneServer.cs
@@ -5,6 +5,7 @@ using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
+using FFXIVClassic.Common;
namespace FFXIVClassic_World_Server.DataObjects
{
@@ -12,6 +13,7 @@ namespace FFXIVClassic_World_Server.DataObjects
{
public readonly string zoneServerIp;
public readonly int zoneServerPort;
+ public readonly int[] ownedZoneIds;
public bool isConnected = false;
public Socket zoneServerConnection;
@@ -36,5 +38,21 @@ namespace FFXIVClassic_World_Server.DataObjects
catch (Exception e)
{ Program.Log.Error("Failed to connect"); return; }
}
+
+ public void SendPacket(SubPacket subpacket)
+ {
+ if (isConnected)
+ {
+ byte[] packetBytes = subpacket.GetBytes();
+
+ try
+ {
+ zoneServerConnection.Send(packetBytes);
+ }
+ catch (Exception e)
+ { Program.Log.Error("Weird case, socket was d/ced: {0}", e); }
+ }
+ }
+
}
}
diff --git a/FFXIVClassic Proxy Server/FFXIVClassic World Server.csproj b/FFXIVClassic Proxy Server/FFXIVClassic World Server.csproj
index 8ef6fac2..403e4f77 100644
--- a/FFXIVClassic Proxy Server/FFXIVClassic World Server.csproj
+++ b/FFXIVClassic Proxy Server/FFXIVClassic World Server.csproj
@@ -49,6 +49,10 @@
..\packages\NLog.4.3.5\lib\net45\NLog.dll
True
+
+ ..\packages\RabbitMQ.Client.4.0.0\lib\net451\RabbitMQ.Client.dll
+ True
+
diff --git a/FFXIVClassic Proxy Server/PacketProcessor.cs b/FFXIVClassic Proxy Server/PacketProcessor.cs
new file mode 100644
index 00000000..d50c10ed
--- /dev/null
+++ b/FFXIVClassic Proxy Server/PacketProcessor.cs
@@ -0,0 +1,133 @@
+using FFXIVClassic.Common;
+using FFXIVClassic_World_Server.Packets.Send.Login;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace FFXIVClassic_World_Server
+{
+ class PacketProcessor
+ {
+ /*
+ Session Creation:
+
+ Get 0x1 from server
+ Send 0x7
+ Send 0x2
+
+ Zone Change:
+
+ Send 0x7
+ Get 0x8 - Wait??
+ Send 0x2
+ */
+
+
+ Server mServer;
+ List mConnections;
+
+ public PacketProcessor(Server server)
+ {
+ mServer = server;
+ }
+
+ public void ProcessPacket(ClientConnection client, BasePacket packet)
+ {
+ //if (packet.header.isCompressed == 0x01)
+ // BasePacket.DecryptPacket(client.blowfish, ref packet);
+
+ List subPackets = packet.GetSubpackets();
+ foreach (SubPacket subpacket in subPackets)
+ {
+ //Initial Connect Packet, Create session
+ if (subpacket.header.type == 0x01)
+ {
+ packet.DebugPrintPacket();
+ byte[] reply1Data = {
+ 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFD, 0xFF, 0xFF,
+ 0xE5, 0x6E, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x0
+ };
+
+ byte[] reply2Data = {
+ 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x2B, 0x5F, 0x26,
+ 0x66, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xAF, 0x2B, 0x38, 0x2B, 0x5F, 0x26, 0xB8, 0x8D, 0xF0, 0x2B,
+ 0xC8, 0xFD, 0x85, 0xFE, 0xA8, 0x7C, 0x5B, 0x09, 0x38, 0x2B, 0x5F, 0x26, 0xC8, 0xD6, 0xAF, 0x2B,
+ 0xB8, 0x8D, 0xF0, 0x2B, 0x88, 0xAF, 0x5E, 0x26
+ };
+
+ BasePacket reply1 = new BasePacket(reply1Data);
+ BasePacket reply2 = new BasePacket(reply2Data);
+
+ //Write Timestamp into Reply1
+ using (MemoryStream mem = new MemoryStream(reply1.data))
+ {
+ using (BinaryWriter binReader = new BinaryWriter(mem))
+ {
+ binReader.BaseStream.Seek(0x14, SeekOrigin.Begin);
+ binReader.Write((UInt32)Utils.UnixTimeStampUTC());
+ }
+ }
+
+ //Read in Actor Id that owns this connection
+ uint actorID = 0;
+ using (MemoryStream mem = new MemoryStream(packet.data))
+ {
+ using (BinaryReader binReader = new BinaryReader(mem))
+ {
+ try
+ {
+ byte[] readIn = new byte[12];
+ binReader.BaseStream.Seek(0x14, SeekOrigin.Begin);
+ binReader.Read(readIn, 0, 12);
+ actorID = UInt32.Parse(Encoding.ASCII.GetString(readIn));
+ }
+ catch (Exception)
+ { }
+ }
+ }
+
+ mServer.AddSession(actorID);
+
+ if (packet.header.connectionType == BasePacket.TYPE_ZONE)
+ Program.Log.Info("Got {0} connection for ActorID {1} @ {2}.", "zone", actorID, client.GetAddress());
+ else if (packet.header.connectionType == BasePacket.TYPE_CHAT)
+ Program.Log.Info("Got {0} connection for ActorID {1} @ {2}.", "chat", actorID, client.GetAddress());
+
+ break;
+ }
+ //Ping from World Server
+ else if (subpacket.header.type == 0x07)
+ {
+ SubPacket init = Login0x7ResponsePacket.BuildPacket(0x50);
+ client.QueuePacket(BasePacket.CreatePacket(init, true, false));
+ }
+ //Zoning Related
+ else if (subpacket.header.type == 0x08)
+ {
+ //Response, client's current [actorID][time]
+ //BasePacket init = Login0x7ResponsePacket.BuildPacket(BitConverter.ToUInt32(packet.data, 0x10), Utils.UnixTimeStampUTC(), 0x07);
+ //client.QueuePacket(init);
+ packet.DebugPrintPacket();
+ }
+ //Game Message
+ else if (subpacket.header.type == 0x03)
+ {
+ //Send to the correct zone server
+ uint targetSession = subpacket.header.targetId;
+
+ if (mServer.GetSession(targetSession).routing1 != null)
+ mServer.GetSession(targetSession).routing1.SendPacket(subpacket);
+
+ if (mServer.GetSession(targetSession).routing2 != null)
+ mServer.GetSession(targetSession).routing2.SendPacket(subpacket);
+ }
+ else
+ packet.DebugPrintPacket();
+ }
+ }
+
+ }
+}
diff --git a/FFXIVClassic Proxy Server/Packets/Send/0x7ResponsePacket.cs b/FFXIVClassic Proxy Server/Packets/Send/0x7ResponsePacket.cs
new file mode 100644
index 00000000..8d5a92df
--- /dev/null
+++ b/FFXIVClassic Proxy Server/Packets/Send/0x7ResponsePacket.cs
@@ -0,0 +1,31 @@
+using FFXIVClassic.Common;
+using System;
+using System.IO;
+
+namespace FFXIVClassic_World_Server.Packets.Send.Login
+{
+ class Login0x7ResponsePacket
+ {
+ public static SubPacket BuildPacket(uint actorID)
+ {
+ byte[] data = new byte[0x18];
+
+ using (MemoryStream mem = new MemoryStream(data))
+ {
+ using (BinaryWriter binWriter = new BinaryWriter(mem))
+ {
+ try
+ {
+ binWriter.Write((UInt32)actorID);
+ binWriter.Write((UInt32)type);
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ return BasePacket.CreatePacket(data, false, false);
+ }
+ }
+}
diff --git a/FFXIVClassic Proxy Server/Server.cs b/FFXIVClassic Proxy Server/Server.cs
index d02d8312..a24606f0 100644
--- a/FFXIVClassic Proxy Server/Server.cs
+++ b/FFXIVClassic Proxy Server/Server.cs
@@ -21,7 +21,8 @@ namespace FFXIVClassic_World_Server
WorldManager worldManager;
private List mConnectionList = new List();
- private Dictionary mSessionList = new Dictionary();
+ private Dictionary mZoneSessionList = new Dictionary();
+ private Dictionary mChatSessionList = new Dictionary();
public Server()
{
@@ -120,7 +121,36 @@ namespace FFXIVClassic_World_Server
}
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
}
- }
+ }
+
+ public void AddSession(uint id)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void RemoveSession(uint id)
+ {
+ if (mChatSessionList.ContainsKey(id)) {
+ mChatSessionList[id].clientSocket.Disconnect();
+ mConnectionList.Remove(mChatSessionList[id].clientSocket);
+ mChatSessionList.Remove(id);
+ }
+
+ if (mZoneSessionList.ContainsKey(id))
+ {
+ mZoneSessionList[id].clientSocket.Disconnect();
+ mConnectionList.Remove(mZoneSessionList[id].clientSocket);
+ mZoneSessionList.Remove(id);
+ }
+ }
+
+ public Session GetSession(uint targetSession)
+ {
+ if (mZoneSessionList.ContainsKey(targetSession))
+ return mZoneSessionList[targetSession];
+ else
+ return null;
+ }
///
/// Receive Callback. Reads in incoming data, converting them to base packets. Base packets are sent to be parsed. If not enough data at the end to build a basepacket, move to the beginning and prepend.
@@ -202,7 +232,7 @@ namespace FFXIVClassic_World_Server
}
}
}
- }
+ }
///
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
@@ -241,6 +271,11 @@ namespace FFXIVClassic_World_Server
#endregion
+
+ public WorldManager GetWorldManager()
+ {
+ return worldManager;
+ }
}
}
diff --git a/FFXIVClassic Proxy Server/WorldMaster.cs b/FFXIVClassic Proxy Server/WorldMaster.cs
index 40c47d60..b5f2ce12 100644
--- a/FFXIVClassic Proxy Server/WorldMaster.cs
+++ b/FFXIVClassic Proxy Server/WorldMaster.cs
@@ -88,10 +88,10 @@ namespace FFXIVClassic_World_Server
public void DoZoneServerChange(Session session, uint zoneEntrance)
{
/*
- ->Tell old server to save session info and remove
+ ->Tell old server to save session info and remove session. Start zone packets.
->Update the position to zoneEntrance
->Update routing
- ->Tell new server to load session info and add
+ ->Tell new server to load session info and add session. Send end zone packets.
*/
}