Built subpackets to let the zone servers talk to the world server. Implemented cross-server zoning but the E2 packet or something isn't being sent.

This commit is contained in:
Filip Maj 2016-12-03 12:19:59 -05:00
parent 58fda93b45
commit e30831fdc5
27 changed files with 674 additions and 113 deletions

View File

@ -258,6 +258,8 @@ namespace FFXIVClassic_Map_Server
positionY = @y, positionY = @y,
positionZ = @z, positionZ = @z,
rotation = @rot, rotation = @rot,
destinationZoneId = @destZone,
destinationSpawnType = @destSpawn,
currentZoneId = @zoneId currentZoneId = @zoneId
WHERE id = @charaId WHERE id = @charaId
"; ";
@ -269,6 +271,8 @@ namespace FFXIVClassic_Map_Server
cmd.Parameters.AddWithValue("@z", player.positionZ); cmd.Parameters.AddWithValue("@z", player.positionZ);
cmd.Parameters.AddWithValue("@rot", player.rotation); cmd.Parameters.AddWithValue("@rot", player.rotation);
cmd.Parameters.AddWithValue("@zoneId", player.zoneId); cmd.Parameters.AddWithValue("@zoneId", player.zoneId);
cmd.Parameters.AddWithValue("@destZone", player.destinationZone);
cmd.Parameters.AddWithValue("@destSpawn", player.destinationSpawnType);
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
@ -402,7 +406,9 @@ namespace FFXIVClassic_Map_Server
tribe, tribe,
restBonus, restBonus,
achievementPoints, achievementPoints,
playTime playTime,
destinationZoneId,
destinationSpawnType
FROM characters WHERE id = @charId"; FROM characters WHERE id = @charId";
cmd = new MySqlCommand(query, conn); cmd = new MySqlCommand(query, conn);
@ -420,7 +426,6 @@ namespace FFXIVClassic_Map_Server
player.currentMainState = reader.GetUInt16(5); player.currentMainState = reader.GetUInt16(5);
player.zoneId = reader.GetUInt32(6); player.zoneId = reader.GetUInt32(6);
player.isZoning = true; player.isZoning = true;
player.zone = Server.GetWorldManager().GetZone(player.zoneId);
player.gcCurrent = reader.GetByte(7); player.gcCurrent = reader.GetByte(7);
player.gcRankLimsa = reader.GetByte(8); player.gcRankLimsa = reader.GetByte(8);
player.gcRankGridania = reader.GetByte(9); player.gcRankGridania = reader.GetByte(9);
@ -434,6 +439,13 @@ namespace FFXIVClassic_Map_Server
player.playerWork.restBonusExpRate = reader.GetInt32(17); player.playerWork.restBonusExpRate = reader.GetInt32(17);
player.achievementPoints = reader.GetUInt32(18); player.achievementPoints = reader.GetUInt32(18);
player.playTime = reader.GetUInt32(19); player.playTime = reader.GetUInt32(19);
player.destinationZone = reader.GetUInt32("destinationZoneId");
player.destinationSpawnType = reader.GetByte("destinationSpawnType");
if (player.destinationZone != 0)
player.zoneId = player.destinationZone;
player.zone = Server.GetWorldManager().GetZone(player.zoneId);
} }
} }

View File

@ -256,6 +256,10 @@
<Compile Include="packets\send\_0xE2Packet.cs" /> <Compile Include="packets\send\_0xE2Packet.cs" />
<Compile Include="packets\receive\PingPacket.cs" /> <Compile Include="packets\receive\PingPacket.cs" />
<Compile Include="packets\receive\UpdatePlayerPositionPacket.cs" /> <Compile Include="packets\receive\UpdatePlayerPositionPacket.cs" />
<Compile Include="packets\WorldPackets\Receive\SessionEndPacket.cs" />
<Compile Include="packets\WorldPackets\Receive\SessionBeginPacket.cs" />
<Compile Include="packets\WorldPackets\Send\SessionBeginConfirmPacket.cs" />
<Compile Include="packets\WorldPackets\Send\SessionEndConfirmPacket.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="lua\LuaUtils.cs" /> <Compile Include="lua\LuaUtils.cs" />
@ -280,6 +284,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</None> </None>
<None Include="packages.config" /> <None Include="packages.config" />
<Compile Include="packets\WorldPackets\Send\WorldRequestZoneChangePacket.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">

View File

@ -18,6 +18,8 @@ using FFXIVClassic_Map_Server.packets.send.recruitment;
using FFXIVClassic_Map_Server.packets.receive.events; using FFXIVClassic_Map_Server.packets.receive.events;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.packets.WorldPackets.Send;
using FFXIVClassic_Map_Server.packets.WorldPackets.Receive;
namespace FFXIVClassic_Map_Server namespace FFXIVClassic_Map_Server
{ {
@ -34,20 +36,33 @@ namespace FFXIVClassic_Map_Server
{ {
Session session = mServer.GetSession(subpacket.header.targetId); Session session = mServer.GetSession(subpacket.header.targetId);
if (session == null && subpacket.gameMessage.opcode != 0x1000)
return;
//Normal Game Opcode //Normal Game Opcode
switch (subpacket.gameMessage.opcode) switch (subpacket.gameMessage.opcode)
{ {
//World Server - End Session //World Server - Session Begin
case 0x1000: case 0x1000:
session.GetActor().CleanupAndSave(); subpacket.DebugPrintSubPacket();
break; session = mServer.AddSession(subpacket.header.targetId);
//World Server - End Session and Zone
case 0x1001:
session.GetActor().CleanupAndSave(); if (session.GetActor().destinationZone != 0)
Server.GetWorldManager().DoZoneIn(session.GetActor(), false, session.GetActor().destinationSpawnType);
client.FlushQueuedSendPackets();
break; break;
//World Server - Begin Session //World Server - Session End
case 0x1002: case 0x1001:
SessionEndPacket endSessionPacket = new SessionEndPacket(subpacket.data);
if (endSessionPacket.destinationZoneId == 0)
session.GetActor().CleanupAndSave();
else
session.GetActor().CleanupAndSave(endSessionPacket.destinationZoneId, endSessionPacket.destinationSpawnType, endSessionPacket.destinationX, endSessionPacket.destinationY, endSessionPacket.destinationZ, endSessionPacket.destinationRot);
client.QueuePacket(SessionEndConfirmPacket.BuildPacket(session, endSessionPacket.destinationZoneId), true, false);
client.FlushQueuedSendPackets();
break; break;
//Ping //Ping
case 0x0001: case 0x0001:
@ -60,12 +75,12 @@ namespace FFXIVClassic_Map_Server
case 0x0002: case 0x0002:
subpacket.DebugPrintSubPacket(); subpacket.DebugPrintSubPacket();
session = mServer.AddSession(subpacket.header.targetId); session = mServer.AddSession(subpacket.header.targetId);
client.QueuePacket(_0x2Packet.BuildPacket(session.id), true, false); client.QueuePacket(_0x2Packet.BuildPacket(session.id), true, false);
Server.GetWorldManager().DoLogin(session.GetActor()); LuaEngine.OnBeginLogin(session.GetActor());
Server.GetWorldManager().DoZoneIn(session.GetActor(), true, 0x1);
LuaEngine.OnLogin(session.GetActor());
client.FlushQueuedSendPackets(); client.FlushQueuedSendPackets();
@ -98,7 +113,6 @@ namespace FFXIVClassic_Map_Server
//Update Position //Update Position
case 0x00CA: case 0x00CA:
//Update Position //Update Position
subpacket.DebugPrintSubPacket();
UpdatePlayerPositionPacket posUpdate = new UpdatePlayerPositionPacket(subpacket.data); UpdatePlayerPositionPacket posUpdate = new UpdatePlayerPositionPacket(subpacket.data);
session.UpdatePlayerActorPosition(posUpdate.x, posUpdate.y, posUpdate.z, posUpdate.rot, posUpdate.moveState); session.UpdatePlayerActorPosition(posUpdate.x, posUpdate.y, posUpdate.z, posUpdate.rot, posUpdate.moveState);
session.GetActor().SendInstanceUpdate(); session.GetActor().SendInstanceUpdate();

View File

@ -95,6 +95,9 @@ namespace FFXIVClassic_Map_Server
public Session AddSession(uint id) public Session AddSession(uint id)
{ {
if (mSessionList.ContainsKey(id))
return mSessionList[id];
Session session = new Session(id); Session session = new Session(id);
mSessionList.Add(id, session); mSessionList.Add(id, session);
return session; return session;
@ -104,7 +107,6 @@ namespace FFXIVClassic_Map_Server
{ {
if (mSessionList.ContainsKey(id)) if (mSessionList.ContainsKey(id))
{ {
mSessionList[id].GetActor().CleanupAndSave();
mSessionList.Remove(id); mSessionList.Remove(id);
} }
} }
@ -244,6 +246,11 @@ namespace FFXIVClassic_Map_Server
#endregion #endregion
public static ZoneConnection GetWorldConnection()
{
return mWorldConnection;
}
public static Server GetServer() public static Server GetServer()
{ {
return mSelf; return mSelf;
@ -254,11 +261,6 @@ namespace FFXIVClassic_Map_Server
return mCommandProcessor; return mCommandProcessor;
} }
public static ZoneConnection GetWorldConnection()
{
return mWorldConnection;
}
public static WorldManager GetWorldManager() public static WorldManager GetWorldManager()
{ {
return mWorldManager; return mWorldManager;

View File

@ -384,9 +384,8 @@ namespace FFXIVClassic_Map_Server
oldZone.AddActorToZone(player); oldZone.AddActorToZone(player);
} }
var message = "WorldManager.DoZoneChange: unable to change areas, new area is not valid."; Program.Log.Debug("Request to change to zone not on this server by: {0}.", player.customDisplayName);
player.SendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM, "[Debug]", message); RequestWorldServerZoneChange(player, destinationZoneId, spawnType, spawnX, spawnY, spawnZ, spawnRotation);
Program.Log.Debug(message);
return; return;
} }
@ -450,8 +449,8 @@ namespace FFXIVClassic_Map_Server
} }
} }
//Login Zone In //Session started, zone into world
public void DoLogin(Player player) public void DoZoneIn(Player player, bool isLogin, ushort spawnType)
{ {
//Add player to new zone and update //Add player to new zone and update
Zone zone = GetZone(player.zoneId); Zone zone = GetZone(player.zoneId);
@ -463,14 +462,18 @@ namespace FFXIVClassic_Map_Server
//Set the current zone and add player //Set the current zone and add player
player.zone = zone; player.zone = zone;
LuaEngine.OnBeginLogin(player);
zone.AddActorToZone(player); zone.AddActorToZone(player);
//Send packets //Send packets
player.SendZoneInPackets(this, 0x1); if (!isLogin)
{
player.playerSession.QueuePacket(DeleteAllActorsPacket.BuildPacket(player.actorId), true, false);
player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.actorId, 0x0), true, false);
player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.actorId, 0x0), true, false);
}
player.SendZoneInPackets(this, spawnType);
LuaEngine.OnLogin(player);
LuaEngine.OnZoneIn(player); LuaEngine.OnZoneIn(player);
} }
@ -485,6 +488,12 @@ namespace FFXIVClassic_Map_Server
} }
private void RequestWorldServerZoneChange(Player player, uint destinationZoneId, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation)
{
ZoneConnection zc = Server.GetWorldConnection();
zc.RequestZoneChange(player.playerSession.id, destinationZoneId, spawnType, spawnX, spawnY, spawnZ, spawnRotation);
}
public Player GetPCInWorld(string name) public Player GetPCInWorld(string name)
{ {
foreach (Zone zone in zoneList.Values) foreach (Zone zone in zoneList.Values)

View File

@ -70,7 +70,7 @@ namespace FFXIVClassic_Map_Server.Actors
return SetActorSpeedPacket.BuildPacket(actorId, playerActorId); return SetActorSpeedPacket.BuildPacket(actorId, playerActorId);
} }
public SubPacket CreateSpawnPositonPacket(uint playerActorId, uint spawnType) public SubPacket CreateSpawnPositonPacket(uint playerActorId, ushort spawnType)
{ {
SubPacket spawnPacket; SubPacket spawnPacket;
if (!spawnedFirstTime && playerActorId == actorId) if (!spawnedFirstTime && playerActorId == actorId)
@ -91,7 +91,7 @@ namespace FFXIVClassic_Map_Server.Actors
return spawnPacket; return spawnPacket;
} }
public SubPacket CreateSpawnTeleportPacket(uint playerActorId, uint spawnType) public SubPacket CreateSpawnTeleportPacket(uint playerActorId, ushort spawnType)
{ {
SubPacket spawnPacket; SubPacket spawnPacket;
@ -223,7 +223,7 @@ namespace FFXIVClassic_Map_Server.Actors
return GetSpawnPackets(playerActorId, 0x1); return GetSpawnPackets(playerActorId, 0x1);
} }
public virtual BasePacket GetSpawnPackets(uint playerActorId, uint spawnType) public virtual BasePacket GetSpawnPackets(uint playerActorId, ushort spawnType)
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId, 8)); subpackets.Add(CreateAddActorPacket(playerActorId, 8));

View File

@ -116,7 +116,7 @@ namespace FFXIVClassic_Map_Server.Actors
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams); return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
} }
public override BasePacket GetSpawnPackets(uint playerActorId, uint spawnType) public override BasePacket GetSpawnPackets(uint playerActorId, ushort spawnType)
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId)); subpackets.Add(CreateAddActorPacket(playerActorId));

View File

@ -84,6 +84,8 @@ namespace FFXIVClassic_Map_Server.Actors
public Coroutine currentEventRunning; public Coroutine currentEventRunning;
//Player Info //Player Info
public uint destinationZone;
public ushort destinationSpawnType;
public uint[] timers = new uint[20]; public uint[] timers = new uint[20];
public ushort currentJob; public ushort currentJob;
public uint currentTitle; public uint currentTitle;
@ -259,7 +261,7 @@ namespace FFXIVClassic_Map_Server.Actors
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams); return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
} }
public override BasePacket GetSpawnPackets(uint playerActorId, uint spawnType) public override BasePacket GetSpawnPackets(uint playerActorId, ushort spawnType)
{ {
List<SubPacket> subpackets = new List<SubPacket>(); List<SubPacket> subpackets = new List<SubPacket>();
subpackets.Add(CreateAddActorPacket(playerActorId, 8)); subpackets.Add(CreateAddActorPacket(playerActorId, 8));
@ -647,13 +649,46 @@ namespace FFXIVClassic_Map_Server.Actors
public void CleanupAndSave() public void CleanupAndSave()
{ {
playerSession.LockUpdates(true);
//Remove actor from zone and main server list //Remove actor from zone and main server list
zone.RemoveActorFromZone(this); zone.RemoveActorFromZone(this);
//Set Destination to 0
this.destinationZone = 0;
this.destinationSpawnType = 0;
//Save Player //Save Player
Database.SavePlayerPlayTime(this); Database.SavePlayerPlayTime(this);
Database.SavePlayerPosition(this); Database.SavePlayerPosition(this);
Program.Log.Info("{0} has been logged out and saved.", this.customDisplayName);
Server.GetServer().RemoveSession(playerSession.id);
Program.Log.Info("{0} has been removed from the session list.", this.customDisplayName);
}
public void CleanupAndSave(uint destinationZone, ushort spawnType, float destinationX, float destinationY, float destinationZ, float destinationRot)
{
playerSession.LockUpdates(true);
//Remove actor from zone and main server list
zone.RemoveActorFromZone(this);
//Set destination
this.destinationZone = destinationZone;
this.destinationSpawnType = spawnType;
this.positionX = destinationX;
this.positionY = destinationY;
this.positionZ = destinationZ;
this.rotation = destinationRot;
//Save Player
Database.SavePlayerPlayTime(this);
Database.SavePlayerPosition(this);
Server.GetServer().RemoveSession(playerSession.id);
Program.Log.Info("{0} has been removed from the session list.", this.customDisplayName);
} }
public Area GetZone() public Area GetZone()

View File

@ -20,6 +20,8 @@ namespace FFXIVClassic_Map_Server.dataobjects
public uint languageCode = 1; public uint languageCode = 1;
private uint lastPingPacket = Utils.UnixTimeStampUTC(); private uint lastPingPacket = Utils.UnixTimeStampUTC();
public bool isUpdatesLocked = false;
public string errorMessage = ""; public string errorMessage = "";
public Session(uint sessionId) public Session(uint sessionId)
@ -63,6 +65,9 @@ namespace FFXIVClassic_Map_Server.dataobjects
public void UpdatePlayerActorPosition(float x, float y, float z, float rot, ushort moveState) public void UpdatePlayerActorPosition(float x, float y, float z, float rot, ushort moveState)
{ {
if (isUpdatesLocked)
return;
playerActor.oldPositionX = playerActor.positionX; playerActor.oldPositionX = playerActor.positionX;
playerActor.oldPositionY = playerActor.positionY; playerActor.oldPositionY = playerActor.positionY;
playerActor.oldPositionZ = playerActor.positionZ; playerActor.oldPositionZ = playerActor.positionZ;
@ -80,6 +85,9 @@ namespace FFXIVClassic_Map_Server.dataobjects
public void UpdateInstance(List<Actor> list) public void UpdateInstance(List<Actor> list)
{ {
if (isUpdatesLocked)
return;
List<BasePacket> basePackets = new List<BasePacket>(); List<BasePacket> basePackets = new List<BasePacket>();
List<SubPacket> RemoveActorSubpackets = new List<SubPacket>(); List<SubPacket> RemoveActorSubpackets = new List<SubPacket>();
List<SubPacket> posUpdateSubpackets = new List<SubPacket>(); List<SubPacket> posUpdateSubpackets = new List<SubPacket>();
@ -132,5 +140,10 @@ namespace FFXIVClassic_Map_Server.dataobjects
actorInstanceList.Clear(); actorInstanceList.Clear();
} }
public void LockUpdates(bool f)
{
isUpdatesLocked = f;
}
} }
} }

View File

@ -5,6 +5,7 @@ using FFXIVClassic.Common;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Net; using System.Net;
using System.Collections.Generic; using System.Collections.Generic;
using FFXIVClassic_Map_Server.packets.WorldPackets.Send;
namespace FFXIVClassic_Map_Server.dataobjects namespace FFXIVClassic_Map_Server.dataobjects
{ {
@ -63,5 +64,11 @@ namespace FFXIVClassic_Map_Server.dataobjects
if (socket.Connected) if (socket.Connected)
socket.Disconnect(false); socket.Disconnect(false);
} }
public void RequestZoneChange(uint sessionId, uint destinationZoneId, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation)
{
WorldRequestZoneChangePacket.BuildPacket(sessionId, destinationZoneId, spawnType, spawnX, spawnY, spawnZ, spawnRotation).DebugPrintSubPacket();
QueuePacket(WorldRequestZoneChangePacket.BuildPacket(sessionId, destinationZoneId, spawnType, spawnX, spawnY, spawnZ, spawnRotation), true, false);
}
} }
} }

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Receive
{
class SessionBeginPacket
{
public bool invalidPacket = false;
public SessionBeginPacket(byte[] data)
{
}
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Receive
{
class SessionEndPacket
{
public uint destinationZoneId;
public ushort destinationSpawnType;
public float destinationX;
public float destinationY;
public float destinationZ;
public float destinationRot;
public bool invalidPacket = false;
public SessionEndPacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
destinationZoneId = binReader.ReadUInt32();
destinationSpawnType = binReader.ReadUInt16();
destinationX = binReader.ReadSingle();
destinationY = binReader.ReadSingle();
destinationZ = binReader.ReadSingle();
destinationRot = binReader.ReadSingle();
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -0,0 +1,27 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.IO;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send
{
class SessionBeginConfirmPacket
{
public const ushort OPCODE = 0x1000;
public const uint PACKET_SIZE = 0x28;
public static SubPacket BuildPacket(Session session, ushort errorCode = 0)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)session.id);
binWriter.Write((UInt16)errorCode);
}
}
return new SubPacket(true, OPCODE, 0, session.id, data);
}
}
}

View File

@ -0,0 +1,28 @@
using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.dataobjects;
using System;
using System.IO;
namespace FFXIVClassic_Map_Server.packets.WorldPackets.Send
{
class SessionEndConfirmPacket
{
public const ushort OPCODE = 0x1001;
public const uint PACKET_SIZE = 0x30;
public static SubPacket BuildPacket(Session session, uint destinationZone, ushort errorCode = 0)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
binWriter.Write((UInt32)session.id);
binWriter.Write((UInt16)errorCode);
binWriter.Write((UInt32)destinationZone);
}
}
return new SubPacket(true, OPCODE, 0, session.id, data);
}
}
}

View File

@ -0,0 +1,37 @@
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.WorldPackets.Send
{
class WorldRequestZoneChangePacket
{
public const ushort OPCODE = 0x1002;
public const uint PACKET_SIZE = 0x048;
public static SubPacket BuildPacket(uint sessionId, uint destinationZoneId, 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))
{
binWriter.Write((UInt32)sessionId);
binWriter.Write((UInt32)destinationZoneId);
binWriter.Write((UInt16)spawnType);
binWriter.Write((Single)spawnX);
binWriter.Write((Single)spawnY);
binWriter.Write((Single)spawnZ);
binWriter.Write((Single)spawnRotation);
}
}
return new SubPacket(OPCODE, sessionId, sessionId, data);
}
}
}

View File

@ -24,7 +24,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
public const float INNPOS_Z = 165.050003f; public const float INNPOS_Z = 165.050003f;
public const float INNPOS_ROT = -1.530000f; public const float INNPOS_ROT = -1.530000f;
public static SubPacket BuildPacket(uint sourceActorID, uint targetActorID, uint actorId, float x, float y, float z, float rotation, uint spawnType, bool isZoningPlayer) public static SubPacket BuildPacket(uint sourceActorID, uint targetActorID, uint actorId, float x, float y, float z, float rotation, ushort spawnType, bool isZoningPlayer)
{ {
byte[] data = new byte[PACKET_SIZE-0x20]; byte[] data = new byte[PACKET_SIZE-0x20];

View File

@ -14,17 +14,25 @@ namespace FFXIVClassic_World_Server.DataObjects
{ {
public readonly string zoneServerIp; public readonly string zoneServerIp;
public readonly int zoneServerPort; public readonly int zoneServerPort;
public readonly int[] ownedZoneIds; public readonly List<uint> ownedZoneIds;
public bool isConnected = false; public bool isConnected = false;
public Socket zoneServerConnection; public Socket zoneServerConnection;
private ClientConnection conn; private ClientConnection conn;
private byte[] buffer = new byte[0xFFFF]; private byte[] buffer = new byte[0xFFFF];
public ZoneServer(string ip, int port) public ZoneServer(string ip, int port, uint firstId)
{ {
zoneServerIp = ip; zoneServerIp = ip;
zoneServerPort = port; zoneServerPort = port;
ownedZoneIds = new List<uint>();
ownedZoneIds.Add(firstId);
}
public void AddLoadedZone(uint id)
{
ownedZoneIds.Add(id);
} }
public void Connect() public void Connect()
@ -135,14 +143,19 @@ namespace FFXIVClassic_World_Server.DataObjects
} }
} }
public void SendGoodbye(Session session) public void SendSessionStart(Session session)
{
SendPacket(SessionBeginPacket.BuildPacket(session));
}
public void SendSessionEnd(Session session)
{ {
SendPacket(SessionEndPacket.BuildPacket(session)); SendPacket(SessionEndPacket.BuildPacket(session));
} }
public void SendSessionEnd(Session session, uint destinationZoneId, string destinationPrivateArea, byte spawnType, float spawnX, float spawnY, float spawnZ, float spawnRotation) 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)); SendPacket(SessionEndPacket.BuildPacket(session, destinationZoneId, destinationPrivateArea, spawnType, spawnX, spawnY, spawnZ, spawnRotation));
} }
} }

View File

@ -0,0 +1,53 @@
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFXIVClassic_World_Server
{
class Database
{
public static uint GetCurrentZoneForSession(uint charId)
{
uint currentZone = 0;
uint destinationZone = 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();
MySqlCommand cmd = new MySqlCommand("SELECT currentZoneId, destinationZoneId FROM characters WHERE id = @charaId", conn);
cmd.Parameters.AddWithValue("@charaId", charId);
using (MySqlDataReader Reader = cmd.ExecuteReader())
{
while (Reader.Read())
{
currentZone = Reader.GetUInt32("currentZoneId");
destinationZone = Reader.GetUInt32("destinationZoneId");
}
}
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
if (currentZone == 0 && destinationZone != 0)
return destinationZone;
if (currentZone != 0 && destinationZone == 0)
return currentZone;
else
{
return 0;
}
}
}
}

View File

@ -65,6 +65,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ConfigConstants.cs" /> <Compile Include="ConfigConstants.cs" />
<Compile Include="Database.cs" />
<Compile Include="DataObjects\ClientConnection.cs" /> <Compile Include="DataObjects\ClientConnection.cs" />
<Compile Include="DataObjects\ZoneServer.cs" /> <Compile Include="DataObjects\ZoneServer.cs" />
<Compile Include="DataObjects\Session.cs" /> <Compile Include="DataObjects\Session.cs" />
@ -73,8 +74,10 @@
<Compile Include="Packets\Send\_0x2Packet.cs" /> <Compile Include="Packets\Send\_0x2Packet.cs" />
<Compile Include="Packets\Send\_0x7Packet.cs" /> <Compile Include="Packets\Send\_0x7Packet.cs" />
<Compile Include="Packets\Send\_0x8PingPacket.cs" /> <Compile Include="Packets\Send\_0x8PingPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\SessionBeginConfirmPacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\WorldRequestZoneChangePacket.cs" />
<Compile Include="Packets\WorldPackets\Receive\SessionEndConfirmPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\SessionBeginPacket.cs" /> <Compile Include="Packets\WorldPackets\Send\SessionBeginPacket.cs" />
<Compile Include="Packets\WorldPackets\Send\SessionEndZonePacket.cs" />
<Compile Include="Packets\WorldPackets\Send\SessionEndPacket.cs" /> <Compile Include="Packets\WorldPackets\Send\SessionEndPacket.cs" />
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -3,6 +3,8 @@ using FFXIVClassic_World_Server.DataObjects;
using FFXIVClassic_World_Server.Packets.Receive; using FFXIVClassic_World_Server.Packets.Receive;
using FFXIVClassic_World_Server.Packets.Send; using FFXIVClassic_World_Server.Packets.Send;
using FFXIVClassic_World_Server.Packets.Send.Login; using FFXIVClassic_World_Server.Packets.Send.Login;
using FFXIVClassic_World_Server.Packets.WorldPackets.Receive;
using FFXIVClassic_World_Server.Packets.WorldPackets.Send;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -47,7 +49,10 @@ namespace FFXIVClassic_World_Server
HelloPacket hello = new HelloPacket(packet.data); HelloPacket hello = new HelloPacket(packet.data);
if (packet.header.connectionType == BasePacket.TYPE_ZONE) if (packet.header.connectionType == BasePacket.TYPE_ZONE)
{
mServer.AddSession(client, Session.Channel.ZONE, hello.sessionId); mServer.AddSession(client, Session.Channel.ZONE, hello.sessionId);
mServer.GetWorldManager().DoLogin(mServer.GetSession(hello.sessionId));
}
else if (packet.header.connectionType == BasePacket.TYPE_CHAT) else if (packet.header.connectionType == BasePacket.TYPE_CHAT)
mServer.AddSession(client, Session.Channel.CHAT, hello.sessionId); mServer.AddSession(client, Session.Channel.CHAT, hello.sessionId);
@ -73,7 +78,6 @@ namespace FFXIVClassic_World_Server
{ {
//Send to the correct zone server //Send to the correct zone server
uint targetSession = subpacket.header.targetId; uint targetSession = subpacket.header.targetId;
mServer.GetSession(targetSession).routing1 = Server.GetServer().GetWorldManager().mZoneServerList["127.0.0.1:1989"];
if (mServer.GetSession(targetSession).routing1 != null) if (mServer.GetSession(targetSession).routing1 != null)
mServer.GetSession(targetSession).routing1.SendPacket(subpacket); mServer.GetSession(targetSession).routing1.SendPacket(subpacket);
@ -81,6 +85,57 @@ namespace FFXIVClassic_World_Server
if (mServer.GetSession(targetSession).routing2 != null) if (mServer.GetSession(targetSession).routing2 != null)
mServer.GetSession(targetSession).routing2.SendPacket(subpacket); mServer.GetSession(targetSession).routing2.SendPacket(subpacket);
} }
//World Server Type
else if (subpacket.header.type >= 0x1000)
{
uint targetSession = subpacket.header.targetId;
Session session = mServer.GetSession(targetSession);
switch (subpacket.header.type)
{
//Session Begin Confirm
case 0x1000:
SessionBeginConfirmPacket beginConfirmPacket = new SessionBeginConfirmPacket(packet.data);
if (beginConfirmPacket.invalidPacket || beginConfirmPacket.errorCode == 0)
Program.Log.Error("Session {0} had a error beginning session.", beginConfirmPacket.sessionId);
break;
//Session End Confirm
case 0x1001:
SessionEndConfirmPacket endConfirmPacket = new SessionEndConfirmPacket(packet.data);
if (!endConfirmPacket.invalidPacket && endConfirmPacket.errorCode != 0)
{
//Check destination, if != 0, update route and start new session
if (endConfirmPacket.destinationZone != 0)
{
session.routing1 = Server.GetServer().GetWorldManager().GetZoneServer(endConfirmPacket.destinationZone);
session.routing1.SendSessionStart(session);
}
else
{
mServer.RemoveSession(Session.Channel.ZONE, endConfirmPacket.sessionId);
mServer.RemoveSession(Session.Channel.CHAT, endConfirmPacket.sessionId);
}
}
else
Program.Log.Error("Session {0} had an error ending session.", endConfirmPacket.sessionId);
break;
//Zone Change Request
case 0x1002:
WorldRequestZoneChangePacket zoneChangePacket = new WorldRequestZoneChangePacket(packet.data);
if (!zoneChangePacket.invalidPacket)
{
mServer.GetWorldManager().DoZoneServerChange(session, zoneChangePacket.destinationZoneId, "", zoneChangePacket.destinationSpawnType, zoneChangePacket.destinationX, zoneChangePacket.destinationY, zoneChangePacket.destinationZ, zoneChangePacket.destinationRot);
}
break;
}
}
else else
packet.DebugPrintPacket(); packet.DebugPrintPacket();
} }

View File

@ -0,0 +1,38 @@
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.Receive
{
class SessionBeginConfirmPacket
{
public bool invalidPacket = false;
public uint sessionId;
public ushort errorCode;
public SessionBeginConfirmPacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
sessionId = binReader.ReadUInt32();
errorCode = binReader.ReadUInt16();
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -0,0 +1,39 @@
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.Receive
{
class SessionEndConfirmPacket
{
public bool invalidPacket = false;
public uint sessionId;
public ushort errorCode;
public uint destinationZone;
public SessionEndConfirmPacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
sessionId = binReader.ReadUInt32();
errorCode = binReader.ReadUInt16();
destinationZone = binReader.ReadUInt32();
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -0,0 +1,49 @@
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.Receive
{
class WorldRequestZoneChangePacket
{
public uint sessionId;
public uint destinationZoneId;
public byte destinationSpawnType;
public float destinationX;
public float destinationY;
public float destinationZ;
public float destinationRot;
public bool invalidPacket = false;
public WorldRequestZoneChangePacket(byte[] data)
{
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
sessionId = binReader.ReadUInt32();
destinationZoneId = binReader.ReadUInt32();
destinationSpawnType = (byte)binReader.ReadUInt16();
destinationX = binReader.ReadSingle();
destinationY = binReader.ReadSingle();
destinationZ = binReader.ReadSingle();
destinationRot = binReader.ReadSingle();
}
catch (Exception)
{
invalidPacket = true;
}
}
}
}
}
}

View File

@ -12,12 +12,51 @@ namespace FFXIVClassic_World_Server.Packets.WorldPackets.Send
class SessionEndPacket class SessionEndPacket
{ {
public const ushort OPCODE = 0x1001; public const ushort OPCODE = 0x1001;
public const uint PACKET_SIZE = 0x24; public const uint PACKET_SIZE = 0x38;
public static SubPacket BuildPacket(Session session) public static SubPacket BuildPacket(Session session)
{ {
byte[] data = new byte[PACKET_SIZE - 0x20]; byte[] data = new byte[PACKET_SIZE - 0x20];
using (MemoryStream mem = new MemoryStream(data))
{
using (BinaryWriter binWriter = new BinaryWriter(mem))
{
try
{
binWriter.Write((UInt32)0);
}
catch (Exception)
{ }
}
}
return new SubPacket(true, OPCODE, 0, session.sessionId, data);
}
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)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); return new SubPacket(true, OPCODE, 0, session.sessionId, data);
} }
} }

View File

@ -1,44 +0,0 @@
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);
}
}
}

View File

@ -1,5 +1,6 @@
using FFXIVClassic.Common; using FFXIVClassic.Common;
using FFXIVClassic_World_Server.DataObjects; using FFXIVClassic_World_Server.DataObjects;
using FFXIVClassic_World_Server.Packets.WorldPackets.Receive;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
@ -139,6 +140,57 @@ namespace FFXIVClassic_World_Server
{ {
uint sessionId = subpacket.header.targetId; uint sessionId = subpacket.header.targetId;
if (subpacket.gameMessage.opcode >= 0x1000)
{
subpacket.DebugPrintSubPacket();
uint targetSession = subpacket.header.targetId;
Session session = GetSession(targetSession);
switch (subpacket.gameMessage.opcode)
{
//Session Begin Confirm
case 0x1000:
SessionBeginConfirmPacket beginConfirmPacket = new SessionBeginConfirmPacket(subpacket.data);
if (beginConfirmPacket.invalidPacket || beginConfirmPacket.errorCode == 0)
Program.Log.Error("Session {0} had a error beginning session.", beginConfirmPacket.sessionId);
break;
//Session End Confirm
case 0x1001:
SessionEndConfirmPacket endConfirmPacket = new SessionEndConfirmPacket(subpacket.data);
if (!endConfirmPacket.invalidPacket && endConfirmPacket.errorCode == 0)
{
//Check destination, if != 0, update route and start new session
if (endConfirmPacket.destinationZone != 0)
{
session.routing1 = Server.GetServer().GetWorldManager().GetZoneServer(endConfirmPacket.destinationZone);
session.routing1.SendSessionStart(session);
}
else
{
RemoveSession(Session.Channel.ZONE, endConfirmPacket.sessionId);
RemoveSession(Session.Channel.CHAT, endConfirmPacket.sessionId);
}
}
else
Program.Log.Error("Session {0} had an error ending session.", endConfirmPacket.sessionId);
break;
//Zone Change Request
case 0x1002:
WorldRequestZoneChangePacket zoneChangePacket = new WorldRequestZoneChangePacket(subpacket.data);
if (!zoneChangePacket.invalidPacket)
{
GetWorldManager().DoZoneServerChange(session, zoneChangePacket.destinationZoneId, "", zoneChangePacket.destinationSpawnType, zoneChangePacket.destinationX, zoneChangePacket.destinationY, zoneChangePacket.destinationZ, zoneChangePacket.destinationRot);
}
break;
}
}
if (mZoneSessionList.ContainsKey(sessionId)) if (mZoneSessionList.ContainsKey(sessionId))
{ {
ClientConnection conn = mZoneSessionList[sessionId].clientConnection; ClientConnection conn = mZoneSessionList[sessionId].clientConnection;

View File

@ -34,6 +34,7 @@ namespace FFXIVClassic_World_Server
string query = @" string query = @"
SELECT SELECT
id,
serverIp, serverIp,
serverPort serverPort
FROM server_zones FROM server_zones
@ -45,15 +46,18 @@ namespace FFXIVClassic_World_Server
{ {
while (reader.Read()) while (reader.Read())
{ {
string ip = reader.GetString(0); uint id = reader.GetUInt32(0);
int port = reader.GetInt32(1); string ip = reader.GetString(1);
int port = reader.GetInt32(2);
string address = ip + ":" + port; string address = ip + ":" + port;
if (!mZoneServerList.ContainsKey(address)) if (!mZoneServerList.ContainsKey(address))
{ {
ZoneServer zone = new ZoneServer(ip, port); ZoneServer zone = new ZoneServer(ip, port, id);
mZoneServerList.Add(address, zone); mZoneServerList.Add(address, zone);
} }
else
mZoneServerList[address].AddLoadedZone(id);
} }
} }
} }
@ -130,6 +134,17 @@ namespace FFXIVClassic_World_Server
} }
} }
public ZoneServer GetZoneServer(uint zoneId)
{
foreach (ZoneServer zs in mZoneServerList.Values)
{
if (zs.ownedZoneIds.Contains(zoneId))
return zs;
}
return null;
}
//Moves the actor to the new zone if exists. No packets are sent nor position changed. //Moves the actor to the new zone if exists. No packets are sent nor position changed.
public void DoSeamlessZoneServerChange(Session session, uint destinationZoneId) public void DoSeamlessZoneServerChange(Session session, uint destinationZoneId)
{ {
@ -158,12 +173,8 @@ namespace FFXIVClassic_World_Server
//Login Zone In //Login Zone In
public void DoLogin(Session session) public void DoLogin(Session session)
{ {
/* session.routing1 = GetZoneServer(Database.GetCurrentZoneForSession(session.sessionId));
->Update routing session.routing1.SendSessionStart(session);
->Tell new server to load session info and add
*/
} }
public class ZoneEntrance public class ZoneEntrance