1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-24 05:37:46 +00:00

Implemented equipment and equip graphics. Add some zone callbacks and "first start" functionality. Added playtime.

This commit is contained in:
Filip Maj 2016-03-06 17:55:42 -05:00
parent c9116005d6
commit 44e5430fdc
17 changed files with 676 additions and 129 deletions

View file

@ -63,6 +63,11 @@ namespace FFXIVClassic_Lobby_Server
return String.Format("{0}:{1}", (socket.RemoteEndPoint as IPEndPoint).Address, (socket.RemoteEndPoint as IPEndPoint).Port); return String.Format("{0}:{1}", (socket.RemoteEndPoint as IPEndPoint).Address, (socket.RemoteEndPoint as IPEndPoint).Port);
} }
public bool isConnected()
{
return (socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
public void disconnect() public void disconnect()
{ {
if (socket.Connected) if (socket.Connected)

View file

@ -150,6 +150,132 @@ namespace FFXIVClassic_Lobby_Server
} }
} }
public static void savePlayerAppearance(Player player)
{
string query;
MySqlCommand cmd;
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
query = @"
UPDATE characters_appearance SET
mainHand = @mainHand,
offHand = @offHand,
head = @head,
body = @body,
legs = @legs,
hands = @hands,
feet = @feet,
waist = @waist,
leftFinger = @leftFinger,
rightFinger = @rightFinger,
leftEar = @leftEar,
rightEar = @rightEar
WHERE characterId = @charaId
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@mainHand", player.appearanceIds[Character.MAINHAND]);
cmd.Parameters.AddWithValue("@offHand", player.appearanceIds[Character.OFFHAND]);
cmd.Parameters.AddWithValue("@head", player.appearanceIds[Character.HEADGEAR]);
cmd.Parameters.AddWithValue("@body", player.appearanceIds[Character.BODYGEAR]);
cmd.Parameters.AddWithValue("@legs", player.appearanceIds[Character.LEGSGEAR]);
cmd.Parameters.AddWithValue("@hands", player.appearanceIds[Character.HANDSGEAR]);
cmd.Parameters.AddWithValue("@feet", player.appearanceIds[Character.FEETGEAR]);
cmd.Parameters.AddWithValue("@waist", player.appearanceIds[Character.WAISTGEAR]);
cmd.Parameters.AddWithValue("@leftFinger", player.appearanceIds[Character.L_RINGFINGER]);
cmd.Parameters.AddWithValue("@rightFinger", player.appearanceIds[Character.R_RINGFINGER]);
cmd.Parameters.AddWithValue("@leftEar", player.appearanceIds[Character.L_EAR]);
cmd.Parameters.AddWithValue("@rightEar", player.appearanceIds[Character.R_EAR]);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{ Console.WriteLine(e); }
finally
{
conn.Dispose();
}
}
}
public static void savePlayerPosition(Player player)
{
string query;
MySqlCommand cmd;
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
query = @"
UPDATE characters SET
positionX = @x,
positionY = @y,
positionZ = @z,
rotation = @rot,
currentZoneId = @zoneId
WHERE id = @charaId
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@x", player.positionX);
cmd.Parameters.AddWithValue("@y", player.positionY);
cmd.Parameters.AddWithValue("@z", player.positionZ);
cmd.Parameters.AddWithValue("@rot", player.rotation);
cmd.Parameters.AddWithValue("@zoneId", player.zoneId);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{ Console.WriteLine(e); }
finally
{
conn.Dispose();
}
}
}
public static void savePlayerPlayTime(Player player)
{
string query;
MySqlCommand cmd;
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
query = @"
UPDATE characters SET
playTime = @playtime
WHERE id = @charaId
";
cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
cmd.Parameters.AddWithValue("@playtime", player.getPlayTime(true));
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{ Console.WriteLine(e); }
finally
{
conn.Dispose();
}
}
}
public static void loadPlayerCharacter(Player player) public static void loadPlayerCharacter(Player player)
{ {
string query; string query;
@ -164,7 +290,7 @@ namespace FFXIVClassic_Lobby_Server
//Load basic info //Load basic info
query = @" query = @"
SELECT SELECT
name, name,
positionX, positionX,
positionY, positionY,
positionZ, positionZ,
@ -184,7 +310,8 @@ namespace FFXIVClassic_Lobby_Server
tribe, tribe,
currentParty, currentParty,
restBonus, restBonus,
achievementPoints achievementPoints,
playTime
FROM characters WHERE id = @charId"; FROM characters WHERE id = @charId";
cmd = new MySqlCommand(query, conn); cmd = new MySqlCommand(query, conn);
@ -214,10 +341,11 @@ namespace FFXIVClassic_Lobby_Server
player.playerWork.tribe = reader.GetByte(17); player.playerWork.tribe = reader.GetByte(17);
player.playerWork.restBonusExpRate = reader.GetInt32(19); player.playerWork.restBonusExpRate = reader.GetInt32(19);
player.achievementPoints = reader.GetUInt32(20); player.achievementPoints = reader.GetUInt32(20);
player.playTime = reader.GetUInt32(21);
} }
} }
player.charaWork.parameterSave.state_mainSkillLevel = 49; player.charaWork.parameterSave.state_mainSkillLevel = 50;
/* /*
//Get level of our classjob //Get level of our classjob
@ -312,8 +440,8 @@ namespace FFXIVClassic_Lobby_Server
player.appearanceIds[Character.FACEINFO] = PrimitiveConversion.ToUInt32(CharacterUtils.getFaceInfo(reader.GetByte(8), reader.GetByte(9), reader.GetByte(10), reader.GetByte(11), reader.GetByte(12), reader.GetByte(13), reader.GetByte(14), reader.GetByte(15), reader.GetByte(16), reader.GetByte(17))); player.appearanceIds[Character.FACEINFO] = PrimitiveConversion.ToUInt32(CharacterUtils.getFaceInfo(reader.GetByte(8), reader.GetByte(9), reader.GetByte(10), reader.GetByte(11), reader.GetByte(12), reader.GetByte(13), reader.GetByte(14), reader.GetByte(15), reader.GetByte(16), reader.GetByte(17)));
player.appearanceIds[Character.HIGHLIGHT_HAIR] = (uint)(reader.GetUInt16(6) | reader.GetUInt16(4) << 10); player.appearanceIds[Character.HIGHLIGHT_HAIR] = (uint)(reader.GetUInt16(6) | reader.GetUInt16(4) << 10);
player.appearanceIds[Character.VOICE] = reader.GetByte(2); player.appearanceIds[Character.VOICE] = reader.GetByte(2);
player.appearanceIds[Character.WEAPON1] = reader.GetUInt32(18); player.appearanceIds[Character.MAINHAND] = reader.GetUInt32(18);
player.appearanceIds[Character.WEAPON2] = reader.GetUInt32(19); player.appearanceIds[Character.OFFHAND] = reader.GetUInt32(19);
player.appearanceIds[Character.HEADGEAR] = reader.GetUInt32(20); player.appearanceIds[Character.HEADGEAR] = reader.GetUInt32(20);
player.appearanceIds[Character.BODYGEAR] = reader.GetUInt32(21); player.appearanceIds[Character.BODYGEAR] = reader.GetUInt32(21);
player.appearanceIds[Character.LEGSGEAR] = reader.GetUInt32(22); player.appearanceIds[Character.LEGSGEAR] = reader.GetUInt32(22);
@ -322,8 +450,8 @@ namespace FFXIVClassic_Lobby_Server
player.appearanceIds[Character.WAISTGEAR] = reader.GetUInt32(25); player.appearanceIds[Character.WAISTGEAR] = reader.GetUInt32(25);
player.appearanceIds[Character.R_EAR] = reader.GetUInt32(26); player.appearanceIds[Character.R_EAR] = reader.GetUInt32(26);
player.appearanceIds[Character.L_EAR] = reader.GetUInt32(27); player.appearanceIds[Character.L_EAR] = reader.GetUInt32(27);
player.appearanceIds[Character.R_FINGER] = reader.GetUInt32(28); player.appearanceIds[Character.R_RINGFINGER] = reader.GetUInt32(28);
player.appearanceIds[Character.L_FINGER] = reader.GetUInt32(29); player.appearanceIds[Character.L_RINGFINGER] = reader.GetUInt32(29);
} }
} }
@ -947,5 +1075,6 @@ namespace FFXIVClassic_Lobby_Server
return cheevosPacket.buildPacket(player.actorId); return cheevosPacket.buildPacket(player.actorId);
} }
} }
} }

View file

@ -146,8 +146,6 @@ namespace FFXIVClassic_Lobby_Server
} }
else if (subpacket.header.type == 0x07) else if (subpacket.header.type == 0x07)
{ {
//Ping?
//packet.debugPrintPacket();
BasePacket init = Login0x7ResponsePacket.buildPacket(BitConverter.ToUInt32(packet.data, 0x10), Utils.UnixTimeStampUTC()); BasePacket init = Login0x7ResponsePacket.buildPacket(BitConverter.ToUInt32(packet.data, 0x10), Utils.UnixTimeStampUTC());
//client.queuePacket(init); //client.queuePacket(init);
} }
@ -174,6 +172,7 @@ namespace FFXIVClassic_Lobby_Server
//subpacket.debugPrintSubPacket(); //subpacket.debugPrintSubPacket();
PingPacket pingPacket = new PingPacket(subpacket.data); PingPacket pingPacket = new PingPacket(subpacket.data);
client.queuePacket(BasePacket.createPacket(PongPacket.buildPacket(player.actorID, pingPacket.time), true, false)); client.queuePacket(BasePacket.createPacket(PongPacket.buildPacket(player.actorID, pingPacket.time), true, false));
player.ping();
break; break;
//Unknown //Unknown
case 0x0002: case 0x0002:
@ -254,7 +253,7 @@ namespace FFXIVClassic_Lobby_Server
} }
} }
mServer.GetLuaEngine().doActorOnEventStarted(player.getActor(), ownerActor, eventStart); LuaEngine.doActorOnEventStarted(player.getActor(), ownerActor, eventStart);
Log.debug(String.Format("\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.eventStarter, LuaUtils.dumpParams(eventStart.luaParams))); Log.debug(String.Format("\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.eventStarter, LuaUtils.dumpParams(eventStart.luaParams)));
break; break;
@ -273,7 +272,7 @@ namespace FFXIVClassic_Lobby_Server
break; break;
} }
mServer.GetLuaEngine().doActorOnEventUpdated(player.getActor(), updateOwnerActor, eventUpdate); LuaEngine.doActorOnEventUpdated(player.getActor(), updateOwnerActor, eventUpdate);
break; break;
case 0x012F: case 0x012F:

View file

@ -23,6 +23,14 @@ namespace FFXIVClassic_Lobby_Server
#endif #endif
bool startServer = true; bool startServer = true;
Utils.FFXIVLoginStringDecodeBinary("C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV\\ffxivlogin.exe");
Console.WriteLine(Utils.FFXIVLoginStringDecode(new byte[]{0x6F, 0xD6, 0x3C, 0xD6, 0x20, 0x81, 0x3F, 0x06, 0x36, 0x78, 0xD3, 0xAE, 0xDB, 0x4E, 0x08, 0xF1, 0x7D, 0xAE, 0x90, 0x43, 0x18, 0x70, 0x32, 0x08, 0x6B, 0x75, 0x98, 0xA1, 0x51, 0x15, 0xA9, 0xF7, 0x74, 0xB3, 0x6F, 0x10, 0xEA, 0x76, 0x34, 0x0B, 0x7E, 0x2D, 0xD2, 0xAC, 0xD7, 0xC3, 0xD3, 0xC1, 0x4D, 0x96, 0xED, 0xD4, 0xCC, 0x5E, 0x0D, 0xF5, 0x7E, 0x35, 0x99, 0xB9, 0x57, 0x38, 0x51, 0x79, 0x39, 0x3F, 0x08, 0xFB, 0xE8, 0xEE, 0x25, 0x4F, 0xAE, 0xE2, 0xFC, 0x7E, 0x2A, 0x72, 0x34, 0x57, 0x7E}));
Console.WriteLine(Utils.ByteArrayToHex(Utils.FFXIVLoginStringEncode(0xd018, "http://141.117.163.26/login/")));
return;
Console.ForegroundColor = ConsoleColor.Cyan; Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("---------FFXIV 1.0 Map Server---------"); Console.WriteLine("---------FFXIV 1.0 Map Server---------");
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;

View file

@ -25,6 +25,8 @@ namespace FFXIVClassic_Lobby_Server
public const int FFXIV_MAP_PORT = 54992; public const int FFXIV_MAP_PORT = 54992;
public const int BUFFER_SIZE = 0xFFFF; //Max basepacket size is 0xFFFF public const int BUFFER_SIZE = 0xFFFF; //Max basepacket size is 0xFFFF
public const int BACKLOG = 100; public const int BACKLOG = 100;
public const int HEALTH_THREAD_SLEEP_TIME = 5;
public const string STATIC_ACTORS_PATH = "./staticactors.bin"; public const string STATIC_ACTORS_PATH = "./staticactors.bin";
private static Server mSelf; private static Server mSelf;
@ -41,6 +43,30 @@ namespace FFXIVClassic_Lobby_Server
private PacketProcessor mProcessor; private PacketProcessor mProcessor;
private Thread mConnectionHealthThread;
private bool killHealthThread = false;
private void connectionHealth()
{
Log.info(String.Format("Connection Health thread started; it will run every {0} seconds.", HEALTH_THREAD_SLEEP_TIME));
while (!killHealthThread)
{
lock (mConnectedPlayerList)
{
List<ConnectedPlayer> dcedPlayers = new List<ConnectedPlayer>();
foreach (ConnectedPlayer cp in mConnectedPlayerList.Values)
{
if (cp.checkIfDCing())
dcedPlayers.Add(cp);
}
foreach (ConnectedPlayer cp in dcedPlayers)
cp.getActor().cleanupAndSave();
}
Thread.Sleep(HEALTH_THREAD_SLEEP_TIME * 1000);
}
}
public Server() public Server()
{ {
mSelf = this; mSelf = this;
@ -53,6 +79,10 @@ namespace FFXIVClassic_Lobby_Server
public bool startServer() public bool startServer()
{ {
mConnectionHealthThread = new Thread(new ThreadStart(connectionHealth));
mConnectionHealthThread.Name = "MapThread:Health";
//mConnectionHealthThread.Start();
mStaticActors = new StaticActors(STATIC_ACTORS_PATH); mStaticActors = new StaticActors(STATIC_ACTORS_PATH);
gamedataItems = Database.getItemGamedata(); gamedataItems = Database.getItemGamedata();
@ -102,6 +132,15 @@ namespace FFXIVClassic_Lobby_Server
return true; return true;
} }
public void removePlayer(Player player)
{
lock (mConnectedPlayerList)
{
if (mConnectedPlayerList.ContainsKey(player.actorId))
mConnectedPlayerList.Remove(player.actorId);
}
}
#region Socket Handling #region Socket Handling
private void acceptCallback(IAsyncResult result) private void acceptCallback(IAsyncResult result)
{ {
@ -411,17 +450,11 @@ namespace FFXIVClassic_Lobby_Server
} }
} }
public LuaEngine GetLuaEngine()
{
return mLuaEngine;
}
public WorldManager GetWorldManager() public WorldManager GetWorldManager()
{ {
return mWorldManager; return mWorldManager;
} }
public void printPos(ConnectedPlayer client) public void printPos(ConnectedPlayer client)
{ {
if (client != null) if (client != null)
@ -439,19 +472,36 @@ namespace FFXIVClassic_Lobby_Server
} }
} }
private void giveItem(ConnectedPlayer client, uint itemId, int quantity) private void setGraphic(ConnectedPlayer client, uint slot, uint wId, uint eId, uint vId, uint cId)
{ {
if (client != null) if (client != null)
{ {
Player p = client.getActor(); Player p = client.getActor();
p.getInventory(Inventory.NORMAL).addItem(itemId, quantity, 1); p.graphicChange(slot, wId, eId, vId, cId);
} }
else else
{ {
foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList) foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList)
{ {
Player p = entry.Value.getActor(); Player p = entry.Value.getActor();
p.getInventory(Inventory.NORMAL).addItem(itemId, quantity, 1); p.graphicChange(slot, wId, eId, vId, cId);
}
}
}
private void giveItem(ConnectedPlayer client, uint itemId, int quantity)
{
if (client != null)
{
Player p = client.getActor();
p.getInventory(Inventory.NORMAL).addItem(itemId, quantity);
}
else
{
foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList)
{
Player p = entry.Value.getActor();
p.getInventory(Inventory.NORMAL).addItem(itemId, quantity);
} }
} }
} }
@ -463,7 +513,7 @@ namespace FFXIVClassic_Lobby_Server
Player p = client.getActor(); Player p = client.getActor();
if (p.getInventory(type) != null) if (p.getInventory(type) != null)
p.getInventory(type).addItem(itemId, quantity, 1); p.getInventory(type).addItem(itemId, quantity);
} }
else else
{ {
@ -472,7 +522,7 @@ namespace FFXIVClassic_Lobby_Server
Player p = entry.Value.getActor(); Player p = entry.Value.getActor();
if (p.getInventory(type) != null) if (p.getInventory(type) != null)
p.getInventory(type).addItem(itemId, quantity, 1); p.getInventory(type).addItem(itemId, quantity);
} }
} }
} }
@ -520,14 +570,14 @@ namespace FFXIVClassic_Lobby_Server
if (client != null) if (client != null)
{ {
Player p = client.getActor(); Player p = client.getActor();
p.getInventory(Inventory.CURRANCY).addItem(itemId, quantity, 1); p.getInventory(Inventory.CURRANCY).addItem(itemId, quantity);
} }
else else
{ {
foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList) foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList)
{ {
Player p = entry.Value.getActor(); Player p = entry.Value.getActor();
p.getInventory(Inventory.CURRANCY).addItem(itemId, quantity, 1); p.getInventory(Inventory.CURRANCY).addItem(itemId, quantity);
} }
} }
} }
@ -554,14 +604,14 @@ namespace FFXIVClassic_Lobby_Server
if (client != null) if (client != null)
{ {
Player p = client.getActor(); Player p = client.getActor();
p.getInventory(Inventory.KEYITEMS).addItem(itemId, 1, 1); p.getInventory(Inventory.KEYITEMS).addItem(itemId, 1);
} }
else else
{ {
foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList) foreach (KeyValuePair<uint, ConnectedPlayer> entry in mConnectedPlayerList)
{ {
Player p = entry.Value.getActor(); Player p = entry.Value.getActor();
p.getInventory(Inventory.KEYITEMS).addItem(itemId, 1, 1); p.getInventory(Inventory.KEYITEMS).addItem(itemId, 1);
} }
} }
} }
@ -618,6 +668,18 @@ namespace FFXIVClassic_Lobby_Server
mWorldManager.reloadZone(client.getActor().zoneId); mWorldManager.reloadZone(client.getActor().zoneId);
return true; return true;
} }
else if (split[0].Equals("reloaditems"))
{
Log.info(String.Format("Got request to reload item gamedata"));
if (client != null)
client.getActor().queuePacket(SendMessagePacket.buildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", "Reloading Item Gamedata..."));
gamedataItems.Clear();
gamedataItems = Database.getItemGamedata();
Log.info(String.Format("Loaded {0} items.", gamedataItems.Count));
if (client != null)
client.getActor().queuePacket(SendMessagePacket.buildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", String.Format("Loaded {0} items.", gamedataItems.Count)));
return true;
}
else if (split[0].Equals("sendpacket")) else if (split[0].Equals("sendpacket"))
{ {
if (split.Length < 2) if (split.Length < 2)
@ -633,6 +695,19 @@ namespace FFXIVClassic_Lobby_Server
Log.error("Could not load packet: " + e); Log.error("Could not load packet: " + e);
} }
} }
else if (split[0].Equals("graphic"))
{
try
{
if (split.Length == 6)
setGraphic(client, UInt32.Parse(split[1]), UInt32.Parse(split[2]), UInt32.Parse(split[3]), UInt32.Parse(split[4]), UInt32.Parse(split[5]));
return true;
}
catch (Exception e)
{
Log.error("Could not give item.");
}
}
else if (split[0].Equals("giveitem")) else if (split[0].Equals("giveitem"))
{ {
try try
@ -755,7 +830,7 @@ namespace FFXIVClassic_Lobby_Server
} }
else if (split[0].Equals("property")) else if (split[0].Equals("property"))
{ {
if (split.Length == 5) if (split.Length == 4)
testCodePacket(Utils.MurmurHash2(split[1], 0), Convert.ToUInt32(split[2], 16), split[3]); testCodePacket(Utils.MurmurHash2(split[1], 0), Convert.ToUInt32(split[2], 16), split[3]);
return true; return true;
} }

View file

@ -5,6 +5,7 @@ using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.common.EfficientHashTables; using FFXIVClassic_Map_Server.common.EfficientHashTables;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.dataobjects.chara; using FFXIVClassic_Map_Server.dataobjects.chara;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send; using FFXIVClassic_Map_Server.packets.send;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.packets.send.login; using FFXIVClassic_Map_Server.packets.send.login;
@ -275,7 +276,7 @@ namespace FFXIVClassic_Map_Server
if (player.zone != null) if (player.zone != null)
{ {
oldZone = player.zone; oldZone = player.zone;
oldZone.removeActorToZone(player); oldZone.removeActorFromZone(player);
} }
//Add player to new zone and update //Add player to new zone and update
@ -286,6 +287,8 @@ namespace FFXIVClassic_Map_Server
return; return;
newZone.addActorToZone(player); newZone.addActorToZone(player);
LuaEngine.onZoneIn(player);
} }
//Moves actor to new zone, and sends packets to spawn at the given zone entrance //Moves actor to new zone, and sends packets to spawn at the given zone entrance
@ -310,7 +313,7 @@ namespace FFXIVClassic_Map_Server
if (player.zone != null) if (player.zone != null)
{ {
oldZone = player.zone; oldZone = player.zone;
oldZone.removeActorToZone(player); oldZone.removeActorFromZone(player);
} }
//Add player to new zone and update //Add player to new zone and update
@ -336,6 +339,8 @@ namespace FFXIVClassic_Map_Server
player.sendZoneInPackets(this, spawnType); player.sendZoneInPackets(this, spawnType);
player.playerSession.clearInstance(); player.playerSession.clearInstance();
player.sendInstanceUpdate(); player.sendInstanceUpdate();
LuaEngine.onZoneIn(player);
} }
//Login Zone In //Login Zone In
@ -351,13 +356,16 @@ namespace FFXIVClassic_Map_Server
//Set the current zone and add player //Set the current zone and add player
player.zone = zone; player.zone = zone;
zone.addActorToZone(player); zone.addActorToZone(player);
//Send packets //Send packets
player.playerSession.queuePacket(DeleteAllActorsPacket.buildPacket(player.actorId), true, false); player.playerSession.queuePacket(DeleteAllActorsPacket.buildPacket(player.actorId), true, false);
player.playerSession.queuePacket(_0x2Packet.buildPacket(player.actorId), true, false); player.playerSession.queuePacket(_0x2Packet.buildPacket(player.actorId), true, false);
player.sendZoneInPackets(this, 0x1); player.sendZoneInPackets(this, 0x1);
player.playerSession.clearInstance(); player.playerSession.clearInstance();
player.sendInstanceUpdate(); player.sendInstanceUpdate();
LuaEngine.onLogin(player);
LuaEngine.onZoneIn(player);
} }
public void reloadZone(uint zoneId) public void reloadZone(uint zoneId)

View file

@ -4,6 +4,7 @@ using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.dataobjects.chara; using FFXIVClassic_Map_Server.dataobjects.chara;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using MoonSharp.Interpreter;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -20,7 +21,6 @@ namespace FFXIVClassic_Map_Server.Actors
public ushort weatherNormal, weatherCommon, weatherRare; public ushort weatherNormal, weatherCommon, weatherRare;
public ushort bgmDay, bgmNight, bgmBattle; public ushort bgmDay, bgmNight, bgmBattle;
private string classPath; private string classPath;
public int boundingGridSize = 50; public int boundingGridSize = 50;
@ -31,6 +31,8 @@ namespace FFXIVClassic_Map_Server.Actors
private Dictionary<uint, Actor> mActorList = new Dictionary<uint,Actor>(); private Dictionary<uint, Actor> mActorList = new Dictionary<uint,Actor>();
private List<Actor>[,] mActorBlock; private List<Actor>[,] mActorBlock;
Script areaScript;
public Area(uint id, string zoneName, ushort regionId, string className, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid) public Area(uint id, string zoneName, ushort regionId, string className, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid)
: base(id) : base(id)
{ {
@ -66,7 +68,7 @@ namespace FFXIVClassic_Map_Server.Actors
mActorBlock[x, y] = new List<Actor>(); mActorBlock[x, y] = new List<Actor>();
} }
} }
} }
public override SubPacket createScriptBindPacket(uint playerActorId) public override SubPacket createScriptBindPacket(uint playerActorId)
@ -117,7 +119,7 @@ namespace FFXIVClassic_Map_Server.Actors
mActorBlock[gridX, gridY].Add(actor); mActorBlock[gridX, gridY].Add(actor);
} }
public void removeActorToZone(Actor actor) public void removeActorFromZone(Actor actor)
{ {
mActorList.Remove(actor.actorId); mActorList.Remove(actor.actorId);

View file

@ -16,29 +16,32 @@ namespace FFXIVClassic_Map_Server.Actors
public const int FACEINFO = 2; public const int FACEINFO = 2;
public const int HIGHLIGHT_HAIR = 3; public const int HIGHLIGHT_HAIR = 3;
public const int VOICE = 4; public const int VOICE = 4;
public const int WEAPON1 = 5; public const int MAINHAND = 5;
public const int WEAPON2 = 6; public const int OFFHAND = 6;
public const int WEAPON3 = 7; public const int SPMAINHAND = 7;
public const int UNKNOWN1 = 8; public const int SPOFFHAND = 8;
public const int UNKNOWN2 = 9; public const int THROWING = 9;
public const int UNKNOWN3 = 10; public const int PACK = 10;
public const int UNKNOWN4 = 11; public const int POUCH = 11;
public const int HEADGEAR = 12; public const int HEADGEAR = 12;
public const int BODYGEAR = 13; public const int BODYGEAR = 13;
public const int LEGSGEAR = 14; public const int LEGSGEAR = 14;
public const int HANDSGEAR = 15; public const int HANDSGEAR = 15;
public const int FEETGEAR = 16; public const int FEETGEAR = 16;
public const int WAISTGEAR = 17; public const int WAISTGEAR = 17;
public const int UNKNOWN5 = 18; public const int NECKGEAR = 18;
public const int R_EAR = 19; public const int L_EAR = 19;
public const int L_EAR = 20; public const int R_EAR = 20;
public const int UNKNOWN6 = 21; public const int R_WRIST = 21;
public const int UNKNOWN7 = 22; public const int L_WRIST = 22;
public const int R_FINGER = 23; public const int R_RINGFINGER = 23;
public const int L_FINGER = 24; public const int L_RINGFINGER = 24;
public const int R_INDEXFINGER = 25;
public const int L_INDEXFINGER = 26;
public const int UNKNOWN = 27;
public uint modelId; public uint modelId;
public uint[] appearanceIds = new uint[0x1D]; public uint[] appearanceIds = new uint[28];
public uint animationId = 0; public uint animationId = 0;

View file

@ -49,9 +49,8 @@ namespace FFXIVClassic_Map_Server.Actors
{ {
List<LuaParam> lParams; List<LuaParam> lParams;
LuaEngine lua = Server.getServer().GetLuaEngine();
Player player = Server.getServer().GetWorldManager().GetPCInWorld(playerActorId); Player player = Server.getServer().GetWorldManager().GetPCInWorld(playerActorId);
lParams = lua.doActorOnInstantiate(player, this); lParams = LuaEngine.doActorOnInstantiate(player, this);
if (lParams == null) if (lParams == null)
{ {
@ -154,7 +153,7 @@ namespace FFXIVClassic_Map_Server.Actors
appearanceIds[Character.FACEINFO] = PrimitiveConversion.ToUInt32(CharacterUtils.getFaceInfo(reader.GetByte(6), reader.GetByte(7), reader.GetByte(5), reader.GetByte(14), reader.GetByte(13), reader.GetByte(12), reader.GetByte(11), reader.GetByte(10), reader.GetByte(9), reader.GetByte(8))); appearanceIds[Character.FACEINFO] = PrimitiveConversion.ToUInt32(CharacterUtils.getFaceInfo(reader.GetByte(6), reader.GetByte(7), reader.GetByte(5), reader.GetByte(14), reader.GetByte(13), reader.GetByte(12), reader.GetByte(11), reader.GetByte(10), reader.GetByte(9), reader.GetByte(8)));
appearanceIds[Character.HIGHLIGHT_HAIR] = (uint)(reader.GetUInt32(3) | reader.GetUInt32(2) << 10); //5- Hair Highlight, 4 - Hair Style appearanceIds[Character.HIGHLIGHT_HAIR] = (uint)(reader.GetUInt32(3) | reader.GetUInt32(2) << 10); //5- Hair Highlight, 4 - Hair Style
appearanceIds[Character.VOICE] = reader.GetUInt32(17); appearanceIds[Character.VOICE] = reader.GetUInt32(17);
appearanceIds[Character.WEAPON1] = reader.GetUInt32(19); appearanceIds[Character.MAINHAND] = reader.GetUInt32(19);
//appearanceIds[Character.WEAPON2] = reader.GetUInt32(22); //appearanceIds[Character.WEAPON2] = reader.GetUInt32(22);
appearanceIds[Character.HEADGEAR] = reader.GetUInt32(26); appearanceIds[Character.HEADGEAR] = reader.GetUInt32(26);
appearanceIds[Character.BODYGEAR] = reader.GetUInt32(27); appearanceIds[Character.BODYGEAR] = reader.GetUInt32(27);
@ -164,8 +163,8 @@ namespace FFXIVClassic_Map_Server.Actors
appearanceIds[Character.WAISTGEAR] = reader.GetUInt32(31); appearanceIds[Character.WAISTGEAR] = reader.GetUInt32(31);
appearanceIds[Character.R_EAR] = reader.GetUInt32(32); appearanceIds[Character.R_EAR] = reader.GetUInt32(32);
appearanceIds[Character.L_EAR] = reader.GetUInt32(33); appearanceIds[Character.L_EAR] = reader.GetUInt32(33);
appearanceIds[Character.R_FINGER] = reader.GetUInt32(36); appearanceIds[Character.R_RINGFINGER] = reader.GetUInt32(36);
appearanceIds[Character.L_FINGER] = reader.GetUInt32(37); appearanceIds[Character.L_RINGFINGER] = reader.GetUInt32(37);
} }
} }

View file

@ -13,24 +13,24 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
{ {
class Equipment class Equipment
{ {
public const int SLOT_MAINHAND = 0x00; public const int SLOT_MAINHAND = 0;
public const int SLOT_OFFHAND = 0x01; public const int SLOT_OFFHAND = 1;
public const int SLOT_THROWINGWEAPON = 0x04; public const int SLOT_THROWINGWEAPON = 4;
public const int SLOT_PACK = 0x05; public const int SLOT_PACK = 5;
public const int SLOT_POUCH = 0x06; public const int SLOT_POUCH = 6;
public const int SLOT_HEAD = 0x08; public const int SLOT_HEAD = 8;
public const int SLOT_UNDERSHIRT = 0x09; public const int SLOT_UNDERSHIRT = 9;
public const int SLOT_BODY = 0x0A; public const int SLOT_BODY = 10;
public const int SLOT_UNDERGARMENT = 0x0B; public const int SLOT_UNDERGARMENT = 11;
public const int SLOT_LEGS = 0x0C; public const int SLOT_LEGS = 12;
public const int SLOT_HANDS = 0x0D; public const int SLOT_HANDS = 13;
public const int SLOT_BOOTS = 0x0E; public const int SLOT_BOOTS = 14;
public const int SLOT_WAIST = 0x0F; public const int SLOT_WAIST = 15;
public const int SLOT_NECK = 0x10; public const int SLOT_NECK = 16;
public const int SLOT_EARS = 0x11; public const int SLOT_EARS = 17;
public const int SLOT_WRISTS = 0x13; public const int SLOT_WRISTS = 19;
public const int SLOT_RIGHTFINGER = 0x15; public const int SLOT_RIGHTFINGER = 21;
public const int SLOT_LEFTFINGER = 0x16; public const int SLOT_LEFTFINGER = 22;
private Player owner; private Player owner;
private ushort inventoryCapacity; private ushort inventoryCapacity;
@ -71,6 +71,27 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
owner.queuePacket(InventorySetEndPacket.buildPacket(owner.actorId)); owner.queuePacket(InventorySetEndPacket.buildPacket(owner.actorId));
} }
public void SetEquipment(ushort[] slots, ushort[] itemSlots)
{
if (slots.Length != itemSlots.Length)
return;
for (int i = 0; i < slots.Length; i++)
{
InventoryItem item = normalInventory.getItem(itemSlots[i]);
if (item == null)
continue;
Database.equipItem(owner, slots[i], itemSlots[i]);
list[slots[i]] = normalInventory.getItem(itemSlots[i]);
}
owner.queuePacket(InventoryBeginChangePacket.buildPacket(owner.actorId));
SendFullEquipment(false);
owner.queuePacket(InventoryEndChangePacket.buildPacket(owner.actorId));
}
public void SetEquipment(List<Tuple<ushort, InventoryItem>> toEquip) public void SetEquipment(List<Tuple<ushort, InventoryItem>> toEquip)
{ {
List<ushort> slotsToUpdate = new List<ushort>(); List<ushort> slotsToUpdate = new List<ushort>();
@ -81,6 +102,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
} }
} }
public void Equip(ushort slot, ushort invSlot)
{
InventoryItem item = normalInventory.getItem(invSlot);
if (item == null)
return;
Equip(slot, item);
}
public void Equip(ushort slot, InventoryItem item) public void Equip(ushort slot, InventoryItem item)
{ {
if (slot >= list.Length) if (slot >= list.Length)

View file

@ -70,6 +70,16 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
owner.queuePacket(InventorySetEndPacket.buildPacket(owner.actorId)); owner.queuePacket(InventorySetEndPacket.buildPacket(owner.actorId));
} }
public void addItem(uint itemId)
{
addItem(itemId, 1, 1);
}
public void addItem(uint itemId, int quantity)
{
addItem(itemId, quantity, 1);
}
public void addItem(uint itemId, int quantity, byte quality) public void addItem(uint itemId, int quantity, byte quality)
{ {
if (!isSpaceForAdd(itemId, quantity)) if (!isSpaceForAdd(itemId, quantity))
@ -119,7 +129,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
//New item that spilled over //New item that spilled over
while (quantityCount > 0) while (quantityCount > 0)
{ {
InventoryItem addedItem = Database.addItem(owner, itemId, Math.Min(quantityCount, 5), quality, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability, inventoryCode); InventoryItem addedItem = Database.addItem(owner, itemId, Math.Min(quantityCount, gItem.maxStack), quality, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability, inventoryCode);
list.Add(addedItem); list.Add(addedItem);
@ -137,6 +147,31 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
owner.queuePacket(InventoryEndChangePacket.buildPacket(owner.actorId)); owner.queuePacket(InventoryEndChangePacket.buildPacket(owner.actorId));
} }
public void addItem(uint[] itemId)
{
if (!isSpaceForAdd(itemId[0], itemId.Length))
return;
//Update lists and db
owner.queuePacket(InventoryBeginChangePacket.buildPacket(owner.actorId));
owner.queuePacket(InventorySetBeginPacket.buildPacket(owner.actorId, inventoryCapacity, inventoryCode));
int startPos = list.Count;
//New item that spilled over
for (int i = 0; i < itemId.Length; i++)
{
Item gItem = Server.getItemGamedata(itemId[i]);
InventoryItem addedItem = Database.addItem(owner, itemId[i], 1, (byte)1, gItem.isExclusive ? (byte)0x3 : (byte)0x0, gItem.durability, inventoryCode);
list.Add(addedItem);
}
sendInventoryPackets(startPos);
owner.queuePacket(InventorySetEndPacket.buildPacket(owner.actorId));
owner.queuePacket(InventoryEndChangePacket.buildPacket(owner.actorId));
}
public void removeItem(uint itemId, int quantity) public void removeItem(uint itemId, int quantity)
{ {
if (!hasItem(itemId, quantity)) if (!hasItem(itemId, quantity))

View file

@ -59,6 +59,9 @@ namespace FFXIVClassic_Map_Server.Actors
public uint[] timers = new uint[20]; public uint[] timers = new uint[20];
public ushort currentJob; public ushort currentJob;
public uint currentTitle; public uint currentTitle;
public uint playTime;
public uint lastPlayTimeUpdate;
public bool isGM = false;
//Inventory //Inventory
private Dictionary<ushort, Inventory> inventories = new Dictionary<ushort, Inventory>(); private Dictionary<ushort, Inventory> inventories = new Dictionary<ushort, Inventory>();
@ -162,6 +165,7 @@ namespace FFXIVClassic_Map_Server.Actors
charaWork.parameterTemp.tp = 3000; charaWork.parameterTemp.tp = 3000;
Database.loadPlayerCharacter(this); Database.loadPlayerCharacter(this);
lastPlayTimeUpdate = Utils.UnixTimeStampUTC();
} }
public List<SubPacket> create0x132Packets(uint playerActorId) public List<SubPacket> create0x132Packets(uint playerActorId)
@ -545,6 +549,34 @@ namespace FFXIVClassic_Map_Server.Actors
} }
} }
public void setDCFlag(bool flag)
{
if (flag)
{
broadcastPacket(SetActorIconPacket.buildPacket(actorId, actorId, SetActorIconPacket.DISCONNECTING), true);
}
else
{
if (isGM)
broadcastPacket(SetActorIconPacket.buildPacket(actorId, actorId, SetActorIconPacket.ISGM), true);
else
broadcastPacket(SetActorIconPacket.buildPacket(actorId, actorId, 0), true);
}
}
public void cleanupAndSave()
{
//Remove actor from zone and main server list
zone.removeActorFromZone(this);
Server.getServer().removePlayer(this);
//Save Player
Database.savePlayerPlayTime(this);
Database.savePlayerPosition(this);
Log.info(String.Format("{0} has been logged out and saved.", this.customDisplayName));
}
public Zone getZone() public Zone getZone()
{ {
return zone; return zone;
@ -558,11 +590,25 @@ namespace FFXIVClassic_Map_Server.Actors
public void logout() public void logout()
{ {
queuePacket(LogoutPacket.buildPacket(actorId)); queuePacket(LogoutPacket.buildPacket(actorId));
cleanupAndSave();
} }
public void quitGame() public void quitGame()
{ {
queuePacket(QuitPacket.buildPacket(actorId)); queuePacket(QuitPacket.buildPacket(actorId));
cleanupAndSave();
}
public uint getPlayTime(bool doUpdate)
{
if (doUpdate)
{
uint curTime = Utils.UnixTimeStampUTC();
playTime += curTime - lastPlayTimeUpdate;
lastPlayTimeUpdate = curTime;
}
return playTime;
} }
public void changeMusic(ushort musicId) public void changeMusic(ushort musicId)
@ -635,33 +681,62 @@ namespace FFXIVClassic_Map_Server.Actors
//zone.broadcastPacketAroundActor(this, worldMasterMessage); //zone.broadcastPacketAroundActor(this, worldMasterMessage);
} }
public void graphicChange(uint slot, uint graphicId)
{
appearanceIds[slot] = graphicId;
broadcastPacket(createAppearancePacket(actorId), true);
}
public void graphicChange(uint slot, uint weapId, uint equipId, uint variantId, uint colorId)
{
uint mixedVariantId;
if (weapId == 0)
mixedVariantId = ((variantId & 0x1F) << 5) | colorId;
else
mixedVariantId = variantId;
uint graphicId =
(weapId & 0x3FF) << 20 |
(equipId & 0x3FF) << 10 |
(mixedVariantId & 0x3FF);
appearanceIds[slot] = graphicId;
broadcastPacket(createAppearancePacket(actorId), true);
}
public void graphicChange(int slot, InventoryItem invItem) public void graphicChange(int slot, InventoryItem invItem)
{ {
Item item = Server.getItemGamedata(invItem.itemId); if (invItem == null)
appearanceIds[slot] = 0;
if (item == null) else
{ {
Item item = Server.getItemGamedata(invItem.itemId);
} if (item is EquipmentItem)
else if (item is EquipmentItem)
{
EquipmentItem eqItem = (EquipmentItem)item;
uint graphicId;
if (eqItem.graphicsWeaponId == null || eqItem.graphicsEquipmentId == null || eqItem.graphicsVariantId == null)
graphicId = 1025;
else
{ {
graphicId = EquipmentItem eqItem = (EquipmentItem)item;
eqItem.graphicsWeaponId << 20 |
eqItem.graphicsEquipmentId << 10 | uint mixedVariantId;
eqItem.graphicsVariantId << 5 |
eqItem.graphicsColorId << 5; if (eqItem.graphicsWeaponId == 0)
mixedVariantId = ((eqItem.graphicsVariantId & 0x1F) << 5) | eqItem.graphicsColorId;
else
mixedVariantId = eqItem.graphicsVariantId;
uint graphicId =
(eqItem.graphicsWeaponId & 0x3FF) << 20 |
(eqItem.graphicsEquipmentId & 0x3FF) << 10 |
(mixedVariantId & 0x3FF);
appearanceIds[slot] = graphicId;
} }
appearanceIds[BODYGEAR] = graphicId; }
broadcastPacket(createAppearancePacket(actorId), true);
} Database.savePlayerAppearance(this);
broadcastPacket(createAppearancePacket(actorId), true);
} }
public Inventory getInventory(ushort type) public Inventory getInventory(ushort type)

View file

@ -18,12 +18,14 @@ namespace FFXIVClassic_Lobby_Server.common
} }
public static void debug(String message) public static void debug(String message)
{ {
#if DEBUG
Console.Write("[{0}]", DateTime.Now.ToString("dd/MMM HH:mm")); Console.Write("[{0}]", DateTime.Now.ToString("dd/MMM HH:mm"));
Console.ForegroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("[DEBUG] "); Console.Write("[DEBUG] ");
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine(message); Console.WriteLine(message);
#endif
} }
public static void info(String message) public static void info(String message)

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -179,5 +180,127 @@ namespace FFXIVClassic_Lobby_Server.common
return data; return data;
} }
public static string FFXIVLoginStringDecodeBinary(string path)
{
Console.OutputEncoding = System.Text.Encoding.UTF8;
byte[] data = File.ReadAllBytes(path);
int offset = 0x5405a;
//int offset = 0x5425d;
//int offset = 0x53ea0;
while (true)
{
string result = "";
uint key = (uint)data[offset + 0] << 8 | data[offset+1];
uint key2 = data[offset + 2];
key = RotateRight(key, 1) & 0xFFFF;
key -= 0x22AF;
key &= 0xFFFF;
key2 = key2 ^ key;
key = RotateRight(key, 1) & 0xFFFF;
key -= 0x22AF;
key &= 0xFFFF;
uint finalKey = key;
key = data[offset + 3];
uint count = (key2 & 0xFF) << 8;
key = key ^ finalKey;
key &= 0xFF;
count |= key;
int count2 = 0;
while (count != 0)
{
uint encrypted = data[offset + 4 + count2];
finalKey = RotateRight(finalKey, 1) & 0xFFFF;
finalKey -= 0x22AF;
finalKey &= 0xFFFF;
encrypted = encrypted ^ (finalKey & 0xFF);
result += (char)encrypted;
count--;
count2++;
}
offset += 4 + count2;
Console.WriteLine(result);
}
}
public static string FFXIVLoginStringDecode(byte[] data)
{
string result = "";
uint key = (uint)data[0] << 8 | data[1];
uint key2 = data[2];
key = RotateRight(key, 1) & 0xFFFF;
key -= 0x22AF;
key2 = key2 ^ key;
key = RotateRight(key, 1) & 0xFFFF;
key -= 0x22AF;
uint finalKey = key;
key = data[3];
uint count = (key2 & 0xFF) << 8;
key = key ^ finalKey;
key &= 0xFF;
count |= key;
int count2 = 0;
while (count != 0)
{
uint encrypted = data[4 + count2];
finalKey = RotateRight(finalKey, 1) & 0xFFFF;
finalKey -= 0x22AF;
encrypted = encrypted ^ (finalKey & 0xFF);
result += (char)encrypted;
count--;
count2++;
}
return result;
}
public static byte[] FFXIVLoginStringEncode(uint key, string text)
{
key = key & 0xFFFF;
uint count = 0;
byte[] asciiBytes = Encoding.ASCII.GetBytes(text);
byte[] result = new byte[4 + text.Length];
for (count = 0; count < text.Length; count++)
{
result[result.Length - count - 1] = (byte)(asciiBytes[asciiBytes.Length - count - 1] ^ (key & 0xFF));
key += 0x22AF;
key &= 0xFFFF;
key = RotateLeft(key, 1) & 0xFFFF;
}
count = count ^ key;
result[3] = (byte) (count & 0xFF);
key += 0x22AF & 0xFFFF;
key = RotateLeft(key, 1) & 0xFFFF;
result[2] = (byte)(key & 0xFF);
key += 0x22AF & 0xFFFF;
key = RotateLeft(key, 1) & 0xFFFF;
result[1] = (byte)(key & 0xFF);
result[0] = (byte)((key >> 8) & 0xFF);
return result;
}
public static uint RotateLeft(uint value, int bits)
{
return (value << bits) | (value >> (16 - bits));
}
public static uint RotateRight(uint value, int bits)
{
return (value >> bits) | (value << (16 - bits));
}
} }
} }

View file

@ -1,4 +1,5 @@
using FFXIVClassic_Lobby_Server; using FFXIVClassic_Lobby_Server;
using FFXIVClassic_Lobby_Server.common;
using FFXIVClassic_Lobby_Server.packets; using FFXIVClassic_Lobby_Server.packets;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
@ -19,9 +20,9 @@ namespace FFXIVClassic_Map_Server.dataobjects
private ClientConnection zoneConnection; private ClientConnection zoneConnection;
private ClientConnection chatConnection; private ClientConnection chatConnection;
public string errorMessage = ""; private uint lastPingPacket = Utils.UnixTimeStampUTC();
bool isDisconnected; public string errorMessage = "";
public ConnectedPlayer(uint actorId) public ConnectedPlayer(uint actorId)
{ {
@ -51,11 +52,15 @@ namespace FFXIVClassic_Map_Server.dataobjects
public void disconnect() public void disconnect()
{ {
isDisconnected = true;
zoneConnection.disconnect(); zoneConnection.disconnect();
chatConnection.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);
@ -71,6 +76,23 @@ namespace FFXIVClassic_Map_Server.dataobjects
return playerActor; return playerActor;
} }
public void ping()
{
lastPingPacket = Utils.UnixTimeStampUTC();
}
public bool checkIfDCing()
{
uint currentTime = Utils.UnixTimeStampUTC();
if (currentTime - lastPingPacket >= 5000) //Show D/C flag
playerActor.setDCFlag(true);
else if (currentTime - lastPingPacket >= 30000) //DCed
return true;
else
playerActor.setDCFlag(false);
return false;
}
public void updatePlayerActorPosition(float x, float y, float z, float rot, ushort moveState) public void updatePlayerActorPosition(float x, float y, float z, float rot, ushort moveState)
{ {
@ -88,17 +110,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
getActor().zone.updateActorPosition(getActor()); getActor().zone.updateActorPosition(getActor());
} }
public void sendMotd()
{
}
public void sendChat(ConnectedPlayer sender, string message, int mode)
{
}
public List<BasePacket> updateInstance(List<Actor> list) public List<BasePacket> updateInstance(List<Actor> list)
{ {
List<BasePacket> basePackets = new List<BasePacket>(); List<BasePacket> basePackets = new List<BasePacket>();

View file

@ -19,6 +19,8 @@ namespace FFXIVClassic_Map_Server.lua
{ {
class LuaEngine class LuaEngine
{ {
const string FILEPATH_PLAYER = "./scripts/player.lua";
const string FILEPATH_ZONE = "./scripts/zones/{0}/zone.lua";
const string FILEPATH_COMMANDS = "./scripts/commands/{0}.lua"; const string FILEPATH_COMMANDS = "./scripts/commands/{0}.lua";
const string FILEPATH_NPCS = "./scripts/zones/{0}/npcs/{1}.lua"; const string FILEPATH_NPCS = "./scripts/zones/{0}/npcs/{1}.lua";
@ -27,7 +29,7 @@ namespace FFXIVClassic_Map_Server.lua
UserData.RegistrationPolicy = InteropRegistrationPolicy.Automatic; UserData.RegistrationPolicy = InteropRegistrationPolicy.Automatic;
} }
public List<LuaParam> doActorOnInstantiate(Player player, Actor target) public static List<LuaParam> doActorOnInstantiate(Player player, Actor target)
{ {
string luaPath; string luaPath;
@ -58,7 +60,7 @@ namespace FFXIVClassic_Map_Server.lua
return null; return null;
} }
public void doActorOnEventStarted(Player player, Actor target, EventStartPacket eventStart) public static void doActorOnEventStarted(Player player, Actor target, EventStartPacket eventStart)
{ {
string luaPath; string luaPath;
@ -96,7 +98,7 @@ namespace FFXIVClassic_Map_Server.lua
} }
public void doActorOnEventUpdated(Player player, Actor target, EventUpdatePacket eventUpdate) public static void doActorOnEventUpdated(Player player, Actor target, EventUpdatePacket eventUpdate)
{ {
string luaPath; string luaPath;
@ -131,5 +133,38 @@ namespace FFXIVClassic_Map_Server.lua
player.playerSession.queuePacket(BasePacket.createPacket(sendError, true, false)); player.playerSession.queuePacket(BasePacket.createPacket(sendError, true, false));
} }
} }
public static void onZoneIn(Player player)
{
string luaPath = String.Format(FILEPATH_ZONE, player.getZone().actorId);
if (File.Exists(luaPath))
{
Script script = new Script();
((ScriptLoaderBase)script.Options.ScriptLoader).ModulePaths = new string[] { "./scripts/?", "./scripts/?.lua" };
script.Globals["getStaticActor"] = (Func<string, Actor>)Server.getStaticActors;
script.Globals["getWorldMaster"] = (Func<Actor>)Server.getServer().GetWorldManager().GetActor;
script.DoFile(luaPath);
//Run Script
DynValue result = script.Call(script.Globals["onZoneIn"], player);
}
}
public static void onLogin(Player player)
{
if (File.Exists(FILEPATH_PLAYER))
{
Script script = new Script();
((ScriptLoaderBase)script.Options.ScriptLoader).ModulePaths = new string[] { "./scripts/?", "./scripts/?.lua" };
script.Globals["getStaticActor"] = (Func<string, Actor>)Server.getStaticActors;
script.Globals["getWorldMaster"] = (Func<Actor>)Server.getServer().GetWorldManager().GetActor;
script.DoFile(FILEPATH_PLAYER);
//Run Script
DynValue result = script.Call(script.Globals["onLogin"], player);
}
}
} }
} }

View file

@ -18,22 +18,29 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
public const int FACEINFO = 2; public const int FACEINFO = 2;
public const int HIGHLIGHT_HAIR = 3; public const int HIGHLIGHT_HAIR = 3;
public const int VOICE = 4; public const int VOICE = 4;
public const int WEAPON1 = 5; public const int MAINHAND = 5;
public const int WEAPON2 = 6; public const int OFFHAND = 6;
public const int WEAPON3 = 7; public const int SPMAINHAND = 7;
public const int SPOFFHAND = 8;
public const int THROWING = 9;
public const int PACK = 10;
public const int POUCH = 11;
public const int HEADGEAR = 12; public const int HEADGEAR = 12;
public const int BODYGEAR = 13; public const int BODYGEAR = 13;
public const int LEGSGEAR = 14; public const int LEGSGEAR = 14;
public const int HANDSGEAR = 15; public const int HANDSGEAR = 15;
public const int FEETGEAR = 16; public const int FEETGEAR = 16;
public const int WAISTGEAR = 17; public const int WAISTGEAR = 17;
public const int UNKNOWN1 = 18; public const int NECKGEAR = 18;
public const int R_EAR = 19; public const int L_EAR = 19;
public const int L_EAR = 20; public const int R_EAR = 20;
public const int UNKNOWN2 = 21; public const int R_WRIST = 21;
public const int UNKNOWN3 = 22; public const int L_WRIST = 22;
public const int R_FINGER = 23; public const int R_RINGFINGER = 23;
public const int L_FINGER = 24; public const int L_RINGFINGER = 24;
public const int R_INDEXFINGER = 25;
public const int L_INDEXFINGER = 26;
public const int UNKNOWN = 27;
public uint modelID; public uint modelID;
public uint[] appearanceIDs; public uint[] appearanceIDs;
@ -41,7 +48,7 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
public SetActorAppearancePacket(uint modelID) public SetActorAppearancePacket(uint modelID)
{ {
this.modelID = modelID; this.modelID = modelID;
appearanceIDs = new uint[0x1D]; appearanceIDs = new uint[28];
} }
public SetActorAppearancePacket(uint modelID, uint[] appearanceTable) public SetActorAppearancePacket(uint modelID, uint[] appearanceTable)
@ -58,16 +65,15 @@ namespace FFXIVClassic_Map_Server.packets.send.actor
{ {
using (BinaryWriter binWriter = new BinaryWriter(mem)) using (BinaryWriter binWriter = new BinaryWriter(mem))
{ {
binWriter.Write((uint)modelID); binWriter.Write((uint)modelID);
for (int i = 0; i <= 0x1A; i++) for (int i = 0; i < appearanceIDs.Length; i++)
{ {
binWriter.Write((uint)i); binWriter.Write((uint)i);
binWriter.Write((uint)appearanceIDs[i]); binWriter.Write((uint)appearanceIDs[i]);
} }
binWriter.Write((uint) 0x1B);
binWriter.Seek(0x20, SeekOrigin.Current); binWriter.Seek(0x100, SeekOrigin.Begin);
binWriter.Write((uint) 0x1C); binWriter.Write(appearanceIDs.Length);
binWriter.Write((uint) 0x00);
} }
} }