1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-20 11:47:48 +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); ConnectedPlayer player = null;
List<SubPacket> subPackets = packet.GetSubpackets(); if(mPlayers.ContainsKey(subpacket.header.targetId))
foreach (SubPacket subpacket in subPackets) player = mPlayers[subpacket.header.targetId];
{
if (subpacket.header.type == 0x01)
{
packet.DebugPrintPacket();
byte[] reply1Data = {
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFD, 0xFF, 0xFF,
0xE5, 0x6E, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x0
};
byte[] reply2Data = { if (player == null)
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x38, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x2B, 0x5F, 0x26,
0x66, 0x00, 0x00, 0x00, 0xC8, 0xD6, 0xAF, 0x2B, 0x38, 0x2B, 0x5F, 0x26, 0xB8, 0x8D, 0xF0, 0x2B,
0xC8, 0xFD, 0x85, 0xFE, 0xA8, 0x7C, 0x5B, 0x09, 0x38, 0x2B, 0x5F, 0x26, 0xC8, 0xD6, 0xAF, 0x2B,
0xB8, 0x8D, 0xF0, 0x2B, 0x88, 0xAF, 0x5E, 0x26
};
BasePacket reply1 = new BasePacket(reply1Data);
BasePacket reply2 = new BasePacket(reply2Data);
//Write Timestamp into Reply1
using (MemoryStream mem = new MemoryStream(reply1.data))
{
using (BinaryWriter binReader = new BinaryWriter(mem))
{
binReader.BaseStream.Seek(0x14, SeekOrigin.Begin);
binReader.Write((UInt32)Utils.UnixTimeStampUTC());
}
}
//Read in Actor Id that owns this connection
uint actorID = 0;
using (MemoryStream mem = new MemoryStream(packet.data))
{
using (BinaryReader binReader = new BinaryReader(mem))
{
try
{
byte[] readIn = new byte[12];
binReader.BaseStream.Seek(0x14, SeekOrigin.Begin);
binReader.Read(readIn, 0, 12);
actorID = UInt32.Parse(Encoding.ASCII.GetString(readIn));
}
catch (Exception)
{ }
}
}
//Should never happen.... unless actor id IS 0!
if (actorID == 0)
break;
client.owner = actorID;
//Write Actor ID into reply2
using (MemoryStream mem = new MemoryStream(reply2.data))
{
using (BinaryWriter binReader = new BinaryWriter(mem))
{
binReader.BaseStream.Seek(0x10, SeekOrigin.Begin);
binReader.Write(actorID);
}
}
ConnectedPlayer player = null;
if (packet.header.connectionType == BasePacket.TYPE_ZONE)
{
while (mPlayers != null && !mPlayers.ContainsKey(client.owner))
{ }
player = mPlayers[client.owner];
}
//Create connected player if not Created
if (player == null)
{
player = new ConnectedPlayer(actorID);
mPlayers[actorID] = player;
}
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] player = new ConnectedPlayer(client, subpacket.header.targetId);
//BasePacket init = Login0x7ResponsePacket.BuildPacket(BitConverter.ToUInt32(packet.data, 0x10), Utils.UnixTimeStampUTC(), 0x07); }
//client.QueuePacket(init);
packet.DebugPrintPacket(); subpacket.DebugPrintSubPacket();
}
else if (subpacket.header.type == 0x03) //Normal Game Opcode
switch (subpacket.gameMessage.opcode)
{ {
ConnectedPlayer player = null; //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:
if(mPlayers.ContainsKey(client.owner)) subpacket.DebugPrintSubPacket();
player = mPlayers[client.owner];
player = new ConnectedPlayer(client, subpacket.header.targetId);
mPlayers[subpacket.header.targetId] = player;
client.QueuePacket(_0x2Packet.BuildPacket(player.actorID), true, false);
if (player == null || !player.IsClientConnectionsReady()) Server.GetWorldManager().DoLogin(player.GetActor());
return;
//Normal Game Opcode break;
switch (subpacket.gameMessage.opcode) //Chat Received
{ case 0x0003:
//Ping ChatMessagePacket chatMessage = new ChatMessagePacket(subpacket.data);
case 0x0001: 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(); 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(); if (chatMessage.message.StartsWith("!"))
client.QueuePacket(_0x2Packet.BuildPacket(player.actorID), true, false); {
if (cp.DoCommand(chatMessage.message, player))
return; ;
}
Server.GetWorldManager().DoLogin(player.GetActor()); player.GetActor().BroadcastPacket(SendMessagePacket.BuildPacket(player.actorID, player.actorID, chatMessage.logType, player.GetActor().customDisplayName, chatMessage.message), false);
break;
break; //Langauge Code
//Chat Received case 0x0006:
case 0x0003: LangaugeCodePacket langCode = new LangaugeCodePacket(subpacket.data);
ChatMessagePacket chatMessage = new ChatMessagePacket(subpacket.data); player.languageCode = langCode.languageCode;
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); break;
subpacket.DebugPrintSubPacket(); //Unknown - Happens a lot at login, then once every time player zones
case 0x0007:
if (chatMessage.message.StartsWith("!")) //subpacket.DebugPrintSubPacket();
{ _0x07Packet unknown07 = new _0x07Packet(subpacket.data);
if (cp.DoCommand(chatMessage.message, player)) break;
continue; //Update Position
} case 0x00CA:
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;
}
*/
Actor ownerActor = Server.GetStaticActors(eventStart.scriptOwnerActorID);
player.GetActor().currentEventOwner = eventStart.scriptOwnerActorID; player.GetActor().currentEventOwner = eventStart.scriptOwnerActorID;
player.GetActor().currentEventName = eventStart.triggerName; 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 (ownerActor == null)
{
//Is it a Director?
if (player.GetActor().currentDirector != null && player.GetActor().currentEventOwner == player.GetActor().currentDirector.actorId)
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);
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) if (player.GetActor().currentDirector != null && player.GetActor().currentEventOwner == player.GetActor().currentDirector.actorId)
updateOwnerActor = player.GetActor().currentDirector; ownerActor = player.GetActor().currentDirector;
else
if (updateOwnerActor == null) {
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; break;
} }
*/ }
player.GetActor().UpdateEvent(eventUpdate); }
//LuaEngine.DoActorOnEventUpdated(player.GetActor(), updateOwnerActor, eventUpdate); 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;
if (updateOwnerActor == null)
break;
}
*/
player.GetActor().UpdateEvent(eventUpdate);
//LuaEngine.DoActorOnEventUpdated(player.GetActor(), updateOwnerActor, eventUpdate);
break; break;
case 0x012F: case 0x012F:
//subpacket.DebugPrintSubPacket(); //subpacket.DebugPrintSubPacket();
ParameterDataRequestPacket paramRequest = new ParameterDataRequestPacket(subpacket.data); ParameterDataRequestPacket paramRequest = new ParameterDataRequestPacket(subpacket.data);
if (paramRequest.paramName.Equals("charaWork/exp")) if (paramRequest.paramName.Equals("charaWork/exp"))
player.GetActor().SendCharaExpInfo(); player.GetActor().SendCharaExpInfo();
break; break;
/* RECRUITMENT */ /* RECRUITMENT */
//Start Recruiting //Start Recruiting
case 0x01C3: case 0x01C3:
StartRecruitingRequestPacket recruitRequestPacket = new StartRecruitingRequestPacket(subpacket.data); StartRecruitingRequestPacket recruitRequestPacket = new StartRecruitingRequestPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(StartRecruitingResponse.BuildPacket(player.actorID, true), true, false)); client.QueuePacket(BasePacket.CreatePacket(StartRecruitingResponse.BuildPacket(player.actorID, true), true, false));
break; break;
//End Recruiting //End Recruiting
case 0x01C4: case 0x01C4:
client.QueuePacket(BasePacket.CreatePacket(EndRecruitmentPacket.BuildPacket(player.actorID), true, false)); client.QueuePacket(BasePacket.CreatePacket(EndRecruitmentPacket.BuildPacket(player.actorID), true, false));
break; break;
//Party Window Opened, Request State //Party Window Opened, Request State
case 0x01C5: case 0x01C5:
client.QueuePacket(BasePacket.CreatePacket(RecruiterStatePacket.BuildPacket(player.actorID, true, true, 1), true, false)); client.QueuePacket(BasePacket.CreatePacket(RecruiterStatePacket.BuildPacket(player.actorID, true, true, 1), true, false));
break; break;
//Search Recruiting //Search Recruiting
case 0x01C7: case 0x01C7:
RecruitmentSearchRequestPacket recruitSearchPacket = new RecruitmentSearchRequestPacket(subpacket.data); RecruitmentSearchRequestPacket recruitSearchPacket = new RecruitmentSearchRequestPacket(subpacket.data);
break; break;
//Get Recruitment Details //Get Recruitment Details
case 0x01C8: case 0x01C8:
RecruitmentDetailsRequestPacket currentRecruitDetailsPacket = new RecruitmentDetailsRequestPacket(subpacket.data); RecruitmentDetailsRequestPacket currentRecruitDetailsPacket = new RecruitmentDetailsRequestPacket(subpacket.data);
RecruitmentDetails details = new RecruitmentDetails(); RecruitmentDetails details = new RecruitmentDetails();
details.recruiterName = "Localhost Character"; details.recruiterName = "Localhost Character";
details.purposeId = 2; details.purposeId = 2;
details.locationId = 1; details.locationId = 1;
details.subTaskId = 1; details.subTaskId = 1;
details.comment = "This is a test details packet sent by the server. No implementation has been Created yet..."; details.comment = "This is a test details packet sent by the server. No implementation has been Created yet...";
details.num[0] = 1; details.num[0] = 1;
client.QueuePacket(BasePacket.CreatePacket(CurrentRecruitmentDetailsPacket.BuildPacket(player.actorID, details), true, false)); client.QueuePacket(BasePacket.CreatePacket(CurrentRecruitmentDetailsPacket.BuildPacket(player.actorID, details), true, false));
break; break;
//Accepted Recruiting //Accepted Recruiting
case 0x01C6: case 0x01C6:
subpacket.DebugPrintSubPacket(); subpacket.DebugPrintSubPacket();
break; break;
/* SOCIAL STUFF */ /* SOCIAL STUFF */
case 0x01C9: case 0x01C9:
AddRemoveSocialPacket addBlackList = new AddRemoveSocialPacket(subpacket.data); AddRemoveSocialPacket addBlackList = new AddRemoveSocialPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(BlacklistAddedPacket.BuildPacket(player.actorID, true, addBlackList.name), true, false)); client.QueuePacket(BasePacket.CreatePacket(BlacklistAddedPacket.BuildPacket(player.actorID, true, addBlackList.name), true, false));
break; break;
case 0x01CA: case 0x01CA:
AddRemoveSocialPacket RemoveBlackList = new AddRemoveSocialPacket(subpacket.data); AddRemoveSocialPacket RemoveBlackList = new AddRemoveSocialPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(BlacklistRemovedPacket.BuildPacket(player.actorID, true, RemoveBlackList.name), true, false)); client.QueuePacket(BasePacket.CreatePacket(BlacklistRemovedPacket.BuildPacket(player.actorID, true, RemoveBlackList.name), true, false));
break; break;
case 0x01CB: case 0x01CB:
int offset1 = 0; int offset1 = 0;
client.QueuePacket(BasePacket.CreatePacket(SendBlacklistPacket.BuildPacket(player.actorID, new String[] { "Test" }, ref offset1), true, false)); client.QueuePacket(BasePacket.CreatePacket(SendBlacklistPacket.BuildPacket(player.actorID, new String[] { "Test" }, ref offset1), true, false));
break; break;
case 0x01CC: case 0x01CC:
AddRemoveSocialPacket addFriendList = new AddRemoveSocialPacket(subpacket.data); AddRemoveSocialPacket addFriendList = new AddRemoveSocialPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(FriendlistAddedPacket.BuildPacket(player.actorID, true, (uint)addFriendList.name.GetHashCode(), true, addFriendList.name), true, false)); client.QueuePacket(BasePacket.CreatePacket(FriendlistAddedPacket.BuildPacket(player.actorID, true, (uint)addFriendList.name.GetHashCode(), true, addFriendList.name), true, false));
break; break;
case 0x01CD: case 0x01CD:
AddRemoveSocialPacket RemoveFriendList = new AddRemoveSocialPacket(subpacket.data); AddRemoveSocialPacket RemoveFriendList = new AddRemoveSocialPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(FriendlistRemovedPacket.BuildPacket(player.actorID, true, RemoveFriendList.name), true, false)); client.QueuePacket(BasePacket.CreatePacket(FriendlistRemovedPacket.BuildPacket(player.actorID, true, RemoveFriendList.name), true, false));
break; break;
case 0x01CE: case 0x01CE:
int offset2 = 0; int offset2 = 0;
client.QueuePacket(BasePacket.CreatePacket(SendFriendlistPacket.BuildPacket(player.actorID, new Tuple<long, string>[] { new Tuple<long, string>(01, "Test2") }, ref offset2), 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 0x01CF: case 0x01CF:
client.QueuePacket(BasePacket.CreatePacket(FriendStatusPacket.BuildPacket(player.actorID, null), true, false)); client.QueuePacket(BasePacket.CreatePacket(FriendStatusPacket.BuildPacket(player.actorID, null), true, false));
break; break;
/* SUPPORT DESK STUFF */ /* SUPPORT DESK STUFF */
//Request for FAQ/Info List //Request for FAQ/Info List
case 0x01D0: case 0x01D0:
FaqListRequestPacket faqRequest = new FaqListRequestPacket(subpacket.data); FaqListRequestPacket faqRequest = new FaqListRequestPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(FaqListResponsePacket.BuildPacket(player.actorID, new string[] { "Testing FAQ1", "Coded style!" }), true, false)); client.QueuePacket(BasePacket.CreatePacket(FaqListResponsePacket.BuildPacket(player.actorID, new string[] { "Testing FAQ1", "Coded style!" }), true, false));
break; break;
//Request for body of a faq/info selection //Request for body of a faq/info selection
case 0x01D1: case 0x01D1:
FaqBodyRequestPacket faqBodyRequest = new FaqBodyRequestPacket(subpacket.data); FaqBodyRequestPacket faqBodyRequest = new FaqBodyRequestPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(FaqBodyResponsePacket.BuildPacket(player.actorID, "HERE IS A GIANT BODY. Nothing else to say!"), true, false)); client.QueuePacket(BasePacket.CreatePacket(FaqBodyResponsePacket.BuildPacket(player.actorID, "HERE IS A GIANT BODY. Nothing else to say!"), true, false));
break; break;
//Request issue list //Request issue list
case 0x01D2: case 0x01D2:
GMTicketIssuesRequestPacket issuesRequest = new GMTicketIssuesRequestPacket(subpacket.data); GMTicketIssuesRequestPacket issuesRequest = new GMTicketIssuesRequestPacket(subpacket.data);
client.QueuePacket(BasePacket.CreatePacket(IssueListResponsePacket.BuildPacket(player.actorID, new string[] { "Test1", "Test2", "Test3", "Test4", "Test5" }), true, false)); client.QueuePacket(BasePacket.CreatePacket(IssueListResponsePacket.BuildPacket(player.actorID, new string[] { "Test1", "Test2", "Test3", "Test4", "Test5" }), true, false));
break; break;
//Request if GM ticket exists //Request if GM ticket exists
case 0x01D3: case 0x01D3:
client.QueuePacket(BasePacket.CreatePacket(StartGMTicketPacket.BuildPacket(player.actorID, false), true, false)); client.QueuePacket(BasePacket.CreatePacket(StartGMTicketPacket.BuildPacket(player.actorID, false), true, false));
break; break;
//Request for GM response message //Request for GM response message
case 0x01D4: case 0x01D4:
client.QueuePacket(BasePacket.CreatePacket(GMTicketPacket.BuildPacket(player.actorID, "This is a GM Ticket Title", "This is a GM Ticket Body."), 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;
//GM Ticket Sent //GM Ticket Sent
case 0x01D5: case 0x01D5:
GMSupportTicketPacket gmTicket = new GMSupportTicketPacket(subpacket.data); GMSupportTicketPacket gmTicket = new GMSupportTicketPacket(subpacket.data);
Program.Log.Info("Got GM Ticket: \n" + gmTicket.ticketTitle + "\n" + gmTicket.ticketBody); Program.Log.Info("Got GM Ticket: \n" + gmTicket.ticketTitle + "\n" + gmTicket.ticketBody);
client.QueuePacket(BasePacket.CreatePacket(GMTicketSentResponsePacket.BuildPacket(player.actorID, true), true, false)); client.QueuePacket(BasePacket.CreatePacket(GMTicketSentResponsePacket.BuildPacket(player.actorID, true), true, false));
break; break;
//Request to end ticket //Request to end ticket
case 0x01D6: case 0x01D6:
client.QueuePacket(BasePacket.CreatePacket(EndGMTicketPacket.BuildPacket(player.actorID), true, false)); client.QueuePacket(BasePacket.CreatePacket(EndGMTicketPacket.BuildPacket(player.actorID), true, false));
break; break;
default: default:
Program.Log.Debug("Unknown command 0x{0:X} received.", subpacket.gameMessage.opcode); Program.Log.Debug("Unknown command 0x{0:X} received.", subpacket.gameMessage.opcode);
subpacket.DebugPrintSubPacket(); subpacket.DebugPrintSubPacket();
break; 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,21 +138,18 @@ 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
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn); conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
@ -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);
@ -85,7 +86,7 @@ namespace FFXIVClassic_World_Server
else else
packet.DebugPrintPacket(); packet.DebugPrintPacket();
} }
} }
} }
} }

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

@ -75,55 +75,7 @@ namespace FFXIVClassic_World_Server
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
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)
{ {
@ -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)
{ {