diff --git a/FFXIVClassic Map Server/CommandProcessor.cs b/FFXIVClassic Map Server/CommandProcessor.cs index ea3d8cc6..16792d81 100644 --- a/FFXIVClassic Map Server/CommandProcessor.cs +++ b/FFXIVClassic Map Server/CommandProcessor.cs @@ -8,6 +8,7 @@ using System.IO; using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send; using FFXIVClassic_Map_Server.lua; +using FFXIVClassic_Map_Server.Actors; namespace FFXIVClassic_Map_Server { @@ -74,7 +75,9 @@ namespace FFXIVClassic_Map_Server if (cmd.Any()) { // if client isnt null, take player to be the player actor - var player = session.GetActor(); + Player player = null; + if (session != null) + player = session.GetActor(); if (cmd.Equals("help")) { diff --git a/FFXIVClassic Map Server/PacketProcessor.cs b/FFXIVClassic Map Server/PacketProcessor.cs index edb76410..6958c0bf 100644 --- a/FFXIVClassic Map Server/PacketProcessor.cs +++ b/FFXIVClassic Map Server/PacketProcessor.cs @@ -37,6 +37,18 @@ namespace FFXIVClassic_Map_Server //Normal Game Opcode switch (subpacket.gameMessage.opcode) { + //World Server - End Session + case 0x1000: + session.GetActor().CleanupAndSave(); + break; + //World Server - End Session and Zone + case 0x1001: + + session.GetActor().CleanupAndSave(); + break; + //World Server - Begin Session + case 0x1002: + break; //Ping case 0x0001: //subpacket.DebugPrintSubPacket(); @@ -86,7 +98,7 @@ namespace FFXIVClassic_Map_Server //Update Position case 0x00CA: //Update Position - //subpacket.DebugPrintSubPacket(); + subpacket.DebugPrintSubPacket(); UpdatePlayerPositionPacket posUpdate = new UpdatePlayerPositionPacket(subpacket.data); session.UpdatePlayerActorPosition(posUpdate.x, posUpdate.y, posUpdate.z, posUpdate.rot, posUpdate.moveState); session.GetActor().SendInstanceUpdate(); diff --git a/FFXIVClassic World Server/DataObjects/ZoneServer.cs b/FFXIVClassic World Server/DataObjects/ZoneServer.cs index e7371402..00896f2f 100644 --- a/FFXIVClassic World Server/DataObjects/ZoneServer.cs +++ b/FFXIVClassic World Server/DataObjects/ZoneServer.cs @@ -6,6 +6,7 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using FFXIVClassic.Common; +using FFXIVClassic_World_Server.Packets.WorldPackets.Send; namespace FFXIVClassic_World_Server.DataObjects { @@ -134,6 +135,15 @@ namespace FFXIVClassic_World_Server.DataObjects } } + public void SendGoodbye(Session session) + { + SendPacket(SessionEndPacket.BuildPacket(session)); + } + + public void SendSessionEnd(Session session, uint destinationZoneId, string destinationPrivateArea, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation) + { + SendPacket(SessionEndAndZonePacket.BuildPacket(session, destinationZoneId, destinationPrivateArea, spawnType, spawnX, spawnY, spawnZ, spawnRotation)); + } } } diff --git a/FFXIVClassic World Server/FFXIVClassic World Server.csproj b/FFXIVClassic World Server/FFXIVClassic World Server.csproj index a2b0cb76..7d4825ee 100644 --- a/FFXIVClassic World Server/FFXIVClassic World Server.csproj +++ b/FFXIVClassic World Server/FFXIVClassic World Server.csproj @@ -73,6 +73,9 @@ + + + diff --git a/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionBeginPacket.cs b/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionBeginPacket.cs new file mode 100644 index 00000000..686aceeb --- /dev/null +++ b/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionBeginPacket.cs @@ -0,0 +1,24 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.DataObjects; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.WorldPackets.Send +{ + class SessionBeginPacket + { + public const ushort OPCODE = 0x1000; + public const uint PACKET_SIZE = 0x24; + + public static SubPacket BuildPacket(Session session) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + return new SubPacket(true, OPCODE, 0, session.sessionId, data); + } + } +} diff --git a/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionEndPacket.cs b/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionEndPacket.cs new file mode 100644 index 00000000..fb384d8c --- /dev/null +++ b/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionEndPacket.cs @@ -0,0 +1,24 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.DataObjects; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.WorldPackets.Send +{ + class SessionEndPacket + { + public const ushort OPCODE = 0x1001; + public const uint PACKET_SIZE = 0x24; + + public static SubPacket BuildPacket(Session session) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + return new SubPacket(true, OPCODE, 0, session.sessionId, data); + } + } +} diff --git a/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionEndZonePacket.cs b/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionEndZonePacket.cs new file mode 100644 index 00000000..453737c1 --- /dev/null +++ b/FFXIVClassic World Server/Packets/WorldPackets/Send/SessionEndZonePacket.cs @@ -0,0 +1,44 @@ +using FFXIVClassic.Common; +using FFXIVClassic_World_Server.DataObjects; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_World_Server.Packets.WorldPackets.Send +{ + class SessionEndAndZonePacket + { + public const ushort OPCODE = 0x1002; + public const uint PACKET_SIZE = 0x48; + + public static SubPacket BuildPacket(Session session, uint destinationZoneId, string destinationPrivateArea, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryWriter binWriter = new BinaryWriter(mem)) + { + try + { + binWriter.Write((UInt32)destinationZoneId); + binWriter.Write((UInt32)destinationZoneId); + binWriter.Write((UInt32)spawnType); + binWriter.Write((Single)spawnX); + binWriter.Write((Single)spawnY); + binWriter.Write((Single)spawnZ); + binWriter.Write((Single)spawnRotation); + + } + catch (Exception) + { } + } + } + + return new SubPacket(true, OPCODE, 0, session.sessionId, data); + } + } +} diff --git a/FFXIVClassic World Server/Server.cs b/FFXIVClassic World Server/Server.cs index c286c6aa..b88ab3d7 100644 --- a/FFXIVClassic World Server/Server.cs +++ b/FFXIVClassic World Server/Server.cs @@ -40,6 +40,7 @@ namespace FFXIVClassic_World_Server mPacketProcessor = new PacketProcessor(this); mWorldManager = new WorldManager(this); mWorldManager.LoadZoneServerList(); + mWorldManager.LoadZoneEntranceList(); mWorldManager.ConnectToZoneServers(); IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT)); @@ -135,10 +136,9 @@ namespace FFXIVClassic_World_Server } public void OnReceiveSubPacketFromZone(ZoneServer zoneServer, SubPacket subpacket) - { - //subpacket.DebugPrintSubPacket(); + { uint sessionId = subpacket.header.targetId; - + if (mZoneSessionList.ContainsKey(sessionId)) { ClientConnection conn = mZoneSessionList[sessionId].clientConnection; diff --git a/FFXIVClassic World Server/WorldMaster.cs b/FFXIVClassic World Server/WorldMaster.cs index 26541d1e..797f043a 100644 --- a/FFXIVClassic World Server/WorldMaster.cs +++ b/FFXIVClassic World Server/WorldMaster.cs @@ -15,6 +15,7 @@ namespace FFXIVClassic_World_Server { private Server mServer; public Dictionary mZoneServerList; + private Dictionary zoneEntranceList; public WorldManager(Server server) { @@ -65,6 +66,57 @@ namespace FFXIVClassic_World_Server } } + + public void LoadZoneEntranceList() + { + zoneEntranceList = new Dictionary(); + int count = 0; + 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(); + + string query = @" + SELECT + id, + zoneId, + spawnType, + spawnX, + spawnY, + spawnZ, + spawnRotation, + privateAreaName + FROM server_zones_spawnlocations"; + + MySqlCommand cmd = new MySqlCommand(query, conn); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + uint id = reader.GetUInt32(0); + string privArea = null; + + if (!reader.IsDBNull(7)) + privArea = reader.GetString(7); + + ZoneEntrance entance = new ZoneEntrance(reader.GetUInt32(1), privArea, reader.GetByte(2), reader.GetFloat(3), reader.GetFloat(4), reader.GetFloat(5), reader.GetFloat(6)); + zoneEntranceList[id] = entance; + count++; + } + } + } + catch (MySqlException e) + { Console.WriteLine(e); } + finally + { + conn.Dispose(); + } + } + + Program.Log.Info(String.Format("Loaded {0} zone spawn locations.", count)); + } public void ConnectToZoneServers() { @@ -87,23 +139,20 @@ namespace FFXIVClassic_World_Server //Moves actor to new zone, and sends packets to spawn at the given zone entrance public void DoZoneServerChange(Session session, uint zoneEntrance) { - /* - ->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 session. Send end zone packets. - */ + if (!zoneEntranceList.ContainsKey(zoneEntrance)) + { + Program.Log.Error("Given zone entrance was not found: " + zoneEntrance); + return; + } + + ZoneEntrance ze = zoneEntranceList[zoneEntrance]; + DoZoneServerChange(session, ze.zoneId, ze.privateAreaName, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation); } //Moves actor to new zone, and sends packets to spawn at the given coords. public void DoZoneServerChange(Session session, uint destinationZoneId, string destinationPrivateArea, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation) { - /* - ->Tell old server to save session info and remove - ->Update the position to params - ->Update routing - ->Tell new server to load session info and add - */ + session.routing1.SendSessionEnd(session, destinationZoneId, destinationPrivateArea, spawnType, spawnX, spawnY, spawnZ, spawnRotation); } //Login Zone In