1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-20 19:57:46 +00:00

More work on the world server. Modified map server to communicate with it.

This commit is contained in:
Filip Maj 2016-08-29 08:17:14 -04:00
parent bd26a71fef
commit 6bffe69b21
16 changed files with 507 additions and 577 deletions

View file

@ -295,6 +295,41 @@ namespace FFXIVClassic.Common
return packet; return packet;
} }
/// <summary>
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
/// </summary>
/// <param name="offset">Current offset in buffer.</param>
/// <param name="buffer">Incoming buffer.</param>
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
public static BasePacket CreatePacket(ref int offset, byte[] buffer, int bytesRead)
{
BasePacket newPacket = null;
//Too small to even get length
if (bytesRead <= offset)
return null;
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
//Too small to whole packet
if (bytesRead < offset + packetSize)
return null;
if (buffer.Length < offset + packetSize)
return null;
try
{
newPacket = new BasePacket(buffer, ref offset);
}
catch (OverflowException)
{
return null;
}
return newPacket;
}
public static unsafe void EncryptPacket(Blowfish blowfish, BasePacket packet) public static unsafe void EncryptPacket(Blowfish blowfish, BasePacket packet)
{ {
var data = packet.data; var data = packet.data;

View file

@ -153,6 +153,41 @@ namespace FFXIVClassic.Common
return outBytes; return outBytes;
} }
/// <summary>
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
/// </summary>
/// <param name="offset">Current offset in buffer.</param>
/// <param name="buffer">Incoming buffer.</param>
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
public static SubPacket CreatePacket(ref int offset, byte[] buffer, int bytesRead)
{
SubPacket newPacket = null;
//Too small to even get length
if (bytesRead <= offset)
return null;
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
//Too small to whole packet
if (bytesRead < offset + packetSize)
return null;
if (buffer.Length < offset + packetSize)
return null;
try
{
newPacket = new SubPacket(buffer, ref offset);
}
catch (OverflowException)
{
return null;
}
return newPacket;
}
public void DebugPrintSubPacket() public void DebugPrintSubPacket()
{ {
#if DEBUG #if DEBUG
@ -169,6 +204,9 @@ namespace FFXIVClassic.Common
logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE), logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE),
ConsoleOutputColor.DarkMagenta); ConsoleOutputColor.DarkMagenta);
} }
else
logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE),
ConsoleOutputColor.DarkMagenta);
#endif #endif
} }
} }

View file

@ -88,7 +88,7 @@ namespace FFXIVClassic_Map_Server
if (cmd.Any()) if (cmd.Any())
{ {
// if client isnt null, take player to be the player actor // if client isnt null, take player to be the player actor
var player = client?.GetActor(); var player = client.GetActor();
if (cmd.Equals("help")) if (cmd.Equals("help"))
{ {

View file

@ -30,7 +30,7 @@ namespace FFXIVClassic_Map_Server
INIFile configIni = new INIFile("./map_config.ini"); INIFile configIni = new INIFile("./map_config.ini");
ConfigConstants.OPTIONS_BINDIP = configIni.GetValue("General", "server_ip", "127.0.0.1"); ConfigConstants.OPTIONS_BINDIP = configIni.GetValue("General", "server_ip", "127.0.0.1");
ConfigConstants.OPTIONS_PORT = configIni.GetValue("General", "server_port", "54992"); ConfigConstants.OPTIONS_PORT = configIni.GetValue("General", "server_port", "1989");
ConfigConstants.OPTIONS_TIMESTAMP = configIni.GetValue("General", "showtimestamp", "true").ToLower().Equals("true"); ConfigConstants.OPTIONS_TIMESTAMP = configIni.GetValue("General", "showtimestamp", "true").ToLower().Equals("true");
ConfigConstants.DATABASE_WORLDID = UInt32.Parse(configIni.GetValue("Database", "worldid", "0")); ConfigConstants.DATABASE_WORLDID = UInt32.Parse(configIni.GetValue("Database", "worldid", "0"));

View file

@ -91,7 +91,7 @@
<Compile Include="actors\quest\Quest.cs" /> <Compile Include="actors\quest\Quest.cs" />
<Compile Include="actors\StaticActors.cs" /> <Compile Include="actors\StaticActors.cs" />
<Compile Include="actors\world\WorldMaster.cs" /> <Compile Include="actors\world\WorldMaster.cs" />
<Compile Include="ClientConnection.cs" /> <Compile Include="ZoneConnection.cs" />
<Compile Include="CommandProcessor.cs" /> <Compile Include="CommandProcessor.cs" />
<Compile Include="ConfigConstants.cs" /> <Compile Include="ConfigConstants.cs" />
<Compile Include="Database.cs" /> <Compile Include="Database.cs" />

View file

@ -26,393 +26,283 @@ namespace FFXIVClassic_Map_Server
Server mServer; Server mServer;
CommandProcessor cp; CommandProcessor cp;
Dictionary<uint, ConnectedPlayer> mPlayers; Dictionary<uint, ConnectedPlayer> mPlayers;
List<ClientConnection> mConnections;
public PacketProcessor(Server server, Dictionary<uint, ConnectedPlayer> playerList, List<ClientConnection> connectionList) public PacketProcessor(Server server, Dictionary<uint, ConnectedPlayer> playerList)
{ {
mPlayers = playerList; mPlayers = playerList;
mConnections = connectionList;
mServer = server; mServer = server;
cp = new CommandProcessor(playerList); cp = new CommandProcessor(playerList);
} }
public void ProcessPacket(ClientConnection client, BasePacket packet) public void ProcessPacket(ZoneConnection client, SubPacket subpacket)
{ {
if (packet.header.isCompressed == 0x01)
BasePacket.DecryptPacket(client.blowfish, ref packet);
List<SubPacket> subPackets = packet.GetSubpackets(); ConnectedPlayer player = null;
foreach (SubPacket subpacket in subPackets)
{ if(mPlayers.ContainsKey(subpacket.header.targetId))
if (subpacket.header.type == 0x01) player = mPlayers[subpacket.header.targetId];
if (player == null)
{ {
packet.DebugPrintPacket(); player = new ConnectedPlayer(client, subpacket.header.targetId);
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 = { subpacket.DebugPrintSubPacket();
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); //Normal Game Opcode
BasePacket reply2 = new BasePacket(reply2Data); switch (subpacket.gameMessage.opcode)
{
//Write Timestamp into Reply1 //Ping
using (MemoryStream mem = new MemoryStream(reply1.data)) case 0x0001:
{ //subpacket.DebugPrintSubPacket();
using (BinaryWriter binReader = new BinaryWriter(mem)) PingPacket pingPacket = new PingPacket(subpacket.data);
{ client.QueuePacket(BasePacket.CreatePacket(PongPacket.BuildPacket(player.actorID, pingPacket.time), true, false));
binReader.BaseStream.Seek(0x14, SeekOrigin.Begin); player.Ping();
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)
{ }
}
}
//Should never happen.... unless actor id IS 0!
if (actorID == 0)
break; break;
//Unknown
case 0x0002:
client.owner = actorID; subpacket.DebugPrintSubPacket();
//Write Actor ID into reply2 player = new ConnectedPlayer(client, subpacket.header.targetId);
using (MemoryStream mem = new MemoryStream(reply2.data)) mPlayers[subpacket.header.targetId] = player;
{
using (BinaryWriter binReader = new BinaryWriter(mem)) client.QueuePacket(_0x2Packet.BuildPacket(player.actorID), true, false);
Server.GetWorldManager().DoLogin(player.GetActor());
break;
//Chat Received
case 0x0003:
ChatMessagePacket chatMessage = new ChatMessagePacket(subpacket.data);
Program.Log.Info("Got type-{5} message: {0} @ {1}, {2}, {3}, Rot: {4}", chatMessage.message, chatMessage.posX, chatMessage.posY, chatMessage.posZ, chatMessage.posRot, chatMessage.logType);
subpacket.DebugPrintSubPacket();
if (chatMessage.message.StartsWith("!"))
{ {
binReader.BaseStream.Seek(0x10, SeekOrigin.Begin); if (cp.DoCommand(chatMessage.message, player))
binReader.Write(actorID); return; ;
} }
}
ConnectedPlayer player = null; player.GetActor().BroadcastPacket(SendMessagePacket.BuildPacket(player.actorID, player.actorID, chatMessage.logType, player.GetActor().customDisplayName, chatMessage.message), false);
if (packet.header.connectionType == BasePacket.TYPE_ZONE) break;
{ //Langauge Code
while (mPlayers != null && !mPlayers.ContainsKey(client.owner)) case 0x0006:
{ } LangaugeCodePacket langCode = new LangaugeCodePacket(subpacket.data);
player = mPlayers[client.owner]; player.languageCode = langCode.languageCode;
} break;
//Unknown - Happens a lot at login, then once every time player zones
//Create connected player if not Created case 0x0007:
if (player == null) //subpacket.DebugPrintSubPacket();
{ _0x07Packet unknown07 = new _0x07Packet(subpacket.data);
player = new ConnectedPlayer(actorID); break;
mPlayers[actorID] = player; //Update Position
} case 0x00CA:
player.SetConnection(packet.header.connectionType, client);
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());
//Create player actor
reply1.DebugPrintPacket();
client.QueuePacket(reply1);
client.QueuePacket(reply2);
break;
}
else if (subpacket.header.type == 0x07)
{
BasePacket init = Login0x7ResponsePacket.BuildPacket(BitConverter.ToUInt32(packet.data, 0x10), Utils.UnixTimeStampUTC(), 0x08);
//client.QueuePacket(init);
}
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();
}
else if (subpacket.header.type == 0x03)
{
ConnectedPlayer player = null;
if(mPlayers.ContainsKey(client.owner))
player = mPlayers[client.owner];
if (player == null || !player.IsClientConnectionsReady())
return;
//Normal Game Opcode
switch (subpacket.gameMessage.opcode)
{
//Ping
case 0x0001:
//subpacket.DebugPrintSubPacket();
PingPacket pingPacket = new PingPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(PongPacket.BuildPacket(player.actorID, pingPacket.time), true, false));
player.Ping();
break;
//Unknown
case 0x0002:
subpacket.DebugPrintSubPacket();
client.QueuePacket(_0x2Packet.BuildPacket(player.actorID), true, false);
Server.GetWorldManager().DoLogin(player.GetActor());
break;
//Chat Received
case 0x0003:
ChatMessagePacket chatMessage = new ChatMessagePacket(subpacket.data);
Program.Log.Info("Got type-{5} message: {0} @ {1}, {2}, {3}, Rot: {4}", chatMessage.message, chatMessage.posX, chatMessage.posY, chatMessage.posZ, chatMessage.posRot, chatMessage.logType);
subpacket.DebugPrintSubPacket();
if (chatMessage.message.StartsWith("!"))
{
if (cp.DoCommand(chatMessage.message, player))
continue;
}
player.GetActor().BroadcastPacket(SendMessagePacket.BuildPacket(player.actorID, player.actorID, chatMessage.logType, player.GetActor().customDisplayName, chatMessage.message), false);
break;
//Langauge Code
case 0x0006:
LangaugeCodePacket langCode = new LangaugeCodePacket(subpacket.data);
player.languageCode = langCode.languageCode;
break;
//Unknown - Happens a lot at login, then once every time player zones
case 0x0007:
//subpacket.DebugPrintSubPacket();
_0x07Packet unknown07 = new _0x07Packet(subpacket.data);
break;
//Update Position //Update Position
case 0x00CA: //subpacket.DebugPrintSubPacket();
//Update Position UpdatePlayerPositionPacket posUpdate = new UpdatePlayerPositionPacket(subpacket.data);
//subpacket.DebugPrintSubPacket(); player.UpdatePlayerActorPosition(posUpdate.x, posUpdate.y, posUpdate.z, posUpdate.rot, posUpdate.moveState);
UpdatePlayerPositionPacket posUpdate = new UpdatePlayerPositionPacket(subpacket.data); player.GetActor().SendInstanceUpdate();
player.UpdatePlayerActorPosition(posUpdate.x, posUpdate.y, posUpdate.z, posUpdate.rot, posUpdate.moveState);
player.GetActor().SendInstanceUpdate(); if (player.GetActor().IsInZoneChange())
player.GetActor().SetZoneChanging(false);
break;
//Set Target
case 0x00CD:
//subpacket.DebugPrintSubPacket();
SetTargetPacket setTarget = new SetTargetPacket(subpacket.data);
player.GetActor().currentTarget = setTarget.actorID;
player.GetActor().BroadcastPacket(SetActorTargetAnimatedPacket.BuildPacket(player.actorID, player.actorID, setTarget.actorID), true);
break;
//Lock Target
case 0x00CC:
LockTargetPacket lockTarget = new LockTargetPacket(subpacket.data);
player.GetActor().currentLockedTarget = lockTarget.actorID;
break;
//Start Event
case 0x012D:
subpacket.DebugPrintSubPacket();
EventStartPacket eventStart = new EventStartPacket(subpacket.data);
/*
if (eventStart.error != null)
{
player.errorMessage += eventStart.error;
if (eventStart.errorIndex == eventStart.errorNum - 1)
Program.Log.Error("\n"+player.errorMessage);
if (player.GetActor().IsInZoneChange())
player.GetActor().SetZoneChanging(false);
break; break;
//Set Target }
case 0x00CD: */
//subpacket.DebugPrintSubPacket();
SetTargetPacket setTarget = new SetTargetPacket(subpacket.data); Actor ownerActor = Server.GetStaticActors(eventStart.scriptOwnerActorID);
player.GetActor().currentTarget = setTarget.actorID;
player.GetActor().BroadcastPacket(SetActorTargetAnimatedPacket.BuildPacket(player.actorID, player.actorID, setTarget.actorID), true);
break;
//Lock Target
case 0x00CC:
LockTargetPacket lockTarget = new LockTargetPacket(subpacket.data);
player.GetActor().currentLockedTarget = lockTarget.actorID;
break;
//Start Event
case 0x012D:
subpacket.DebugPrintSubPacket();
EventStartPacket eventStart = new EventStartPacket(subpacket.data);
/*
if (eventStart.error != null)
{
player.errorMessage += eventStart.error;
if (eventStart.errorIndex == eventStart.errorNum - 1)
Program.Log.Error("\n"+player.errorMessage);
break; player.GetActor().currentEventOwner = eventStart.scriptOwnerActorID;
} player.GetActor().currentEventName = eventStart.triggerName;
*/
Actor ownerActor = Server.GetStaticActors(eventStart.scriptOwnerActorID);
player.GetActor().currentEventOwner = eventStart.scriptOwnerActorID;
player.GetActor().currentEventName = eventStart.triggerName;
if (ownerActor == null)
{
//Is it a instance actor?
ownerActor = Server.GetWorldManager().GetActorInWorld(player.GetActor().currentEventOwner);
if (ownerActor == null) if (ownerActor == null)
{ {
//Is it a instance actor? //Is it a Director?
ownerActor = Server.GetWorldManager().GetActorInWorld(player.GetActor().currentEventOwner); if (player.GetActor().currentDirector != null && player.GetActor().currentEventOwner == player.GetActor().currentDirector.actorId)
if (ownerActor == null) ownerActor = player.GetActor().currentDirector;
else
{ {
//Is it a Director? Program.Log.Debug("\n===Event START===\nCould not find actor 0x{0:X} for event started by caller: 0x{1:X}\nEvent Starter: {2}\nParams: {3}", eventStart.actorID, eventStart.scriptOwnerActorID, eventStart.triggerName, LuaUtils.DumpParams(eventStart.luaParams));
if (player.GetActor().currentDirector != null && player.GetActor().currentEventOwner == player.GetActor().currentDirector.actorId) break;
ownerActor = player.GetActor().currentDirector;
else
{
Program.Log.Debug("\n===Event START===\nCould not find actor 0x{0:X} for event started by caller: 0x{1:X}\nEvent Starter: {2}\nParams: {3}", eventStart.actorID, eventStart.scriptOwnerActorID, eventStart.triggerName, LuaUtils.DumpParams(eventStart.luaParams));
break;
}
} }
} }
}
player.GetActor().StartEvent(ownerActor, eventStart); player.GetActor().StartEvent(ownerActor, eventStart);
Program.Log.Debug("\n===Event START===\nSource Actor: 0x{0:X}\nCaller Actor: 0x{1:X}\nVal1: 0x{2:X}\nVal2: 0x{3:X}\nEvent Starter: {4}\nParams: {5}", eventStart.actorID, eventStart.scriptOwnerActorID, eventStart.val1, eventStart.val2, eventStart.triggerName, LuaUtils.DumpParams(eventStart.luaParams));
break;
//Unknown, happens at npc spawn and cutscene play????
case 0x00CE:
break;
//Event Result
case 0x012E:
subpacket.DebugPrintSubPacket();
EventUpdatePacket eventUpdate = new EventUpdatePacket(subpacket.data);
Program.Log.Debug("\n===Event UPDATE===\nSource Actor: 0x{0:X}\nCaller Actor: 0x{1:X}\nVal1: 0x{2:X}\nVal2: 0x{3:X}\nStep: 0x{4:X}\nParams: {5}", eventUpdate.actorID, eventUpdate.scriptOwnerActorID, eventUpdate.val1, eventUpdate.val2, eventUpdate.step, LuaUtils.DumpParams(eventUpdate.luaParams));
/*
//Is it a static actor? If not look in the player's instance
Actor updateOwnerActor = Server.GetStaticActors(player.GetActor().currentEventOwner);
if (updateOwnerActor == null)
{
updateOwnerActor = Server.GetWorldManager().GetActorInWorld(player.GetActor().currentEventOwner);
if (player.GetActor().currentDirector != null && player.GetActor().currentEventOwner == player.GetActor().currentDirector.actorId)
updateOwnerActor = player.GetActor().currentDirector;
Program.Log.Debug("\n===Event START===\nSource Actor: 0x{0:X}\nCaller Actor: 0x{1:X}\nVal1: 0x{2:X}\nVal2: 0x{3:X}\nEvent Starter: {4}\nParams: {5}", eventStart.actorID, eventStart.scriptOwnerActorID, eventStart.val1, eventStart.val2, eventStart.triggerName, LuaUtils.DumpParams(eventStart.luaParams));
break;
//Unknown, happens at npc spawn and cutscene play????
case 0x00CE:
break;
//Event Result
case 0x012E:
subpacket.DebugPrintSubPacket();
EventUpdatePacket eventUpdate = new EventUpdatePacket(subpacket.data);
Program.Log.Debug("\n===Event UPDATE===\nSource Actor: 0x{0:X}\nCaller Actor: 0x{1:X}\nVal1: 0x{2:X}\nVal2: 0x{3:X}\nStep: 0x{4:X}\nParams: {5}", eventUpdate.actorID, eventUpdate.scriptOwnerActorID, eventUpdate.val1, eventUpdate.val2, eventUpdate.step, LuaUtils.DumpParams(eventUpdate.luaParams));
/*
//Is it a static actor? If not look in the player's instance
Actor updateOwnerActor = Server.GetStaticActors(player.GetActor().currentEventOwner);
if (updateOwnerActor == null) if (updateOwnerActor == null)
{ break;
updateOwnerActor = Server.GetWorldManager().GetActorInWorld(player.GetActor().currentEventOwner); }
*/
player.GetActor().UpdateEvent(eventUpdate);
if (player.GetActor().currentDirector != null && player.GetActor().currentEventOwner == player.GetActor().currentDirector.actorId) //LuaEngine.DoActorOnEventUpdated(player.GetActor(), updateOwnerActor, eventUpdate);
updateOwnerActor = player.GetActor().currentDirector;
if (updateOwnerActor == null) break;
break; case 0x012F:
} //subpacket.DebugPrintSubPacket();
*/ ParameterDataRequestPacket paramRequest = new ParameterDataRequestPacket(subpacket.data);
player.GetActor().UpdateEvent(eventUpdate); if (paramRequest.paramName.Equals("charaWork/exp"))
player.GetActor().SendCharaExpInfo();
//LuaEngine.DoActorOnEventUpdated(player.GetActor(), updateOwnerActor, eventUpdate); break;
/* RECRUITMENT */
break; //Start Recruiting
case 0x012F: case 0x01C3:
//subpacket.DebugPrintSubPacket(); StartRecruitingRequestPacket recruitRequestPacket = new StartRecruitingRequestPacket(subpacket.data);
ParameterDataRequestPacket paramRequest = new ParameterDataRequestPacket(subpacket.data); client.QueuePacket(BasePacket.CreatePacket(StartRecruitingResponse.BuildPacket(player.actorID, true), true, false));
if (paramRequest.paramName.Equals("charaWork/exp")) break;
player.GetActor().SendCharaExpInfo(); //End Recruiting
break; case 0x01C4:
/* RECRUITMENT */ client.QueuePacket(BasePacket.CreatePacket(EndRecruitmentPacket.BuildPacket(player.actorID), true, false));
//Start Recruiting break;
case 0x01C3: //Party Window Opened, Request State
StartRecruitingRequestPacket recruitRequestPacket = new StartRecruitingRequestPacket(subpacket.data); case 0x01C5:
client.QueuePacket(BasePacket.CreatePacket(StartRecruitingResponse.BuildPacket(player.actorID, true), true, false)); client.QueuePacket(BasePacket.CreatePacket(RecruiterStatePacket.BuildPacket(player.actorID, true, true, 1), true, false));
break; break;
//End Recruiting //Search Recruiting
case 0x01C4: case 0x01C7:
client.QueuePacket(BasePacket.CreatePacket(EndRecruitmentPacket.BuildPacket(player.actorID), true, false)); RecruitmentSearchRequestPacket recruitSearchPacket = new RecruitmentSearchRequestPacket(subpacket.data);
break; break;
//Party Window Opened, Request State //Get Recruitment Details
case 0x01C5: case 0x01C8:
client.QueuePacket(BasePacket.CreatePacket(RecruiterStatePacket.BuildPacket(player.actorID, true, true, 1), true, false)); RecruitmentDetailsRequestPacket currentRecruitDetailsPacket = new RecruitmentDetailsRequestPacket(subpacket.data);
break; RecruitmentDetails details = new RecruitmentDetails();
//Search Recruiting details.recruiterName = "Localhost Character";
case 0x01C7: details.purposeId = 2;
RecruitmentSearchRequestPacket recruitSearchPacket = new RecruitmentSearchRequestPacket(subpacket.data); details.locationId = 1;
break; details.subTaskId = 1;
//Get Recruitment Details details.comment = "This is a test details packet sent by the server. No implementation has been Created yet...";
case 0x01C8: details.num[0] = 1;
RecruitmentDetailsRequestPacket currentRecruitDetailsPacket = new RecruitmentDetailsRequestPacket(subpacket.data); client.QueuePacket(BasePacket.CreatePacket(CurrentRecruitmentDetailsPacket.BuildPacket(player.actorID, details), true, false));
RecruitmentDetails details = new RecruitmentDetails(); break;
details.recruiterName = "Localhost Character"; //Accepted Recruiting
details.purposeId = 2; case 0x01C6:
details.locationId = 1; subpacket.DebugPrintSubPacket();
details.subTaskId = 1; break;
details.comment = "This is a test details packet sent by the server. No implementation has been Created yet..."; /* SOCIAL STUFF */
details.num[0] = 1; case 0x01C9:
client.QueuePacket(BasePacket.CreatePacket(CurrentRecruitmentDetailsPacket.BuildPacket(player.actorID, details), true, false)); AddRemoveSocialPacket addBlackList = new AddRemoveSocialPacket(subpacket.data);
break; client.QueuePacket(BasePacket.CreatePacket(BlacklistAddedPacket.BuildPacket(player.actorID, true, addBlackList.name), true, false));
//Accepted Recruiting break;
case 0x01C6: case 0x01CA:
subpacket.DebugPrintSubPacket(); AddRemoveSocialPacket RemoveBlackList = new AddRemoveSocialPacket(subpacket.data);
break; client.QueuePacket(BasePacket.CreatePacket(BlacklistRemovedPacket.BuildPacket(player.actorID, true, RemoveBlackList.name), true, false));
/* SOCIAL STUFF */ break;
case 0x01C9: case 0x01CB:
AddRemoveSocialPacket addBlackList = new AddRemoveSocialPacket(subpacket.data); int offset1 = 0;
client.QueuePacket(BasePacket.CreatePacket(BlacklistAddedPacket.BuildPacket(player.actorID, true, addBlackList.name), true, false)); client.QueuePacket(BasePacket.CreatePacket(SendBlacklistPacket.BuildPacket(player.actorID, new String[] { "Test" }, ref offset1), true, false));
break; break;
case 0x01CA: case 0x01CC:
AddRemoveSocialPacket RemoveBlackList = new AddRemoveSocialPacket(subpacket.data); AddRemoveSocialPacket addFriendList = new AddRemoveSocialPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(BlacklistRemovedPacket.BuildPacket(player.actorID, true, RemoveBlackList.name), true, false)); client.QueuePacket(BasePacket.CreatePacket(FriendlistAddedPacket.BuildPacket(player.actorID, true, (uint)addFriendList.name.GetHashCode(), true, addFriendList.name), true, false));
break; break;
case 0x01CB: case 0x01CD:
int offset1 = 0; AddRemoveSocialPacket RemoveFriendList = new AddRemoveSocialPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(SendBlacklistPacket.BuildPacket(player.actorID, new String[] { "Test" }, ref offset1), true, false)); client.QueuePacket(BasePacket.CreatePacket(FriendlistRemovedPacket.BuildPacket(player.actorID, true, RemoveFriendList.name), true, false));
break; break;
case 0x01CC: case 0x01CE:
AddRemoveSocialPacket addFriendList = new AddRemoveSocialPacket(subpacket.data); int offset2 = 0;
client.QueuePacket(BasePacket.CreatePacket(FriendlistAddedPacket.BuildPacket(player.actorID, true, (uint)addFriendList.name.GetHashCode(), true, addFriendList.name), true, false)); client.QueuePacket(BasePacket.CreatePacket(SendFriendlistPacket.BuildPacket(player.actorID, new Tuple<long, string>[] { new Tuple<long, string>(01, "Test2") }, ref offset2), true, false));
break; break;
case 0x01CD: case 0x01CF:
AddRemoveSocialPacket RemoveFriendList = new AddRemoveSocialPacket(subpacket.data); client.QueuePacket(BasePacket.CreatePacket(FriendStatusPacket.BuildPacket(player.actorID, null), true, false));
client.QueuePacket(BasePacket.CreatePacket(FriendlistRemovedPacket.BuildPacket(player.actorID, true, RemoveFriendList.name), true, false)); break;
break; /* SUPPORT DESK STUFF */
case 0x01CE: //Request for FAQ/Info List
int offset2 = 0; case 0x01D0:
client.QueuePacket(BasePacket.CreatePacket(SendFriendlistPacket.BuildPacket(player.actorID, new Tuple<long, string>[] { new Tuple<long, string>(01, "Test2") }, ref offset2), true, false)); FaqListRequestPacket faqRequest = new FaqListRequestPacket(subpacket.data);
break; client.QueuePacket(BasePacket.CreatePacket(FaqListResponsePacket.BuildPacket(player.actorID, new string[] { "Testing FAQ1", "Coded style!" }), true, false));
case 0x01CF: break;
client.QueuePacket(BasePacket.CreatePacket(FriendStatusPacket.BuildPacket(player.actorID, null), true, false)); //Request for body of a faq/info selection
break; case 0x01D1:
/* SUPPORT DESK STUFF */ FaqBodyRequestPacket faqBodyRequest = new FaqBodyRequestPacket(subpacket.data);
//Request for FAQ/Info List client.QueuePacket(BasePacket.CreatePacket(FaqBodyResponsePacket.BuildPacket(player.actorID, "HERE IS A GIANT BODY. Nothing else to say!"), true, false));
case 0x01D0: break;
FaqListRequestPacket faqRequest = new FaqListRequestPacket(subpacket.data); //Request issue list
client.QueuePacket(BasePacket.CreatePacket(FaqListResponsePacket.BuildPacket(player.actorID, new string[] { "Testing FAQ1", "Coded style!" }), true, false)); case 0x01D2:
break; GMTicketIssuesRequestPacket issuesRequest = new GMTicketIssuesRequestPacket(subpacket.data);
//Request for body of a faq/info selection client.QueuePacket(BasePacket.CreatePacket(IssueListResponsePacket.BuildPacket(player.actorID, new string[] { "Test1", "Test2", "Test3", "Test4", "Test5" }), true, false));
case 0x01D1: break;
FaqBodyRequestPacket faqBodyRequest = new FaqBodyRequestPacket(subpacket.data); //Request if GM ticket exists
client.QueuePacket(BasePacket.CreatePacket(FaqBodyResponsePacket.BuildPacket(player.actorID, "HERE IS A GIANT BODY. Nothing else to say!"), true, false)); case 0x01D3:
break; client.QueuePacket(BasePacket.CreatePacket(StartGMTicketPacket.BuildPacket(player.actorID, false), true, false));
//Request issue list break;
case 0x01D2: //Request for GM response message
GMTicketIssuesRequestPacket issuesRequest = new GMTicketIssuesRequestPacket(subpacket.data); case 0x01D4:
client.QueuePacket(BasePacket.CreatePacket(IssueListResponsePacket.BuildPacket(player.actorID, new string[] { "Test1", "Test2", "Test3", "Test4", "Test5" }), true, false)); client.QueuePacket(BasePacket.CreatePacket(GMTicketPacket.BuildPacket(player.actorID, "This is a GM Ticket Title", "This is a GM Ticket Body."), true, false));
break; break;
//Request if GM ticket exists //GM Ticket Sent
case 0x01D3: case 0x01D5:
client.QueuePacket(BasePacket.CreatePacket(StartGMTicketPacket.BuildPacket(player.actorID, false), true, false)); GMSupportTicketPacket gmTicket = new GMSupportTicketPacket(subpacket.data);
break; Program.Log.Info("Got GM Ticket: \n" + gmTicket.ticketTitle + "\n" + gmTicket.ticketBody);
//Request for GM response message client.QueuePacket(BasePacket.CreatePacket(GMTicketSentResponsePacket.BuildPacket(player.actorID, true), true, false));
case 0x01D4: break;
client.QueuePacket(BasePacket.CreatePacket(GMTicketPacket.BuildPacket(player.actorID, "This is a GM Ticket Title", "This is a GM Ticket Body."), true, false)); //Request to end ticket
break; case 0x01D6:
//GM Ticket Sent client.QueuePacket(BasePacket.CreatePacket(EndGMTicketPacket.BuildPacket(player.actorID), true, false));
case 0x01D5: break;
GMSupportTicketPacket gmTicket = new GMSupportTicketPacket(subpacket.data); default:
Program.Log.Info("Got GM Ticket: \n" + gmTicket.ticketTitle + "\n" + gmTicket.ticketBody); Program.Log.Debug("Unknown command 0x{0:X} received.", subpacket.gameMessage.opcode);
client.QueuePacket(BasePacket.CreatePacket(GMTicketSentResponsePacket.BuildPacket(player.actorID, true), true, false)); subpacket.DebugPrintSubPacket();
break; break;
//Request to end ticket
case 0x01D6:
client.QueuePacket(BasePacket.CreatePacket(EndGMTicketPacket.BuildPacket(player.actorID), true, false));
break;
default:
Program.Log.Debug("Unknown command 0x{0:X} received.", subpacket.gameMessage.opcode);
subpacket.DebugPrintSubPacket();
break;
}
} }
else
packet.DebugPrintPacket();
}
} }
} }

View file

@ -26,7 +26,7 @@ namespace FFXIVClassic_Map_Server
private Socket mServerSocket; private Socket mServerSocket;
private Dictionary<uint, ConnectedPlayer> mConnectedPlayerList = new Dictionary<uint, ConnectedPlayer>(); private Dictionary<uint, ConnectedPlayer> mConnectedPlayerList = new Dictionary<uint, ConnectedPlayer>();
private List<ClientConnection> mConnectionList = new List<ClientConnection>(); private ZoneConnection mWorldConnection = new ZoneConnection();
private LuaEngine mLuaEngine = new LuaEngine(); private LuaEngine mLuaEngine = new LuaEngine();
private static WorldManager mWorldManager; private static WorldManager mWorldManager;
@ -119,7 +119,7 @@ namespace FFXIVClassic_Map_Server
Program.Log.Info("Map Server has started @ {0}:{1}", (mServerSocket.LocalEndPoint as IPEndPoint).Address, (mServerSocket.LocalEndPoint as IPEndPoint).Port); Program.Log.Info("Map Server has started @ {0}:{1}", (mServerSocket.LocalEndPoint as IPEndPoint).Address, (mServerSocket.LocalEndPoint as IPEndPoint).Port);
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
mProcessor = new PacketProcessor(this, mConnectedPlayerList, mConnectionList); mProcessor = new PacketProcessor(this, mConnectedPlayerList);
//mGameThread = new Thread(new ThreadStart(mProcessor.update)); //mGameThread = new Thread(new ThreadStart(mProcessor.update));
//mGameThread.Start(); //mGameThread.Start();
@ -138,20 +138,17 @@ namespace FFXIVClassic_Map_Server
#region Socket Handling #region Socket Handling
private void AcceptCallback(IAsyncResult result) private void AcceptCallback(IAsyncResult result)
{ {
ClientConnection conn = null; ZoneConnection conn = null;
Socket socket = (System.Net.Sockets.Socket)result.AsyncState; Socket socket = (System.Net.Sockets.Socket)result.AsyncState;
try try
{ {
conn = new ClientConnection(); conn = new ZoneConnection();
conn.socket = socket.EndAccept(result); conn.socket = socket.EndAccept(result);
conn.buffer = new byte[BUFFER_SIZE]; conn.buffer = new byte[BUFFER_SIZE];
lock (mConnectionList) mWorldConnection = conn;
{
mConnectionList.Add(conn);
}
Program.Log.Info("Connection {0}:{1} has connected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port); Program.Log.Info("Connection {0}:{1} has connected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port);
//Queue recieving of data from the connection //Queue recieving of data from the connection
@ -163,11 +160,7 @@ namespace FFXIVClassic_Map_Server
{ {
if (conn != null) if (conn != null)
{ {
mWorldConnection = null;
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
} }
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket); mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
} }
@ -175,10 +168,7 @@ namespace FFXIVClassic_Map_Server
{ {
if (conn != null) if (conn != null)
{ {
lock (mConnectionList) mWorldConnection = null;
{
mConnectionList.Remove(conn);
}
} }
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket); mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
} }
@ -208,20 +198,13 @@ namespace FFXIVClassic_Map_Server
/// <param name="result"></param> /// <param name="result"></param>
private void ReceiveCallback(IAsyncResult result) private void ReceiveCallback(IAsyncResult result)
{ {
ClientConnection conn = (ClientConnection)result.AsyncState; ZoneConnection conn = (ZoneConnection)result.AsyncState;
//Check if disconnected //Check if disconnected
if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0)) if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0))
{ {
if (mConnectedPlayerList.ContainsKey(conn.owner)) mWorldConnection = null;
mConnectedPlayerList.Remove(conn.owner); Program.Log.Info("Disconnected from world server!");
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
if (conn.connType == BasePacket.TYPE_ZONE)
Program.Log.Info("{0} has disconnected.", conn.owner == 0 ? conn.GetAddress() : "User " + conn.owner);
return;
} }
try try
@ -237,13 +220,13 @@ namespace FFXIVClassic_Map_Server
//Build packets until can no longer or out of data //Build packets until can no longer or out of data
while (true) while (true)
{ {
BasePacket basePacket = BuildPacket(ref offset, conn.buffer, bytesRead); SubPacket subPacket = SubPacket.CreatePacket(ref offset, conn.buffer, bytesRead);
//If can't build packet, break, else process another //If can't build packet, break, else process another
if (basePacket == null) if (subPacket == null)
break; break;
else else
mProcessor.ProcessPacket(conn, basePacket); mProcessor.ProcessPacket(conn, subPacket);
} }
//Not all bytes consumed, transfer leftover to beginning //Not all bytes consumed, transfer leftover to beginning
@ -264,63 +247,20 @@ namespace FFXIVClassic_Map_Server
} }
else else
{ {
Program.Log.Info("{0} has disconnected.", conn.owner == 0 ? conn.GetAddress() : "User " + conn.owner); mWorldConnection = null;
Program.Log.Info("Disconnected from world server!");
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
} }
} }
catch (SocketException) catch (SocketException)
{ {
if (conn.socket != null) if (conn.socket != null)
{ {
Program.Log.Info("{0} has disconnected.", conn.owner == 0 ? conn.GetAddress() : "User " + conn.owner); mWorldConnection = null;
Program.Log.Info("Disconnected from world server!");
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
} }
} }
} }
/// <summary>
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
/// </summary>
/// <param name="offset">Current offset in buffer.</param>
/// <param name="buffer">Incoming buffer.</param>
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
public BasePacket BuildPacket(ref int offset, byte[] buffer, int bytesRead)
{
BasePacket newPacket = null;
//Too small to even get length
if (bytesRead <= offset)
return null;
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
//Too small to whole packet
if (bytesRead < offset + packetSize)
return null;
if (buffer.Length < offset + packetSize)
return null;
try
{
newPacket = new BasePacket(buffer, ref offset);
}
catch (OverflowException)
{
return null;
}
return newPacket;
}
#endregion #endregion

View file

@ -7,27 +7,22 @@ using System.Net;
namespace FFXIVClassic_Map_Server namespace FFXIVClassic_Map_Server
{ {
class ClientConnection class ZoneConnection
{ {
//Connection stuff //Connection stuff
public Blowfish blowfish;
public Socket socket; public Socket socket;
public byte[] buffer; public byte[] buffer;
private BlockingCollection<BasePacket> SendPacketQueue = new BlockingCollection<BasePacket>(1000); private BlockingCollection<SubPacket> SendPacketQueue = new BlockingCollection<SubPacket>(1000);
public int lastPartialSize = 0; public int lastPartialSize = 0;
//Instance Stuff
public uint owner = 0;
public int connType = 0;
public void QueuePacket(BasePacket packet) public void QueuePacket(BasePacket packet)
{ {
SendPacketQueue.Add(packet); //SendPacketQueue.Add(packet);
} }
public void QueuePacket(SubPacket subpacket, bool isAuthed, bool isEncrypted) public void QueuePacket(SubPacket subpacket, bool isAuthed, bool isEncrypted)
{ {
SendPacketQueue.Add(BasePacket.CreatePacket(subpacket, isAuthed, isEncrypted)); SendPacketQueue.Add(subpacket);
} }
public void FlushQueuedSendPackets() public void FlushQueuedSendPackets()
@ -37,9 +32,9 @@ namespace FFXIVClassic_Map_Server
while (SendPacketQueue.Count > 0) while (SendPacketQueue.Count > 0)
{ {
BasePacket packet = SendPacketQueue.Take(); SubPacket packet = SendPacketQueue.Take();
byte[] packetBytes = packet.GetPacketBytes(); byte[] packetBytes = packet.GetBytes();
try try
{ {

View file

@ -20,50 +20,20 @@ namespace FFXIVClassic_Map_Server.dataobjects
public uint languageCode = 1; public uint languageCode = 1;
private ClientConnection zoneConnection; private ZoneConnection zoneConnection;
private ClientConnection chatConnection;
private uint lastPingPacket = Utils.UnixTimeStampUTC(); private uint lastPingPacket = Utils.UnixTimeStampUTC();
public string errorMessage = ""; public string errorMessage = "";
public ConnectedPlayer(uint actorId) public ConnectedPlayer(ZoneConnection zc, uint actorId)
{ {
zoneConnection = zc;
this.actorID = actorId; this.actorID = actorId;
playerActor = new Player(this, actorId); playerActor = new Player(this, actorId);
actorInstanceList.Add(playerActor); actorInstanceList.Add(playerActor);
} }
public void SetConnection(int type, ClientConnection conn)
{
conn.connType = type;
switch (type)
{
case BasePacket.TYPE_ZONE:
zoneConnection = conn;
break;
case BasePacket.TYPE_CHAT:
chatConnection = conn;
break;
}
}
public bool IsClientConnectionsReady()
{
return (zoneConnection != null && chatConnection != null);
}
public void Disconnect()
{
zoneConnection.Disconnect();
chatConnection.Disconnect();
}
public bool IsDisconnected()
{
return (!zoneConnection.IsConnected() && !chatConnection.IsConnected());
}
public void QueuePacket(BasePacket basePacket) public void QueuePacket(BasePacket basePacket)
{ {
zoneConnection.QueuePacket(basePacket); zoneConnection.QueuePacket(basePacket);

View file

@ -18,15 +18,15 @@ namespace FFXIVClassic_World_Server
public static bool Load() public static bool Load()
{ {
Program.Log.Info("Loading config.ini"); Program.Log.Info("Loading world_config.ini");
if (!File.Exists("./config.ini")) if (!File.Exists("./world_config.ini"))
{ {
Program.Log.Error("FILE NOT FOUND!"); Program.Log.Error("FILE NOT FOUND!");
return false; return false;
} }
INIFile configIni = new INIFile("./config.ini"); INIFile configIni = new INIFile("./world_config.ini");
ConfigConstants.OPTIONS_BINDIP = configIni.GetValue("General", "server_ip", "127.0.0.1"); ConfigConstants.OPTIONS_BINDIP = configIni.GetValue("General", "server_ip", "127.0.0.1");
ConfigConstants.OPTIONS_PORT = configIni.GetValue("General", "server_port", "54992"); ConfigConstants.OPTIONS_PORT = configIni.GetValue("General", "server_port", "54992");

View file

@ -16,6 +16,9 @@ namespace FFXIVClassic_World_Server.DataObjects
public readonly int[] ownedZoneIds; public readonly int[] ownedZoneIds;
public bool isConnected = false; public bool isConnected = false;
public Socket zoneServerConnection; public Socket zoneServerConnection;
private ClientConnection conn;
private byte[] buffer = new byte[0xFFFF];
public ZoneServer(string ip, int port) public ZoneServer(string ip, int port)
{ {
@ -34,6 +37,18 @@ namespace FFXIVClassic_World_Server.DataObjects
{ {
zoneServerConnection.Connect(remoteEP); zoneServerConnection.Connect(remoteEP);
isConnected = true; isConnected = true;
conn = new ClientConnection();
conn.socket = zoneServerConnection;
conn.buffer = new byte[0xFFFF];
try
{
zoneServerConnection.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
}
catch (Exception e)
{
throw new ApplicationException("Error occured starting listeners, check inner exception", e);
}
} }
catch (Exception e) catch (Exception e)
{ Program.Log.Error("Failed to connect"); return; } { Program.Log.Error("Failed to connect"); return; }
@ -54,5 +69,71 @@ namespace FFXIVClassic_World_Server.DataObjects
} }
} }
private void ReceiveCallback(IAsyncResult result)
{
ClientConnection conn = (ClientConnection)result.AsyncState;
//Check if disconnected
if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0))
{
conn = null;
isConnected = false;
Program.Log.Info("Zone server @ {0}:{1} disconnected!", zoneServerIp, zoneServerPort);
return;
}
try
{
int bytesRead = conn.socket.EndReceive(result);
bytesRead += conn.lastPartialSize;
if (bytesRead >= 0)
{
int offset = 0;
//Build packets until can no longer or out of data
while (true)
{
SubPacket subpacket = SubPacket.CreatePacket(ref offset, conn.buffer, bytesRead);
//If can't build packet, break, else process another
if (subpacket == null)
break;
else
Server.GetServer().OnReceiveSubPacketFromZone(this, subpacket);
}
//Not all bytes consumed, transfer leftover to beginning
if (offset < bytesRead)
Array.Copy(conn.buffer, offset, conn.buffer, 0, bytesRead - offset);
conn.lastPartialSize = bytesRead - offset;
//Build any queued subpackets into basepackets and send
conn.FlushQueuedSendPackets();
if (offset < bytesRead)
//Need offset since not all bytes consumed
conn.socket.BeginReceive(conn.buffer, bytesRead - offset, conn.buffer.Length - (bytesRead - offset), SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
else
//All bytes consumed, full buffer available
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
}
else
{
conn = null;
isConnected = false;
Program.Log.Info("Zone server @ {0}:{1} disconnected!", zoneServerIp, zoneServerPort);
}
}
catch (SocketException)
{
conn = null;
isConnected = false;
Program.Log.Info("Zone server @ {0}:{1} disconnected!", zoneServerIp, zoneServerPort);
}
}
} }
} }

View file

@ -53,6 +53,7 @@
<!-- add your logging rules here --> <!-- add your logging rules here -->
<logger name='*' minlevel='Trace' writeTo='file' /> <logger name='*' minlevel='Trace' writeTo='file' />
<logger name='FFXIVClassic_World_Server.Program' minlevel='Trace' writeTo='console' /> <logger name='FFXIVClassic_World_Server.Program' minlevel='Trace' writeTo='console' />
<logger name='FFXIVClassic.Common.*' minlevel='Debug' writeTo='packets' />
<!-- <!--
Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f" Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f"
<logger name="*" minlevel="Debug" writeTo="f" /> <logger name="*" minlevel="Debug" writeTo="f" />

View file

@ -75,6 +75,7 @@ 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);

View file

@ -31,14 +31,18 @@ namespace FFXIVClassic_World_Server.Packets.Send
} }
byte[] reply2Data = { byte[] reply2Data = {
0x66, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xAF, 0x2B, 0x38, 0x2B, 0x5F, 0x26, 0xB8, 0x8D, 0xF0, 0x2B, 0x6c, 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, 0xC8, 0xFD, 0x85, 0xFE, 0xA8, 0x7C, 0x5B, 0x09, 0x38, 0x2B, 0x5F, 0x26, 0xC8, 0xD6, 0xAF, 0x2B,
0xB8, 0x8D, 0xF0, 0x2B, 0x88, 0xAF, 0x5E, 0x26 0xB8, 0x8D, 0xF0, 0x2B, 0x88, 0xAF, 0x5E, 0x26
}; };
data = reply2Data; /*
0x6c, 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
*/
return new SubPacket(false, OPCODE, 0, 0, data); return new SubPacket(false, OPCODE, 0, 0, reply2Data);
} }
} }
} }

View file

@ -77,54 +77,6 @@ namespace FFXIVClassic_World_Server
return true; return true;
} }
#region Socket Handling
private void AcceptCallback(IAsyncResult result)
{
ClientConnection conn = null;
Socket socket = (System.Net.Sockets.Socket)result.AsyncState;
try
{
conn = new ClientConnection();
conn.socket = socket.EndAccept(result);
conn.buffer = new byte[BUFFER_SIZE];
lock (mConnectionList)
{
mConnectionList.Add(conn);
}
Program.Log.Info("Connection {0}:{1} has connected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port);
//Queue recieving of data from the connection
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
//Queue the accept of the next incomming connection
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
}
catch (SocketException)
{
if (conn != null)
{
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
}
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
}
catch (Exception)
{
if (conn != null)
{
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
}
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
}
}
public void AddSession(ClientConnection connection, Session.Channel type, uint id) public void AddSession(ClientConnection connection, Session.Channel type, uint id)
{ {
Session session = new Session(id, connection, type); Session session = new Session(id, connection, type);
@ -182,6 +134,70 @@ namespace FFXIVClassic_World_Server
return null; return null;
} }
public void OnReceiveSubPacketFromZone(ZoneServer zoneServer, SubPacket subpacket)
{
uint sessionId = subpacket.header.targetId;
if (mZoneSessionList.ContainsKey(sessionId))
{
ClientConnection conn = mZoneSessionList[sessionId].clientConnection;
conn.QueuePacket(subpacket, true, false);
}
}
public WorldManager GetWorldManager()
{
return mWorldManager;
}
#region Socket Handling
private void AcceptCallback(IAsyncResult result)
{
ClientConnection conn = null;
Socket socket = (System.Net.Sockets.Socket)result.AsyncState;
try
{
conn = new ClientConnection();
conn.socket = socket.EndAccept(result);
conn.buffer = new byte[BUFFER_SIZE];
lock (mConnectionList)
{
mConnectionList.Add(conn);
}
Program.Log.Info("Connection {0}:{1} has connected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port);
//Queue recieving of data from the connection
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
//Queue the accept of the next incomming connection
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
}
catch (SocketException)
{
if (conn != null)
{
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
}
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
}
catch (Exception)
{
if (conn != null)
{
lock (mConnectionList)
{
mConnectionList.Remove(conn);
}
}
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
}
}
/// <summary> /// <summary>
/// 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. /// 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.
/// </summary> /// </summary>
@ -214,7 +230,7 @@ namespace FFXIVClassic_World_Server
//Build packets until can no longer or out of data //Build packets until can no longer or out of data
while (true) while (true)
{ {
BasePacket basePacket = BuildPacket(ref offset, conn.buffer, bytesRead); BasePacket basePacket = BasePacket.CreatePacket(ref offset, conn.buffer, bytesRead);
//If can't build packet, break, else process another //If can't build packet, break, else process another
if (basePacket == null) if (basePacket == null)
@ -264,48 +280,7 @@ namespace FFXIVClassic_World_Server
} }
} }
/// <summary>
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
/// </summary>
/// <param name="offset">Current offset in buffer.</param>
/// <param name="buffer">Incoming buffer.</param>
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
public BasePacket BuildPacket(ref int offset, byte[] buffer, int bytesRead)
{
BasePacket newPacket = null;
//Too small to even get length
if (bytesRead <= offset)
return null;
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
//Too small to whole packet
if (bytesRead < offset + packetSize)
return null;
if (buffer.Length < offset + packetSize)
return null;
try
{
newPacket = new BasePacket(buffer, ref offset);
}
catch (OverflowException)
{
return null;
}
return newPacket;
}
#endregion #endregion
public WorldManager GetWorldManager()
{
return mWorldManager;
}
} }
} }

View file

@ -14,7 +14,7 @@ namespace FFXIVClassic_World_Server
class WorldManager class WorldManager
{ {
private Server mServer; private Server mServer;
private Dictionary<string, ZoneServer> mZoneServerList; public Dictionary<string, ZoneServer> mZoneServerList;
public WorldManager(Server server) public WorldManager(Server server)
{ {