diff --git a/FFXIVClassic Common Class Lib/STA_INIFile.cs b/FFXIVClassic Common Class Lib/STA_INIFile.cs
index 08fe7e2d..1f0d64c3 100644
--- a/FFXIVClassic Common Class Lib/STA_INIFile.cs
+++ b/FFXIVClassic Common Class Lib/STA_INIFile.cs
@@ -178,7 +178,7 @@ namespace FFXIVClassic.Common
// *** Check if original file exists ***
bool OriginalFileExists = File.Exists(m_FileName);
- // *** Get temporary file name ***
+ // *** get temporary file name ***
string TmpFileName = Path.ChangeExtension(m_FileName, "$n$");
// *** Copy content of original file to temporary file, replace modified values ***
diff --git a/FFXIVClassic Common Class Lib/Utils.cs b/FFXIVClassic Common Class Lib/Utils.cs
index f1de60b3..a97f2ee2 100644
--- a/FFXIVClassic Common Class Lib/Utils.cs
+++ b/FFXIVClassic Common Class Lib/Utils.cs
@@ -218,6 +218,16 @@ namespace FFXIVClassic.Common
}
return data;
+ }
+
+ public static string ToStringBase63(int number)
+ {
+ string lookup = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ string secondDigit = lookup.Substring((int)Math.Floor((double)number / (double)lookup.Length), 1);
+ string firstDigit = lookup.Substring(number % lookup.Length, 1);
+
+ return secondDigit + firstDigit;
}
}
}
diff --git a/FFXIVClassic Common Class Lib/packages.config b/FFXIVClassic Common Class Lib/packages.config
index dac938f3..c171747f 100644
--- a/FFXIVClassic Common Class Lib/packages.config
+++ b/FFXIVClassic Common Class Lib/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/FFXIVClassic Lobby Server/NLog.config b/FFXIVClassic Lobby Server/NLog.config
index c152c074..535cf7e4 100644
--- a/FFXIVClassic Lobby Server/NLog.config
+++ b/FFXIVClassic Lobby Server/NLog.config
@@ -16,22 +16,22 @@
See https://github.com/nlog/nlog/wiki/Configuration-file
for information on customizing logging rules and outputs.
-->
-
+
-
-
-
+
+
+
diff --git a/FFXIVClassic Lobby Server/NLog.xsd b/FFXIVClassic Lobby Server/NLog.xsd
index 175dd774..63ded8c9 100644
--- a/FFXIVClassic Lobby Server/NLog.xsd
+++ b/FFXIVClassic Lobby Server/NLog.xsd
@@ -1,12 +1,12 @@
-
+
-
+
@@ -51,17 +51,17 @@
-
+
-
-
-
-
-
+
+
+
+
+
- Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes).
+ Make all tarGets within this section asynchronous (Creates additional threads but the calling thread isn't blocked by any tarGet writes).
@@ -78,7 +78,7 @@
- Prefix for targets/layout renderers/filters/conditions loaded from this assembly.
+ Prefix for tarGets/layout renderers/filters/conditions loaded from this assembly.
@@ -121,9 +121,9 @@
Level that this rule matches.
-
+
- Comma separated list of target names.
+ Comma separated list of tarGet names.
@@ -195,39 +195,39 @@
-
+
-
-
+
+
-
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -247,7 +247,7 @@
-
+
@@ -255,7 +255,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -273,17 +273,17 @@
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -291,7 +291,7 @@
Number of log events that should be processed in a batch by the lazy writer thread.
-
+
Action to be taken when the lazy writer thread request queue count exceeds the set limit.
@@ -309,7 +309,7 @@
-
+
@@ -318,13 +318,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -332,7 +332,7 @@
-
+
@@ -341,7 +341,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -364,15 +364,15 @@
-
+
-
-
+
+
@@ -380,7 +380,7 @@
-
+
@@ -389,7 +389,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -412,12 +412,12 @@
Indicates whether to append newline at the end of log message.
-
+
Action that should be taken if the will be more connections than .
-
+
Action that should be taken if the message is larger than maxMessageSize.
@@ -485,21 +485,21 @@
-
+
-
+
-
+
@@ -517,21 +517,21 @@
-
+
-
-
+
+
- Name of the target.
+ Name of the tarGet.
@@ -567,7 +567,7 @@
-
+
@@ -588,37 +588,37 @@
-
+
-
-
+
+
Condition that must be met in order to set the specified foreground and background color.
-
+
Background color.
-
+
Foreground color.
-
+
-
-
+
+
@@ -645,12 +645,12 @@
Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used.
-
+
Background color.
-
+
Foreground color.
@@ -658,7 +658,7 @@
-
+
@@ -669,7 +669,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -702,7 +702,7 @@
-
+
@@ -715,15 +715,15 @@
-
-
+
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -796,12 +796,12 @@
-
+
-
+
@@ -811,7 +811,7 @@
- Connection string to run the command against. If not provided, connection string from the target is used.
+ Connection string to run the command against. If not provided, connection string from the tarGet is used.
@@ -825,7 +825,7 @@
-
+
@@ -861,7 +861,7 @@
-
+
@@ -870,7 +870,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -893,14 +893,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -913,7 +913,7 @@
-
+
@@ -922,13 +922,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -961,7 +961,7 @@
Value to be used as the event Source.
-
+
Action to take if the message is larger than the option.
@@ -979,7 +979,7 @@
-
+
@@ -988,19 +988,19 @@
-
+
- Name of the target.
+ Name of the tarGet.
- Indicates whether to return to the first target after any successful write.
+ Indicates whether to return to the first tarGet after any successful write.
@@ -1008,7 +1008,7 @@
-
+
@@ -1016,9 +1016,9 @@
-
+
-
+
@@ -1027,9 +1027,9 @@
-
+
-
+
@@ -1045,7 +1045,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1073,7 +1073,7 @@
Line ending mode.
-
+
Way file archives are numbered.
@@ -1083,14 +1083,14 @@
Name of the file to be used for an archive.
-
+
Indicates whether to automatically archive log files every time the specified time passes.
- Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose:
+ Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot Create multiple archive files, if they should have the same name. Choose:
@@ -1110,7 +1110,7 @@
- Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong.
+ Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing Gets written when the filename is wrong.
@@ -1128,9 +1128,9 @@
Indicates whether to archive old log file on startup.
-
+
- Indicates whether to create directories if they do not exist.
+ Indicates whether to Create directories if they Do not exist.
@@ -1138,7 +1138,7 @@
Indicates whether to enable log file(s) to be deleted.
-
+
File attributes (Windows only).
@@ -1175,7 +1175,7 @@
- Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger).
+ Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File tarGet is writing to many files (such as splitting by level or by logger).
@@ -1206,7 +1206,7 @@
-
+
@@ -1214,7 +1214,7 @@
-
+
@@ -1224,7 +1224,7 @@
-
+
@@ -1246,19 +1246,19 @@
-
+
- Name of the target.
+ Name of the tarGet.
- Condition expression. Log events who meet this condition will be forwarded to the wrapped target.
+ Condition expression. Log events who meet this condition will be forwarded to the wrapped tarGet.
@@ -1266,38 +1266,38 @@
-
+
-
-
-
+
+
+
- Name of the target.
+ Name of the tarGet.
- Windows domain name to change context to.
+ Windows Domain name to change context to.
-
+
Required impersonation level.
-
+
Type of the logon provider.
-
+
Logon Type.
@@ -1320,7 +1320,7 @@
-
+
@@ -1328,12 +1328,12 @@
-
+
-
+
@@ -1345,7 +1345,7 @@
-
+
@@ -1353,12 +1353,12 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1373,7 +1373,7 @@
- Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply)
+ Indicates whether to use a WCF service contract that is one way (fire and forGet) or two way (request-reply)
@@ -1394,7 +1394,7 @@
-
+
@@ -1418,7 +1418,7 @@
-
+
@@ -1437,7 +1437,7 @@
-
+
@@ -1448,7 +1448,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1531,7 +1531,7 @@
SMTP Server to be used for sending.
-
+
SMTP Authentication mode.
@@ -1574,7 +1574,7 @@
-
+
@@ -1590,14 +1590,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1610,21 +1610,21 @@
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1647,9 +1647,9 @@
Indicates whether to check if a queue exists before writing to it.
-
+
- Indicates whether to create the queue if it doesn't exists.
+ Indicates whether to Create the queue if it Doesn't exists.
@@ -1672,16 +1672,16 @@
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1699,15 +1699,15 @@
-
+
-
-
+
+
@@ -1716,7 +1716,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1739,12 +1739,12 @@
Indicates whether to append newline at the end of log message.
-
+
Action that should be taken if the will be more connections than .
-
+
Action that should be taken if the message is larger than maxMessageSize.
@@ -1779,15 +1779,15 @@
-
+
-
-
+
+
@@ -1795,7 +1795,7 @@
-
+
@@ -1804,7 +1804,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1827,12 +1827,12 @@
Indicates whether to append newline at the end of log message.
-
+
Action that should be taken if the will be more connections than .
-
+
Action that should be taken if the message is larger than maxMessageSize.
@@ -1902,7 +1902,7 @@
-
+
@@ -1910,7 +1910,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1928,14 +1928,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1948,7 +1948,7 @@
-
+
@@ -1961,12 +1961,12 @@
- Name of the target.
+ Name of the tarGet.
- Indicates whether performance counter should be automatically created.
+ Indicates whether performance counter should be automatically Created.
@@ -2036,15 +2036,15 @@
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2055,7 +2055,7 @@
-
+
@@ -2073,13 +2073,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2087,14 +2087,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2107,7 +2107,7 @@
-
+
@@ -2115,12 +2115,12 @@
- Name of the target.
+ Name of the tarGet.
- Number of retries that should be attempted on the wrapped target in case of a failure.
+ Number of retries that should be attempted on the wrapped tarGet in case of a failure.
@@ -2133,13 +2133,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2147,13 +2147,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2161,14 +2161,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2181,20 +2181,20 @@
-
+
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2217,7 +2217,7 @@
Web service namespace. Only used with Soap.
-
+
Protocol to be used when calling web service.
@@ -2230,7 +2230,7 @@
-
+
diff --git a/FFXIVClassic Lobby Server/PacketProcessor.cs b/FFXIVClassic Lobby Server/PacketProcessor.cs
index e0255986..8ccbbf08 100644
--- a/FFXIVClassic Lobby Server/PacketProcessor.cs
+++ b/FFXIVClassic Lobby Server/PacketProcessor.cs
@@ -166,7 +166,7 @@ namespace FFXIVClassic_Lobby_Server
if (worldId == 0)
worldId = client.newCharaWorldId;
- //Check if this character exists, get world from there
+ //Check if this character exists, Get world from there
if (worldId == 0 && charaReq.characterId != 0)
{
Character chara = Database.GetCharacter(client.currentUserId, charaReq.characterId);
diff --git a/FFXIVClassic Lobby Server/Server.cs b/FFXIVClassic Lobby Server/Server.cs
index 20b08be8..98563bdb 100644
--- a/FFXIVClassic Lobby Server/Server.cs
+++ b/FFXIVClassic Lobby Server/Server.cs
@@ -213,7 +213,7 @@ namespace FFXIVClassic_Lobby_Server
{
BasePacket newPacket = null;
- //Too small to even get length
+ //Too small to even Get length
if (bytesRead <= offset)
return null;
diff --git a/FFXIVClassic Lobby Server/packages.config b/FFXIVClassic Lobby Server/packages.config
index 5a3427bf..cd0d69ec 100644
--- a/FFXIVClassic Lobby Server/packages.config
+++ b/FFXIVClassic Lobby Server/packages.config
@@ -1,10 +1,10 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FFXIVClassic Lobby Server/packets/SubPacket.cs b/FFXIVClassic Lobby Server/packets/SubPacket.cs
index f30393b8..fe8a99ec 100644
--- a/FFXIVClassic Lobby Server/packets/SubPacket.cs
+++ b/FFXIVClassic Lobby Server/packets/SubPacket.cs
@@ -10,7 +10,7 @@ namespace FFXIVClassic_Lobby_Server.packets
public ushort subpacketSize;
public ushort type;
public uint sourceId;
- public uint targetId;
+ public uint tarGetId;
public uint unknown1;
}
@@ -68,14 +68,14 @@ namespace FFXIVClassic_Lobby_Server.packets
offset += header.subpacketSize;
}
- public SubPacket(ushort opcode, uint sourceId, uint targetId, byte[] data)
+ public SubPacket(ushort opcode, uint sourceId, uint tarGetId, byte[] data)
{
this.header = new SubPacketHeader();
this.gameMessage = new GameMessageHeader();
gameMessage.opcode = opcode;
header.sourceId = sourceId;
- header.targetId = targetId;
+ header.tarGetId = tarGetId;
gameMessage.timestamp = Utils.UnixTimeStampUTC();
@@ -90,14 +90,14 @@ namespace FFXIVClassic_Lobby_Server.packets
header.subpacketSize = (ushort)(SUBPACKET_SIZE + GAMEMESSAGE_SIZE + data.Length);
}
- public SubPacket(SubPacket original, uint newTargetId)
+ public SubPacket(SubPacket original, uint newTarGetId)
{
this.header = new SubPacketHeader();
this.gameMessage = original.gameMessage;
header.subpacketSize = original.header.subpacketSize;
header.type = original.header.type;
header.sourceId = original.header.sourceId;
- header.targetId = newTargetId;
+ header.tarGetId = newTarGetId;
data = original.data;
}
diff --git a/FFXIVClassic Map Server/CommandProcessor.cs b/FFXIVClassic Map Server/CommandProcessor.cs
index 50b1b945..19163650 100644
--- a/FFXIVClassic Map Server/CommandProcessor.cs
+++ b/FFXIVClassic Map Server/CommandProcessor.cs
@@ -1,835 +1,844 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using FFXIVClassic.Common;
-using FFXIVClassic_Map_Server.dataobjects;
-using FFXIVClassic_Map_Server.packets;
-using FFXIVClassic_Map_Server.packets.send.actor;
-using FFXIVClassic_Map_Server.packets.send;
-using FFXIVClassic_Map_Server.Actors;
-using FFXIVClassic_Map_Server.actors.chara.player;
-using FFXIVClassic_Map_Server.Properties;
-
-namespace FFXIVClassic_Map_Server
-{
- class CommandProcessor
- {
- private Dictionary mConnectedPlayerList;
- private static Dictionary gamedataItems = Server.GetGamedataItems();
-
- // For the moment, this is the only predefined item
- // TODO: make a list/enum in the future so that items can be given by name, instead of by id
- const UInt32 ITEM_GIL = 1000001;
-
- public CommandProcessor(Dictionary playerList)
- {
- mConnectedPlayerList = playerList;
- }
-
- public void SendPacket(ConnectedPlayer client, string path)
- {
- BasePacket packet = new BasePacket(path);
-
- if (client != null)
- {
- packet.ReplaceActorID(client.actorID);
- client.QueuePacket(packet);
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- packet.ReplaceActorID(entry.Value.actorID);
- entry.Value.QueuePacket(packet);
- }
- }
- }
-
- public void ChangeProperty(uint id, uint value, string target)
- {
- SetActorPropetyPacket ChangeProperty = new SetActorPropetyPacket(target);
-
- ChangeProperty.SetTarget(target);
- ChangeProperty.AddInt(id, value);
- ChangeProperty.AddTarget();
-
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- SubPacket ChangePropertyPacket = ChangeProperty.BuildPacket((entry.Value.actorID), (entry.Value.actorID));
-
- BasePacket packet = BasePacket.CreatePacket(ChangePropertyPacket, true, false);
- packet.DebugPrintPacket();
-
- entry.Value.QueuePacket(packet);
- }
- }
-
- public void DoMusic(ConnectedPlayer client, string music)
- {
- ushort musicId;
-
- if (music.ToLower().StartsWith("0x"))
- musicId = Convert.ToUInt16(music, 16);
- else
- musicId = Convert.ToUInt16(music);
-
- if (client != null)
- client.QueuePacket(BasePacket.CreatePacket(SetMusicPacket.BuildPacket(client.actorID, musicId, 1), true, false));
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- BasePacket musicPacket = BasePacket.CreatePacket(SetMusicPacket.BuildPacket(entry.Value.actorID, musicId, 1), true, false);
- entry.Value.QueuePacket(musicPacket);
- }
- }
- }
-
- ///
- /// Teleports player to a location on a predefined list
- ///
- /// The current player
- /// Predefined list: <ffxiv_database>\server_zones_spawnlocations
- public void DoWarp(ConnectedPlayer client, uint id)
- {
- WorldManager worldManager = Server.GetWorldManager();
- FFXIVClassic_Map_Server.WorldManager.ZoneEntrance ze = worldManager.GetZoneEntrance(id);
-
- if (ze == null)
- return;
-
- if (client != null)
- worldManager.DoZoneChange(client.GetActor(), ze.zoneId, ze.privateAreaName, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation);
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- worldManager.DoZoneChange(entry.Value.GetActor(), ze.zoneId, ze.privateAreaName, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation);
- }
- }
- }
-
- public void DoWarp(ConnectedPlayer client, uint zoneId, string privateArea, byte spawnType, float x, float y, float z, float r)
- {
- WorldManager worldManager = Server.GetWorldManager();
- if (worldManager.GetZone(zoneId) == null)
- {
- if (client != null)
- client.QueuePacket(BasePacket.CreatePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", "Zone Does not exist or setting isn't valid."), true, false));
- Program.Log.Error("Zone Does not exist or setting isn't valid.");
- }
-
- if (client != null)
- worldManager.DoZoneChange(client.GetActor(), zoneId, privateArea, spawnType, x, y, z, r);
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- worldManager.DoZoneChange(entry.Value.GetActor(), zoneId, privateArea, spawnType, x, y, z, r);
- }
- }
- }
-
- public void PrintPos(ConnectedPlayer client)
- {
- if (client != null)
- {
- Player p = client.GetActor();
- client.QueuePacket(BasePacket.CreatePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", String.Format("{0}\'s position: ZoneID: {1}, X: {2}, Y: {3}, Z: {4}, Rotation: {5}", p.customDisplayName, p.zoneId, p.positionX, p.positionY, p.positionZ, p.rotation)), true, false));
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
- Program.Log.Info("{0}\'s position: ZoneID: {1}, X: {2}, Y: {3}, Z: {4}, Rotation: {5}", p.customDisplayName, p.zoneId, p.positionX, p.positionY, p.positionZ, p.rotation);
- }
- }
- }
-
- private void SetGraphic(ConnectedPlayer client, uint slot, uint wId, uint eId, uint vId, uint cId)
- {
- if (client != null)
- {
- Player p = client.GetActor();
- p.GraphicChange(slot, wId, eId, vId, cId);
- p.SendAppearance();
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
- p.GraphicChange(slot, wId, eId, vId, cId);
- p.SendAppearance();
- }
- }
- }
-
- 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 entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
- p.GetInventory(Inventory.NORMAL).AddItem(itemId, quantity);
- }
- }
- }
-
- private void GiveItem(ConnectedPlayer client, uint itemId, int quantity, ushort type)
- {
- if (client != null)
- {
- Player p = client.GetActor();
-
- if (p.GetInventory(type) != null)
- p.GetInventory(type).AddItem(itemId, quantity);
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
-
- if (p.GetInventory(type) != null)
- p.GetInventory(type).AddItem(itemId, quantity);
- }
- }
- }
-
- private void RemoveItem(ConnectedPlayer client, uint itemId, int quantity)
- {
- if (client != null)
- {
- Player p = client.GetActor();
- p.GetInventory(Inventory.NORMAL).RemoveItem(itemId, quantity);
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
- p.GetInventory(Inventory.NORMAL).RemoveItem(itemId, quantity);
- }
- }
- }
-
- private void RemoveItem(ConnectedPlayer client, uint itemId, int quantity, ushort type)
- {
- if (client != null)
- {
- Player p = client.GetActor();
-
- if (p.GetInventory(type) != null)
- p.GetInventory(type).RemoveItem(itemId, quantity);
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
-
- if (p.GetInventory(type) != null)
- p.GetInventory(type).RemoveItem(itemId, quantity);
- }
- }
- }
-
- private void GiveCurrency(ConnectedPlayer client, uint itemId, int quantity)
- {
- if (client != null)
- {
- Player p = client.GetActor();
- p.GetInventory(Inventory.CURRENCY).AddItem(itemId, quantity);
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
- p.GetInventory(Inventory.CURRENCY).AddItem(itemId, quantity);
- }
- }
- }
-
- // TODO: make RemoveCurrency() remove all quantity of a currency if quantity_to_remove > quantity_in_inventory instead of silently failing
- private void RemoveCurrency(ConnectedPlayer client, uint itemId, int quantity)
- {
- if (client != null)
- {
- Player p = client.GetActor();
- p.GetInventory(Inventory.CURRENCY).RemoveItem(itemId, quantity);
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
- p.GetInventory(Inventory.CURRENCY).RemoveItem(itemId, quantity);
- }
- }
- }
-
- private void GiveKeyItem(ConnectedPlayer client, uint itemId)
- {
- if (client != null)
- {
- Player p = client.GetActor();
- p.GetInventory(Inventory.KEYITEMS).AddItem(itemId, 1);
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
- p.GetInventory(Inventory.KEYITEMS).AddItem(itemId, 1);
- }
- }
- }
-
- private void RemoveKeyItem(ConnectedPlayer client, uint itemId)
- {
- if (client != null)
- {
- Player p = client.GetActor();
- p.GetInventory(Inventory.KEYITEMS).RemoveItem(itemId, 1);
- }
- else
- {
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- Player p = entry.Value.GetActor();
- p.GetInventory(Inventory.KEYITEMS).RemoveItem(itemId, 1);
- }
- }
- }
-
- private void ParseWarp(ConnectedPlayer client, string[] split)
- {
- float x = 0, y = 0, z = 0, r = 0.0f;
- uint zoneId = 0;
- string privatearea = null;
-
- if (split.Length == 2) // Predefined list
- {
- // TODO: Handle !warp Playername
- #region !warp (predefined list)
- try
- {
- if (split[1].ToLower().StartsWith("0x"))
- zoneId = Convert.ToUInt32(split[1], 16);
- else
- zoneId = Convert.ToUInt32(split[1]);
- }
- catch{return;}
- #endregion
-
- DoWarp(client, zoneId);
- }
- else if (split.Length == 4)
- {
- #region !warp X Y Z
- if (split[1].StartsWith("@"))
- {
- split[1] = split[1].Replace("@", string.Empty);
-
- if (String.IsNullOrEmpty(split[1]))
- split[1] = "0";
-
- try { x = Single.Parse(split[1]) + client.GetActor().positionX; }
- catch{return;}
-
- split[1] = x.ToString();
- }
- if (split[2].StartsWith("@"))
- {
- split[2] = split[2].Replace("@", string.Empty);
-
- if (String.IsNullOrEmpty(split[2]))
- split[2] = "0";
-
- try { y = Single.Parse(split[2]) + client.GetActor().positionY; }
- catch{return;}
-
- split[2] = y.ToString();
- }
- if (split[3].StartsWith("@"))
- {
- split[3] = split[3].Replace("@", string.Empty);
-
- if (String.IsNullOrEmpty(split[3]))
- split[3] = "0";
-
- try { z = Single.Parse(split[3]) + client.GetActor().positionZ; }
- catch{return;}
-
- split[3] = z.ToString();
- }
-
- try
- {
- x = Single.Parse(split[1]);
- y = Single.Parse(split[2]);
- z = Single.Parse(split[3]);
- }
- catch{return;}
-
- zoneId = client.GetActor().zoneId;
- r = client.GetActor().rotation;
- #endregion
-
- SendMessage(client, String.Format("Warping to: ZoneID: {0} X: {1}, Y: {2}, Z: {3}", zoneId, x, y, z));
- DoWarp(client, zoneId, privatearea, 0x00, x, y, z, r);
- }
- else if (split.Length == 5)
- {
- #region !warp Zone X Y Z
- try
- {
- x = Single.Parse(split[2]);
- y = Single.Parse(split[3]);
- z = Single.Parse(split[4]);
- }
- catch{return;}
-
- if (split[1].ToLower().StartsWith("0x"))
- {
- try { zoneId = Convert.ToUInt32(split[1], 16); }
- catch{return;}
- }
- else
- {
- try { zoneId = Convert.ToUInt32(split[1]); }
- catch{return;}
- }
- #endregion
-
- SendMessage(client, String.Format("Warping to: ZoneID: {0} X: {1}, Y: {2}, Z: {3}", zoneId, x, y, z));
- DoWarp(client, zoneId, privatearea, 0x2, x, y, z, r);
- }
- else if (split.Length == 6)
- {
- #region !warp Zone Instance X Y Z
- try
- {
- x = Single.Parse(split[3]);
- y = Single.Parse(split[4]);
- z = Single.Parse(split[5]);
- }
- catch{return;}
-
- if (split[1].ToLower().StartsWith("0x"))
- {
- try { zoneId = Convert.ToUInt32(split[1], 16); }
- catch{return;}
- }
- else
- {
- try { zoneId = Convert.ToUInt32(split[1]); }
- catch{return;}
- }
-
- privatearea = split[2];
- #endregion
-
- SendMessage(client, String.Format("Warping to: ZoneID: {0} X: {1}, Y: {2}, Z: {3}", zoneId, x, y, z));
- DoWarp(client, zoneId, privatearea, 0x2, x, y, z, r);
- }
- else
- return; // catch any invalid warps here
- }
-
- private void DoWeather(ConnectedPlayer client, string weatherID, string value)
- {
- ushort weather = Convert.ToUInt16(weatherID);
-
- if (client != null)
- {
- client.QueuePacket(BasePacket.CreatePacket(SetWeatherPacket.BuildPacket(client.actorID, weather, Convert.ToUInt16(value)), true, false));
- }
-
- /*
- * WIP: Change weather serverside, currently only clientside
- *
- uint currentZoneID;
- if (client != null)
- {
- currentZoneID = client.GetActor().zoneId;
-
- foreach (KeyValuePair entry in mConnectedPlayerList)
- {
- // Change the weather for everyone in the same zone
- if (currentZoneID == entry.Value.GetActor().zoneId)
- {
- BasePacket weatherPacket = BasePacket.CreatePacket(SetWeatherPacket.BuildPacket(entry.Value.actorID, weather), true, false);
- entry.Value.QueuePacket(weatherPacket);
- }
- }
- }
- */
- }
-
- ///
- /// We only use the default options for SendMessagePacket.
- /// May as well make it less unwieldly to view
- ///
- ///
- ///
- private void SendMessage(ConnectedPlayer client, String message)
- {
- if (client != null)
- client.GetActor().QueuePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", message));
- }
-
- internal bool DoCommand(string input, ConnectedPlayer client)
- {
- input.Trim();
- if (input.StartsWith("!"))
- input = input.Substring(1);
-
- String[] split = input.Split(' ');
- split = split.Select(temp => temp.ToLower()).ToArray(); // Ignore case on commands
- split = split.Where(temp => temp != "").ToArray(); // strips extra whitespace from commands
-
- // Debug
- //SendMessage(client, string.Join(",", split));
-
- if (split.Length >= 1)
- {
- #region !help
- if (split[0].Equals("help"))
- {
- if (split.Length == 1)
- {
- SendMessage(client, Resources.CPhelp);
- }
- if (split.Length == 2)
- {
- if (split[1].Equals("mypos"))
- SendMessage(client, Resources.CPmypos);
- else if (split[1].Equals("music"))
- SendMessage(client, Resources.CPmusic);
- else if (split[1].Equals("warp"))
- SendMessage(client, Resources.CPwarp);
- else if (split[1].Equals("givecurrency"))
- SendMessage(client, Resources.CPgivecurrency);
- else if (split[1].Equals("giveitem"))
- SendMessage(client, Resources.CPgiveitem);
- else if (split[1].Equals("givekeyitem"))
- SendMessage(client, Resources.CPgivekeyitem);
- else if (split[1].Equals("removecurrency"))
- SendMessage(client, Resources.CPremovecurrency);
- else if (split[1].Equals("removeitem"))
- SendMessage(client, Resources.CPremoveitem);
- else if (split[1].Equals("removekeyitem"))
- SendMessage(client, Resources.CPremovekeyitem);
- else if (split[1].Equals("reloaditems"))
- SendMessage(client, Resources.CPreloaditems);
- else if (split[1].Equals("reloadzones"))
- SendMessage(client, Resources.CPreloadzones);
- /*
- else if (split[1].Equals("property"))
- SendMessage(client, Resources.CPproperty);
- else if (split[1].Equals("property2"))
- SendMessage(client, Resources.CPproperty2);
- else if (split[1].Equals("sendpacket"))
- SendMessage(client, Resources.CPsendpacket);
- else if (split[1].Equals("setgraphic"))
- SendMessage(client, Resources.CPsetgraphic);
- */
- }
- if (split.Length == 3)
- {
- if(split[1].Equals("test"))
- {
- if (split[2].Equals("weather"))
- SendMessage(client, Resources.CPtestweather);
- }
- }
-
- return true;
- }
- #endregion
-
- #region !test
- else if (split[0].Equals("test"))
- {
- if (split.Length == 1)
- {
- // catch invalid commands
- SendMessage(client, Resources.CPhelp);
- }
- else if (split.Length >= 2)
- {
- #region !test weather
- if (split[1].Equals("weather"))
- {
- try
- {
- DoWeather(client, split[2], split[3]);
- return true;
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not Change weather: " + e);
- }
- }
- #endregion
- }
-
- }
- #endregion
-
- #region !mypos
- else if (split[0].Equals("mypos"))
- {
- try
- {
- PrintPos(client);
- return true;
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not load packet: " + e);
- }
- }
- #endregion
-
- #region !reloadzones
- else if (split[0].Equals("reloadzones"))
- {
- if (client != null)
- {
- Program.Log.Info("Got request to reset zone: {0}", client.GetActor().zoneId);
- client.GetActor().zone.Clear();
- client.GetActor().zone.AddActorToZone(client.GetActor());
- client.GetActor().SendInstanceUpdate();
- client.QueuePacket(BasePacket.CreatePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", String.Format("Reseting zone {0}...", client.GetActor().zoneId)), true, false));
- }
- Server.GetWorldManager().ReloadZone(client.GetActor().zoneId);
- return true;
- }
- #endregion
-
- #region !reloaditems
- else if (split[0].Equals("reloaditems"))
- {
- Program.Log.Info("Got request to reload item gamedata");
- SendMessage(client, "Reloading Item Gamedata...");
- gamedataItems.Clear();
- gamedataItems = Database.GetItemGamedata();
- Program.Log.Info("Loaded {0} items.", gamedataItems.Count);
- SendMessage(client, String.Format("Loaded {0} items.", gamedataItems.Count));
- return true;
- }
- #endregion
-
- #region !sendpacket
- else if (split[0].Equals("sendpacket"))
- {
- if (split.Length < 2)
- return false;
-
- try
- {
- SendPacket(client, "./packets/" + split[1]);
- return true;
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not load packet: " + e);
- }
- }
- #endregion
-
- #region !graphic
- 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)
- {
- Program.Log.Error("Could not give item.");
- }
- }
- #endregion
-
- #region !giveitem
- else if (split[0].Equals("giveitem"))
- {
- try
- {
- if (split.Length == 2)
- GiveItem(client, UInt32.Parse(split[1]), 1);
- else if (split.Length == 3)
- GiveItem(client, UInt32.Parse(split[1]), Int32.Parse(split[2]));
- else if (split.Length == 4)
- GiveItem(client, UInt32.Parse(split[1]), Int32.Parse(split[2]), UInt16.Parse(split[3]));
- return true;
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not give item.");
- }
- }
- #endregion
-
- #region !removeitem
- else if (split[0].Equals("removeitem"))
- {
- if (split.Length < 2)
- return false;
-
- try
- {
- if (split.Length == 2)
- RemoveItem(client, UInt32.Parse(split[1]), 1);
- else if (split.Length == 3)
- RemoveItem(client, UInt32.Parse(split[1]), Int32.Parse(split[2]));
- else if (split.Length == 4)
- RemoveItem(client, UInt32.Parse(split[1]), Int32.Parse(split[2]), UInt16.Parse(split[3]));
- return true;
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not remove item.");
- }
- }
- #endregion
-
- #region !givekeyitem
- else if (split[0].Equals("givekeyitem"))
- {
- try
- {
- if (split.Length == 2)
- GiveKeyItem(client, UInt32.Parse(split[1]));
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not give keyitem.");
- }
- }
- #endregion
-
- #region !removekeyitem
- else if (split[0].Equals("removekeyitem"))
- {
- if (split.Length < 2)
- return false;
-
- try
- {
- if (split.Length == 2)
- RemoveKeyItem(client, UInt32.Parse(split[1]));
- return true;
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not remove keyitem.");
- }
- }
- #endregion
-
- #region !givecurrency
- else if (split[0].Equals("givecurrency"))
- {
- try
- {
- if (split.Length == 2)
- GiveCurrency(client, ITEM_GIL, Int32.Parse(split[1]));
- else if (split.Length == 3)
- GiveCurrency(client, UInt32.Parse(split[1]), Int32.Parse(split[2]));
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not give currency.");
- }
- }
- #endregion
-
- #region !removecurrency
- else if (split[0].Equals("removecurrency"))
- {
- if (split.Length < 2)
- return false;
-
- try
- {
- if (split.Length == 2)
- RemoveCurrency(client, ITEM_GIL, Int32.Parse(split[1]));
- else if (split.Length == 3)
- RemoveCurrency(client, UInt32.Parse(split[1]), Int32.Parse(split[2]));
- return true;
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not remove currency.");
- }
- }
- #endregion
-
- #region !music
- else if (split[0].Equals("music"))
- {
- if (split.Length < 2)
- return false;
-
- try
- {
- DoMusic(client, split[1]);
- return true;
- }
- catch (Exception e)
- {
- Program.Log.Error("Could not Change music: " + e);
- }
- }
- #endregion
-
- #region !warp
- else if (split[0].Equals("warp"))
- {
- ParseWarp(client, split);
- return true;
- }
- #endregion
-
- #region !property
- else if (split[0].Equals("property"))
- {
- if (split.Length == 4)
- {
- ChangeProperty(Utils.MurmurHash2(split[1], 0), Convert.ToUInt32(split[2], 16), split[3]);
- }
- return true;
- }
- #endregion
-
- #region !property2
- else if (split[0].Equals("property2"))
- {
- if (split.Length == 4)
- {
- ChangeProperty(Convert.ToUInt32(split[1], 16), Convert.ToUInt32(split[2], 16), split[3]);
- }
- return true;
- }
- #endregion
- }
- return false;
- }
- }
-
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading.Tasks;
+using System.Threading;
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.dataobjects;
+using FFXIVClassic_Map_Server.packets;
+using System.IO;
+using FFXIVClassic_Map_Server.packets.send.actor;
+using FFXIVClassic_Map_Server;
+using FFXIVClassic_Map_Server.packets.send;
+using FFXIVClassic_Map_Server.dataobjects.chara;
+using FFXIVClassic_Map_Server.Actors;
+using FFXIVClassic_Map_Server.lua;
+using FFXIVClassic_Map_Server.actors.chara.player;
+using FFXIVClassic_Map_Server.Properties;
+
+namespace FFXIVClassic_Map_Server
+{
+ class CommandProcessor
+ {
+ private Dictionary mConnectedPlayerList;
+ private static Dictionary gamedataItems = Server.GetGamedataItems();
+
+ // For the moment, this is the only predefined item
+ // TODO: make a list/enum in the future so that items can be given by name, instead of by id
+ const UInt32 ITEM_GIL = 1000001;
+
+ public CommandProcessor(Dictionary playerList)
+ {
+ mConnectedPlayerList = playerList;
+ }
+
+ public void SendPacket(ConnectedPlayer client, string path)
+ {
+ BasePacket packet = new BasePacket(path);
+
+ if (client != null)
+ {
+ packet.ReplaceActorID(client.actorID);
+ client.QueuePacket(packet);
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ packet.ReplaceActorID(entry.Value.actorID);
+ entry.Value.QueuePacket(packet);
+ }
+ }
+ }
+
+ public void ChangeProperty(uint id, uint value, string tarGet)
+ {
+ SetActorPropetyPacket ChangeProperty = new SetActorPropetyPacket(tarGet);
+
+ ChangeProperty.SetTarget(tarGet);
+ ChangeProperty.AddInt(id, value);
+ ChangeProperty.AddTarget();
+
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ SubPacket ChangePropertyPacket = ChangeProperty.BuildPacket((entry.Value.actorID), (entry.Value.actorID));
+
+ BasePacket packet = BasePacket.CreatePacket(ChangePropertyPacket, true, false);
+ packet.DebugPrintPacket();
+
+ entry.Value.QueuePacket(packet);
+ }
+ }
+
+ public void DoMusic(ConnectedPlayer client, string music)
+ {
+ ushort musicId;
+
+ if (music.ToLower().StartsWith("0x"))
+ musicId = Convert.ToUInt16(music, 16);
+ else
+ musicId = Convert.ToUInt16(music);
+
+ if (client != null)
+ client.QueuePacket(BasePacket.CreatePacket(SetMusicPacket.BuildPacket(client.actorID, musicId, 1), true, false));
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ BasePacket musicPacket = BasePacket.CreatePacket(SetMusicPacket.BuildPacket(entry.Value.actorID, musicId, 1), true, false);
+ entry.Value.QueuePacket(musicPacket);
+ }
+ }
+ }
+
+ ///
+ /// Teleports player to a location on a predefined list
+ ///
+ /// The current player
+ /// Predefined list: <ffxiv_database>\server_zones_spawnlocations
+ public void DoWarp(ConnectedPlayer client, uint id)
+ {
+ WorldManager worldManager = Server.GetWorldManager();
+ FFXIVClassic_Map_Server.WorldManager.ZoneEntrance ze = worldManager.GetZoneEntrance(id);
+
+ if (ze == null)
+ return;
+
+ if (client != null)
+ worldManager.DoZoneChange(client.GetActor(), ze.zoneId, ze.privateAreaName, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation);
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ worldManager.DoZoneChange(entry.Value.GetActor(), ze.zoneId, ze.privateAreaName, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation);
+ }
+ }
+ }
+
+ public void DoWarp(ConnectedPlayer client, uint zoneId, string privateArea, byte spawnType, float x, float y, float z, float r)
+ {
+ WorldManager worldManager = Server.GetWorldManager();
+ if (worldManager.GetZone(zoneId) == null)
+ {
+ if (client != null)
+ client.QueuePacket(BasePacket.CreatePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", "Zone does not exist or setting isn't valid."), true, false));
+ Program.Log.Error("Zone does not exist or setting isn't valid.");
+ }
+
+ if (client != null)
+ worldManager.DoZoneChange(client.GetActor(), zoneId, privateArea, spawnType, x, y, z, r);
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ worldManager.DoZoneChange(entry.Value.GetActor(), zoneId, privateArea, spawnType, x, y, z, r);
+ }
+ }
+ }
+
+ public void PrintPos(ConnectedPlayer client)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+ client.QueuePacket(BasePacket.CreatePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", String.Format("{0}\'s position: ZoneID: {1}, X: {2}, Y: {3}, Z: {4}, Rotation: {5}", p.customDisplayName, p.zoneId, p.positionX, p.positionY, p.positionZ, p.rotation)), true, false));
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+ Program.Log.Info(String.Format("{0}\'s position: ZoneID: {1}, X: {2}, Y: {3}, Z: {4}, Rotation: {5}", p.customDisplayName, p.zoneId, p.positionX, p.positionY, p.positionZ, p.rotation));
+ }
+ }
+ }
+
+ private void SetGraphic(ConnectedPlayer client, uint slot, uint wId, uint eId, uint vId, uint cId)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+ p.GraphicChange(slot, wId, eId, vId, cId);
+ p.SendAppearance();
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+ p.GraphicChange(slot, wId, eId, vId, cId);
+ p.SendAppearance();
+ }
+ }
+ }
+
+ 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 entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+ p.GetInventory(Inventory.NORMAL).AddItem(itemId, quantity);
+ }
+ }
+ }
+
+ private void GiveItem(ConnectedPlayer client, uint itemId, int quantity, ushort type)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+
+ if (p.GetInventory(type) != null)
+ p.GetInventory(type).AddItem(itemId, quantity);
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+
+ if (p.GetInventory(type) != null)
+ p.GetInventory(type).AddItem(itemId, quantity);
+ }
+ }
+ }
+
+ private void RemoveItem(ConnectedPlayer client, uint itemId, int quantity)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+ p.GetInventory(Inventory.NORMAL).RemoveItem(itemId, quantity);
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+ p.GetInventory(Inventory.NORMAL).RemoveItem(itemId, quantity);
+ }
+ }
+ }
+
+ private void RemoveItem(ConnectedPlayer client, uint itemId, int quantity, ushort type)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+
+ if (p.GetInventory(type) != null)
+ p.GetInventory(type).RemoveItem(itemId, quantity);
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+
+ if (p.GetInventory(type) != null)
+ p.GetInventory(type).RemoveItem(itemId, quantity);
+ }
+ }
+ }
+
+ private void GiveCurrency(ConnectedPlayer client, uint itemId, int quantity)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+ p.GetInventory(Inventory.CURRENCY).AddItem(itemId, quantity);
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+ p.GetInventory(Inventory.CURRENCY).AddItem(itemId, quantity);
+ }
+ }
+ }
+
+ // TODO: make RemoveCurrency() Remove all quantity of a currency if quantity_to_Remove > quantity_in_inventory instead of silently failing
+ private void RemoveCurrency(ConnectedPlayer client, uint itemId, int quantity)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+ p.GetInventory(Inventory.CURRENCY).RemoveItem(itemId, quantity);
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+ p.GetInventory(Inventory.CURRENCY).RemoveItem(itemId, quantity);
+ }
+ }
+ }
+
+ private void GiveKeyItem(ConnectedPlayer client, uint itemId)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+ p.GetInventory(Inventory.KEYITEMS).AddItem(itemId, 1);
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+ p.GetInventory(Inventory.KEYITEMS).AddItem(itemId, 1);
+ }
+ }
+ }
+
+ private void RemoveKeyItem(ConnectedPlayer client, uint itemId)
+ {
+ if (client != null)
+ {
+ Player p = client.GetActor();
+ p.GetInventory(Inventory.KEYITEMS).RemoveItem(itemId, 1);
+ }
+ else
+ {
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ Player p = entry.Value.GetActor();
+ p.GetInventory(Inventory.KEYITEMS).RemoveItem(itemId, 1);
+ }
+ }
+ }
+
+ private void ParseWarp(ConnectedPlayer client, string[] split)
+ {
+ float x = 0, y = 0, z = 0, r = 0.0f;
+ uint zoneId = 0;
+ string privatearea = null;
+
+ if (split.Length == 2) // Predefined list
+ {
+ // TODO: Handle !warp Playername
+ #region !warp (predefined list)
+ try
+ {
+ if (split[1].ToLower().StartsWith("0x"))
+ zoneId = Convert.ToUInt32(split[1], 16);
+ else
+ zoneId = Convert.ToUInt32(split[1]);
+ }
+ catch{return;}
+ #endregion
+
+ DoWarp(client, zoneId);
+ }
+ else if (split.Length == 4)
+ {
+ #region !warp X Y Z
+ if (split[1].StartsWith("@"))
+ {
+ split[1] = split[1].Replace("@", string.Empty);
+
+ if (String.IsNullOrEmpty(split[1]))
+ split[1] = "0";
+
+ try { x = Single.Parse(split[1]) + client.GetActor().positionX; }
+ catch{return;}
+
+ split[1] = x.ToString();
+ }
+ if (split[2].StartsWith("@"))
+ {
+ split[2] = split[2].Replace("@", string.Empty);
+
+ if (String.IsNullOrEmpty(split[2]))
+ split[2] = "0";
+
+ try { y = Single.Parse(split[2]) + client.GetActor().positionY; }
+ catch{return;}
+
+ split[2] = y.ToString();
+ }
+ if (split[3].StartsWith("@"))
+ {
+ split[3] = split[3].Replace("@", string.Empty);
+
+ if (String.IsNullOrEmpty(split[3]))
+ split[3] = "0";
+
+ try { z = Single.Parse(split[3]) + client.GetActor().positionZ; }
+ catch{return;}
+
+ split[3] = z.ToString();
+ }
+
+ try
+ {
+ x = Single.Parse(split[1]);
+ y = Single.Parse(split[2]);
+ z = Single.Parse(split[3]);
+ }
+ catch{return;}
+
+ zoneId = client.GetActor().zoneId;
+ r = client.GetActor().rotation;
+ #endregion
+
+ SendMessage(client, String.Format("Warping to: ZoneID: {0} X: {1}, Y: {2}, Z: {3}", zoneId, x, y, z));
+ DoWarp(client, zoneId, privatearea, 0x00, x, y, z, r);
+ }
+ else if (split.Length == 5)
+ {
+ #region !warp Zone X Y Z
+ try
+ {
+ x = Single.Parse(split[2]);
+ y = Single.Parse(split[3]);
+ z = Single.Parse(split[4]);
+ }
+ catch{return;}
+
+ if (split[1].ToLower().StartsWith("0x"))
+ {
+ try { zoneId = Convert.ToUInt32(split[1], 16); }
+ catch{return;}
+ }
+ else
+ {
+ try { zoneId = Convert.ToUInt32(split[1]); }
+ catch{return;}
+ }
+ #endregion
+
+ SendMessage(client, String.Format("Warping to: ZoneID: {0} X: {1}, Y: {2}, Z: {3}", zoneId, x, y, z));
+ DoWarp(client, zoneId, privatearea, 0x2, x, y, z, r);
+ }
+ else if (split.Length == 6)
+ {
+ #region !warp Zone Instance X Y Z
+ try
+ {
+ x = Single.Parse(split[3]);
+ y = Single.Parse(split[4]);
+ z = Single.Parse(split[5]);
+ }
+ catch{return;}
+
+ if (split[1].ToLower().StartsWith("0x"))
+ {
+ try { zoneId = Convert.ToUInt32(split[1], 16); }
+ catch{return;}
+ }
+ else
+ {
+ try { zoneId = Convert.ToUInt32(split[1]); }
+ catch{return;}
+ }
+
+ privatearea = split[2];
+ #endregion
+
+ SendMessage(client, String.Format("Warping to: ZoneID: {0} X: {1}, Y: {2}, Z: {3}", zoneId, x, y, z));
+ DoWarp(client, zoneId, privatearea, 0x2, x, y, z, r);
+ }
+ else
+ return; // catch any invalid warps here
+ }
+
+ private void doWeather(ConnectedPlayer client, string weatherID, string value)
+ {
+ ushort weather = Convert.ToUInt16(weatherID);
+
+ if (client != null)
+ {
+ client.QueuePacket(BasePacket.CreatePacket(SetWeatherPacket.BuildPacket(client.actorID, weather, Convert.ToUInt16(value)), true, false));
+ }
+
+ /*
+ * WIP: Change weather serverside, currently only clientside
+ *
+ uint currentZoneID;
+ if (client != null)
+ {
+ currentZoneID = client.GetActor().zoneId;
+
+ foreach (KeyValuePair entry in mConnectedPlayerList)
+ {
+ // Change the weather for everyone in the same zone
+ if (currentZoneID == entry.Value.GetActor().zoneId)
+ {
+ BasePacket weatherPacket = BasePacket.CreatePacket(SetWeatherPacket.BuildPacket(entry.Value.actorID, weather), true, false);
+ entry.Value.QueuePacket(weatherPacket);
+ }
+ }
+ }
+ */
+ }
+
+ ///
+ /// We only use the default options for SendMessagePacket.
+ /// May as well make it less unwieldly to view
+ ///
+ ///
+ ///
+ private void SendMessage(ConnectedPlayer client, String message)
+ {
+ if (client != null)
+ client.GetActor().QueuePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", message));
+ }
+
+ internal bool DoCommand(string input, ConnectedPlayer client)
+ {
+ input.Trim();
+ if (input.StartsWith("!"))
+ input = input.Substring(1);
+
+ String[] split = input.Split(' ');
+ split = split.Select(temp => temp.ToLower()).ToArray(); // Ignore case on commands
+ split = split.Where(temp => temp != "").ToArray(); // strips extra whitespace from commands
+
+ // Debug
+ //SendMessage(client, string.Join(",", split));
+
+ if (split.Length >= 1)
+ {
+ #region !help
+ if (split[0].Equals("help"))
+ {
+ if (split.Length == 1)
+ {
+ SendMessage(client, Resources.CPhelp);
+ }
+ if (split.Length == 2)
+ {
+ if (split[1].Equals("mypos"))
+ SendMessage(client, Resources.CPmypos);
+ else if (split[1].Equals("music"))
+ SendMessage(client, Resources.CPmusic);
+ else if (split[1].Equals("warp"))
+ SendMessage(client, Resources.CPwarp);
+ else if (split[1].Equals("givecurrency"))
+ SendMessage(client, Resources.CPgivecurrency);
+ else if (split[1].Equals("giveitem"))
+ SendMessage(client, Resources.CPgiveitem);
+ else if (split[1].Equals("givekeyitem"))
+ SendMessage(client, Resources.CPgivekeyitem);
+ else if (split[1].Equals("Removecurrency"))
+ SendMessage(client, Resources.CPRemovecurrency);
+ else if (split[1].Equals("Removeitem"))
+ SendMessage(client, Resources.CPRemoveitem);
+ else if (split[1].Equals("Removekeyitem"))
+ SendMessage(client, Resources.CPRemovekeyitem);
+ else if (split[1].Equals("reloaditems"))
+ SendMessage(client, Resources.CPreloaditems);
+ else if (split[1].Equals("reloadzones"))
+ SendMessage(client, Resources.CPreloadzones);
+ /*
+ else if (split[1].Equals("property"))
+ SendMessage(client, Resources.CPproperty);
+ else if (split[1].Equals("property2"))
+ SendMessage(client, Resources.CPproperty2);
+ else if (split[1].Equals("sendpacket"))
+ SendMessage(client, Resources.CPsendpacket);
+ else if (split[1].Equals("setgraphic"))
+ SendMessage(client, Resources.CPsetgraphic);
+ */
+ }
+ if (split.Length == 3)
+ {
+ if(split[1].Equals("test"))
+ {
+ if (split[2].Equals("weather"))
+ SendMessage(client, Resources.CPtestweather);
+ }
+ }
+
+ return true;
+ }
+ #endregion
+
+ #region !test
+ else if (split[0].Equals("test"))
+ {
+ if (split.Length == 1)
+ {
+ // catch invalid commands
+ SendMessage(client, Resources.CPhelp);
+ }
+ else if (split.Length >= 2)
+ {
+ #region !test weather
+ if (split[1].Equals("weather"))
+ {
+ try
+ {
+ doWeather(client, split[2], split[3]);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not change weather: " + e);
+ }
+ }
+ #endregion
+ }
+
+ }
+ #endregion
+
+ #region !mypos
+ else if (split[0].Equals("mypos"))
+ {
+ try
+ {
+ PrintPos(client);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not load packet: " + e);
+ }
+ }
+ #endregion
+
+ #region !reloadzones
+ else if (split[0].Equals("reloadzones"))
+ {
+ if (client != null)
+ {
+ Program.Log.Info(String.Format("Got request to reset zone: {0}", client.GetActor().zoneId));
+ client.GetActor().zone.Clear();
+ client.GetActor().zone.AddActorToZone(client.GetActor());
+ client.GetActor().SendInstanceUpdate();
+ client.QueuePacket(BasePacket.CreatePacket(SendMessagePacket.BuildPacket(client.actorID, client.actorID, SendMessagePacket.MESSAGE_TYPE_GENERAL_INFO, "", String.Format("Reseting zone {0}...", client.GetActor().zoneId)), true, false));
+ }
+ Server.GetWorldManager().reloadZone(client.GetActor().zoneId);
+ return true;
+ }
+ #endregion
+
+ #region !reloaditems
+ else if (split[0].Equals("reloaditems"))
+ {
+ Program.Log.Info(String.Format("Got request to reload item gamedata"));
+ SendMessage(client, "Reloading Item Gamedata...");
+ gamedataItems.Clear();
+ gamedataItems = Database.GetItemGamedata();
+ Program.Log.Info(String.Format("Loaded {0} items.", gamedataItems.Count));
+ SendMessage(client, String.Format("Loaded {0} items.", gamedataItems.Count));
+ return true;
+ }
+ #endregion
+
+ #region !sendpacket
+ else if (split[0].Equals("sendpacket"))
+ {
+ if (split.Length < 2)
+ return false;
+
+ try
+ {
+ SendPacket(client, "./packets/" + split[1]);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not load packet: " + e);
+ }
+ }
+ #endregion
+
+ #region !graphic
+ 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)
+ {
+ Program.Log.Error("Could not give item.");
+ }
+ }
+ #endregion
+
+ #region !giveitem
+ else if (split[0].Equals("giveitem"))
+ {
+ try
+ {
+ if (split.Length == 2)
+ GiveItem(client, UInt32.Parse(split[1]), 1);
+ else if (split.Length == 3)
+ GiveItem(client, UInt32.Parse(split[1]), Int32.Parse(split[2]));
+ else if (split.Length == 4)
+ GiveItem(client, UInt32.Parse(split[1]), Int32.Parse(split[2]), UInt16.Parse(split[3]));
+ return true;
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not give item.");
+ }
+ }
+ #endregion
+
+ #region !Removeitem
+ else if (split[0].Equals("Removeitem"))
+ {
+ if (split.Length < 2)
+ return false;
+
+ try
+ {
+ if (split.Length == 2)
+ RemoveItem(client, UInt32.Parse(split[1]), 1);
+ else if (split.Length == 3)
+ RemoveItem(client, UInt32.Parse(split[1]), Int32.Parse(split[2]));
+ else if (split.Length == 4)
+ RemoveItem(client, UInt32.Parse(split[1]), Int32.Parse(split[2]), UInt16.Parse(split[3]));
+ return true;
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not Remove item.");
+ }
+ }
+ #endregion
+
+ #region !givekeyitem
+ else if (split[0].Equals("givekeyitem"))
+ {
+ try
+ {
+ if (split.Length == 2)
+ GiveKeyItem(client, UInt32.Parse(split[1]));
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not give keyitem.");
+ }
+ }
+ #endregion
+
+ #region !Removekeyitem
+ else if (split[0].Equals("Removekeyitem"))
+ {
+ if (split.Length < 2)
+ return false;
+
+ try
+ {
+ if (split.Length == 2)
+ RemoveKeyItem(client, UInt32.Parse(split[1]));
+ return true;
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not Remove keyitem.");
+ }
+ }
+ #endregion
+
+ #region !givecurrency
+ else if (split[0].Equals("givecurrency"))
+ {
+ try
+ {
+ if (split.Length == 2)
+ GiveCurrency(client, ITEM_GIL, Int32.Parse(split[1]));
+ else if (split.Length == 3)
+ GiveCurrency(client, UInt32.Parse(split[1]), Int32.Parse(split[2]));
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not give currency.");
+ }
+ }
+ #endregion
+
+ #region !Removecurrency
+ else if (split[0].Equals("Removecurrency"))
+ {
+ if (split.Length < 2)
+ return false;
+
+ try
+ {
+ if (split.Length == 2)
+ RemoveCurrency(client, ITEM_GIL, Int32.Parse(split[1]));
+ else if (split.Length == 3)
+ RemoveCurrency(client, UInt32.Parse(split[1]), Int32.Parse(split[2]));
+ return true;
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not Remove currency.");
+ }
+ }
+ #endregion
+
+ #region !music
+ else if (split[0].Equals("music"))
+ {
+ if (split.Length < 2)
+ return false;
+
+ try
+ {
+ DoMusic(client, split[1]);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Program.Log.Error("Could not change music: " + e);
+ }
+ }
+ #endregion
+
+ #region !warp
+ else if (split[0].Equals("warp"))
+ {
+ ParseWarp(client, split);
+ return true;
+ }
+ #endregion
+
+ #region !property
+ else if (split[0].Equals("property"))
+ {
+ if (split.Length == 4)
+ {
+ ChangeProperty(Utils.MurmurHash2(split[1], 0), Convert.ToUInt32(split[2], 16), split[3]);
+ }
+ return true;
+ }
+ #endregion
+
+ #region !property2
+ else if (split[0].Equals("property2"))
+ {
+ if (split.Length == 4)
+ {
+ ChangeProperty(Convert.ToUInt32(split[1], 16), Convert.ToUInt32(split[2], 16), split[3]);
+ }
+ return true;
+ }
+ #endregion
+ }
+ return false;
+ }
+ }
+
+}
diff --git a/FFXIVClassic Map Server/Database.cs b/FFXIVClassic Map Server/Database.cs
index 920be9cb..55e1b9fd 100644
--- a/FFXIVClassic Map Server/Database.cs
+++ b/FFXIVClassic Map Server/Database.cs
@@ -400,7 +400,6 @@ namespace FFXIVClassic_Map_Server
birthMonth,
initialTown,
tribe,
- currentParty,
restBonus,
achievementPoints,
playTime
@@ -430,9 +429,9 @@ namespace FFXIVClassic_Map_Server
player.playerWork.birthdayMonth = reader.GetByte(14);
player.playerWork.initialTown = reader.GetByte(15);
player.playerWork.tribe = reader.GetByte(16);
- player.playerWork.restBonusExpRate = reader.GetInt32(18);
- player.achievementPoints = reader.GetUInt32(19);
- player.playTime = reader.GetUInt32(20);
+ player.playerWork.restBonusExpRate = reader.GetInt32(17);
+ player.achievementPoints = reader.GetUInt32(18);
+ player.playTime = reader.GetUInt32(19);
}
}
diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
index d6c8b577..f01958b6 100644
--- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
+++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
@@ -71,7 +71,9 @@
+
+
diff --git a/FFXIVClassic Map Server/NLog.config b/FFXIVClassic Map Server/NLog.config
index 1d8fb2f4..603cb587 100644
--- a/FFXIVClassic Map Server/NLog.config
+++ b/FFXIVClassic Map Server/NLog.config
@@ -16,22 +16,22 @@
See https://github.com/nlog/nlog/wiki/Configuration-file
for information on customizing logging rules and outputs.
-->
-
+
-
-
-
+
+
+
diff --git a/FFXIVClassic Map Server/NLog.xsd b/FFXIVClassic Map Server/NLog.xsd
index 175dd774..63ded8c9 100644
--- a/FFXIVClassic Map Server/NLog.xsd
+++ b/FFXIVClassic Map Server/NLog.xsd
@@ -1,12 +1,12 @@
-
+
-
+
@@ -51,17 +51,17 @@
-
+
-
-
-
-
-
+
+
+
+
+
- Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes).
+ Make all tarGets within this section asynchronous (Creates additional threads but the calling thread isn't blocked by any tarGet writes).
@@ -78,7 +78,7 @@
- Prefix for targets/layout renderers/filters/conditions loaded from this assembly.
+ Prefix for tarGets/layout renderers/filters/conditions loaded from this assembly.
@@ -121,9 +121,9 @@
Level that this rule matches.
-
+
- Comma separated list of target names.
+ Comma separated list of tarGet names.
@@ -195,39 +195,39 @@
-
+
-
-
+
+
-
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -247,7 +247,7 @@
-
+
@@ -255,7 +255,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -273,17 +273,17 @@
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -291,7 +291,7 @@
Number of log events that should be processed in a batch by the lazy writer thread.
-
+
Action to be taken when the lazy writer thread request queue count exceeds the set limit.
@@ -309,7 +309,7 @@
-
+
@@ -318,13 +318,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -332,7 +332,7 @@
-
+
@@ -341,7 +341,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -364,15 +364,15 @@
-
+
-
-
+
+
@@ -380,7 +380,7 @@
-
+
@@ -389,7 +389,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -412,12 +412,12 @@
Indicates whether to append newline at the end of log message.
-
+
Action that should be taken if the will be more connections than .
-
+
Action that should be taken if the message is larger than maxMessageSize.
@@ -485,21 +485,21 @@
-
+
-
+
-
+
@@ -517,21 +517,21 @@
-
+
-
-
+
+
- Name of the target.
+ Name of the tarGet.
@@ -567,7 +567,7 @@
-
+
@@ -588,37 +588,37 @@
-
+
-
-
+
+
Condition that must be met in order to set the specified foreground and background color.
-
+
Background color.
-
+
Foreground color.
-
+
-
-
+
+
@@ -645,12 +645,12 @@
Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used.
-
+
Background color.
-
+
Foreground color.
@@ -658,7 +658,7 @@
-
+
@@ -669,7 +669,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -702,7 +702,7 @@
-
+
@@ -715,15 +715,15 @@
-
-
+
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -796,12 +796,12 @@
-
+
-
+
@@ -811,7 +811,7 @@
- Connection string to run the command against. If not provided, connection string from the target is used.
+ Connection string to run the command against. If not provided, connection string from the tarGet is used.
@@ -825,7 +825,7 @@
-
+
@@ -861,7 +861,7 @@
-
+
@@ -870,7 +870,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -893,14 +893,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -913,7 +913,7 @@
-
+
@@ -922,13 +922,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -961,7 +961,7 @@
Value to be used as the event Source.
-
+
Action to take if the message is larger than the option.
@@ -979,7 +979,7 @@
-
+
@@ -988,19 +988,19 @@
-
+
- Name of the target.
+ Name of the tarGet.
- Indicates whether to return to the first target after any successful write.
+ Indicates whether to return to the first tarGet after any successful write.
@@ -1008,7 +1008,7 @@
-
+
@@ -1016,9 +1016,9 @@
-
+
-
+
@@ -1027,9 +1027,9 @@
-
+
-
+
@@ -1045,7 +1045,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1073,7 +1073,7 @@
Line ending mode.
-
+
Way file archives are numbered.
@@ -1083,14 +1083,14 @@
Name of the file to be used for an archive.
-
+
Indicates whether to automatically archive log files every time the specified time passes.
- Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose:
+ Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot Create multiple archive files, if they should have the same name. Choose:
@@ -1110,7 +1110,7 @@
- Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong.
+ Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing Gets written when the filename is wrong.
@@ -1128,9 +1128,9 @@
Indicates whether to archive old log file on startup.
-
+
- Indicates whether to create directories if they do not exist.
+ Indicates whether to Create directories if they Do not exist.
@@ -1138,7 +1138,7 @@
Indicates whether to enable log file(s) to be deleted.
-
+
File attributes (Windows only).
@@ -1175,7 +1175,7 @@
- Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger).
+ Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File tarGet is writing to many files (such as splitting by level or by logger).
@@ -1206,7 +1206,7 @@
-
+
@@ -1214,7 +1214,7 @@
-
+
@@ -1224,7 +1224,7 @@
-
+
@@ -1246,19 +1246,19 @@
-
+
- Name of the target.
+ Name of the tarGet.
- Condition expression. Log events who meet this condition will be forwarded to the wrapped target.
+ Condition expression. Log events who meet this condition will be forwarded to the wrapped tarGet.
@@ -1266,38 +1266,38 @@
-
+
-
-
-
+
+
+
- Name of the target.
+ Name of the tarGet.
- Windows domain name to change context to.
+ Windows Domain name to change context to.
-
+
Required impersonation level.
-
+
Type of the logon provider.
-
+
Logon Type.
@@ -1320,7 +1320,7 @@
-
+
@@ -1328,12 +1328,12 @@
-
+
-
+
@@ -1345,7 +1345,7 @@
-
+
@@ -1353,12 +1353,12 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1373,7 +1373,7 @@
- Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply)
+ Indicates whether to use a WCF service contract that is one way (fire and forGet) or two way (request-reply)
@@ -1394,7 +1394,7 @@
-
+
@@ -1418,7 +1418,7 @@
-
+
@@ -1437,7 +1437,7 @@
-
+
@@ -1448,7 +1448,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1531,7 +1531,7 @@
SMTP Server to be used for sending.
-
+
SMTP Authentication mode.
@@ -1574,7 +1574,7 @@
-
+
@@ -1590,14 +1590,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1610,21 +1610,21 @@
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1647,9 +1647,9 @@
Indicates whether to check if a queue exists before writing to it.
-
+
- Indicates whether to create the queue if it doesn't exists.
+ Indicates whether to Create the queue if it Doesn't exists.
@@ -1672,16 +1672,16 @@
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1699,15 +1699,15 @@
-
+
-
-
+
+
@@ -1716,7 +1716,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1739,12 +1739,12 @@
Indicates whether to append newline at the end of log message.
-
+
Action that should be taken if the will be more connections than .
-
+
Action that should be taken if the message is larger than maxMessageSize.
@@ -1779,15 +1779,15 @@
-
+
-
-
+
+
@@ -1795,7 +1795,7 @@
-
+
@@ -1804,7 +1804,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1827,12 +1827,12 @@
Indicates whether to append newline at the end of log message.
-
+
Action that should be taken if the will be more connections than .
-
+
Action that should be taken if the message is larger than maxMessageSize.
@@ -1902,7 +1902,7 @@
-
+
@@ -1910,7 +1910,7 @@
- Name of the target.
+ Name of the tarGet.
@@ -1928,14 +1928,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -1948,7 +1948,7 @@
-
+
@@ -1961,12 +1961,12 @@
- Name of the target.
+ Name of the tarGet.
- Indicates whether performance counter should be automatically created.
+ Indicates whether performance counter should be automatically Created.
@@ -2036,15 +2036,15 @@
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2055,7 +2055,7 @@
-
+
@@ -2073,13 +2073,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2087,14 +2087,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2107,7 +2107,7 @@
-
+
@@ -2115,12 +2115,12 @@
- Name of the target.
+ Name of the tarGet.
- Number of retries that should be attempted on the wrapped target in case of a failure.
+ Number of retries that should be attempted on the wrapped tarGet in case of a failure.
@@ -2133,13 +2133,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2147,13 +2147,13 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2161,14 +2161,14 @@
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2181,20 +2181,20 @@
-
+
-
+
-
+
- Name of the target.
+ Name of the tarGet.
@@ -2217,7 +2217,7 @@
Web service namespace. Only used with Soap.
-
+
Protocol to be used when calling web service.
@@ -2230,7 +2230,7 @@
-
+
diff --git a/FFXIVClassic Map Server/PacketProcessor.cs b/FFXIVClassic Map Server/PacketProcessor.cs
index 7474c7eb..09b203aa 100644
--- a/FFXIVClassic Map Server/PacketProcessor.cs
+++ b/FFXIVClassic Map Server/PacketProcessor.cs
@@ -349,8 +349,8 @@ namespace FFXIVClassic_Map_Server
client.QueuePacket(BasePacket.CreatePacket(BlacklistAddedPacket.BuildPacket(player.actorID, true, addBlackList.name), true, false));
break;
case 0x01CA:
- AddRemoveSocialPacket removeBlackList = new AddRemoveSocialPacket(subpacket.data);
- client.QueuePacket(BasePacket.CreatePacket(BlacklistRemovedPacket.BuildPacket(player.actorID, true, removeBlackList.name), true, false));
+ AddRemoveSocialPacket RemoveBlackList = new AddRemoveSocialPacket(subpacket.data);
+ client.QueuePacket(BasePacket.CreatePacket(BlacklistRemovedPacket.BuildPacket(player.actorID, true, RemoveBlackList.name), true, false));
break;
case 0x01CB:
int offset1 = 0;
@@ -361,8 +361,8 @@ namespace FFXIVClassic_Map_Server
client.QueuePacket(BasePacket.CreatePacket(FriendlistAddedPacket.BuildPacket(player.actorID, true, (uint)addFriendList.name.GetHashCode(), true, addFriendList.name), true, false));
break;
case 0x01CD:
- AddRemoveSocialPacket removeFriendList = new AddRemoveSocialPacket(subpacket.data);
- client.QueuePacket(BasePacket.CreatePacket(FriendlistRemovedPacket.BuildPacket(player.actorID, true, removeFriendList.name), true, false));
+ AddRemoveSocialPacket RemoveFriendList = new AddRemoveSocialPacket(subpacket.data);
+ client.QueuePacket(BasePacket.CreatePacket(FriendlistRemovedPacket.BuildPacket(player.actorID, true, RemoveFriendList.name), true, false));
break;
case 0x01CE:
int offset2 = 0;
diff --git a/FFXIVClassic Map Server/Properties/Resources.Designer.cs b/FFXIVClassic Map Server/Properties/Resources.Designer.cs
index 11a22948..75ee4efc 100644
--- a/FFXIVClassic Map Server/Properties/Resources.Designer.cs
+++ b/FFXIVClassic Map Server/Properties/Resources.Designer.cs
@@ -17,7 +17,7 @@ namespace FFXIVClassic_Map_Server.Properties {
///
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
+ // To add or Remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@@ -105,7 +105,7 @@ namespace FFXIVClassic_Map_Server.Properties {
///
///Available commands:
///Standard: mypos, music, warp
- ///Server Administration: givecurrency, giveitem, givekeyitem, removecurrency, removekeyitem, reloaditems, reloadzones
+ ///Server Administration: givecurrency, giveitem, givekeyitem, Removecurrency, Removekeyitem, reloaditems, reloadzones
///Test: test weather.
///
public static string CPhelp {
@@ -176,38 +176,38 @@ namespace FFXIVClassic_Map_Server.Properties {
///
/// Looks up a localized string similar to Removes the specified currency from the current player's inventory
///
- ///*Syntax: removecurrency <quantity>
- /// removecurrency <type> <quantity>
+ ///*Syntax: Removecurrency <quantity>
+ /// Removecurrency <type> <quantity>
///<type> is the specific type of currency desired, defaults to gil if no type specified.
///
- public static string CPremovecurrency {
+ public static string CPRemovecurrency {
get {
- return ResourceManager.GetString("CPremovecurrency", resourceCulture);
+ return ResourceManager.GetString("CPRemovecurrency", resourceCulture);
}
}
///
/// Looks up a localized string similar to Removes the specified items to the current player's inventory
///
- ///*Syntax: removeitem <itemid>
- /// removeitem <itemid> <quantity>
+ ///*Syntax: Removeitem <itemid>
+ /// Removeitem <itemid> <quantity>
///<item id> is the item's specific id as defined in the server database.
///
- public static string CPremoveitem {
+ public static string CPRemoveitem {
get {
- return ResourceManager.GetString("CPremoveitem", resourceCulture);
+ return ResourceManager.GetString("CPRemoveitem", resourceCulture);
}
}
///
/// Looks up a localized string similar to Removes the specified key item to the current player's inventory
///
- ///*Syntax: removekeyitem <itemid>
+ ///*Syntax: Removekeyitem <itemid>
///<item id> is the key item's specific id as defined in the server database.
///
- public static string CPremovekeyitem {
+ public static string CPRemovekeyitem {
get {
- return ResourceManager.GetString("CPremovekeyitem", resourceCulture);
+ return ResourceManager.GetString("CPRemovekeyitem", resourceCulture);
}
}
diff --git a/FFXIVClassic Map Server/Server.cs b/FFXIVClassic Map Server/Server.cs
index 92cb1168..1d8b6061 100644
--- a/FFXIVClassic Map Server/Server.cs
+++ b/FFXIVClassic Map Server/Server.cs
@@ -83,7 +83,9 @@ namespace FFXIVClassic_Map_Server
mWorldManager = new WorldManager(this);
mWorldManager.LoadZoneList();
mWorldManager.LoadZoneEntranceList();
- mWorldManager.LoadNPCs();
+ mWorldManager.LoadActorClasses();
+ mWorldManager.LoadSpawnLocations();
+ mWorldManager.SpawnAllActors();
IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT));
@@ -294,7 +296,7 @@ namespace FFXIVClassic_Map_Server
{
BasePacket newPacket = null;
- //Too small to even get length
+ //Too small to even Get length
if (bytesRead <= offset)
return null;
diff --git a/FFXIVClassic Map Server/WorldManager.cs b/FFXIVClassic Map Server/WorldManager.cs
index e0cbb995..9f551555 100644
--- a/FFXIVClassic Map Server/WorldManager.cs
+++ b/FFXIVClassic Map Server/WorldManager.cs
@@ -1,12 +1,21 @@
-using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server;
+using FFXIVClassic.Common;
using FFXIVClassic_Map_Server.actors.area;
+using FFXIVClassic_Map_Server.actors.chara.npc;
using FFXIVClassic_Map_Server.Actors;
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.dataobjects;
+using FFXIVClassic_Map_Server.dataobjects.chara;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send;
using FFXIVClassic_Map_Server.packets.send.actor;
+using FFXIVClassic_Map_Server.packets.send.login;
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server
{
@@ -16,6 +25,7 @@ namespace FFXIVClassic_Map_Server
private WorldMaster worldMaster = new WorldMaster();
private Dictionary zoneList;
private Dictionary zoneEntranceList;
+ private Dictionary actorClasses = new Dictionary();
private Server mServer;
@@ -66,10 +76,7 @@ namespace FFXIVClassic_Map_Server
}
}
catch (MySqlException e)
- {
- Program.Log.Error(e.ToString());
-
- }
+ { Console.WriteLine(e); }
finally
{
conn.Dispose();
@@ -105,7 +112,7 @@ namespace FFXIVClassic_Map_Server
if (zoneList.ContainsKey(parentZoneId))
{
Zone parent = zoneList[parentZoneId];
- PrivateArea privArea = new PrivateArea(parent, reader.GetUInt32("id"), reader.GetString("className"), reader.GetString("privateAreaName"), reader.GetUInt16("dayMusic"), reader.GetUInt16("nightMusic"), reader.GetUInt16("battleMusic"));
+ PrivateArea privArea = new PrivateArea(parent, reader.GetUInt32("id"), reader.GetString("className"), reader.GetString("privateAreaName"), 1, reader.GetUInt16("dayMusic"), reader.GetUInt16("nightMusic"), reader.GetUInt16("battleMusic"));
parent.AddPrivateArea(privArea);
}
else
@@ -116,16 +123,14 @@ namespace FFXIVClassic_Map_Server
}
}
catch (MySqlException e)
- {
- Program.Log.Error(e.ToString());
- }
+ { Console.WriteLine(e); }
finally
{
conn.Dispose();
}
}
- Program.Log.Info("Loaded {0} zones and {1} private areas.", count1, count2);
+ Program.Log.Info(String.Format("Loaded {0} zones and {1} private areas.", count1, count2));
}
public void LoadZoneEntranceList()
@@ -169,19 +174,17 @@ namespace FFXIVClassic_Map_Server
}
}
catch (MySqlException e)
- {
- Program.Log.Error(e.ToString());
- }
+ { Console.WriteLine(e); }
finally
{
conn.Dispose();
}
}
- Program.Log.Info("Loaded {0} zone spawn locations.", count);
+ Program.Log.Info(String.Format("Loaded {0} zone spawn locations.", count));
}
- public void LoadNPCs()
+ public void LoadActorClasses()
{
int count = 0;
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
@@ -193,20 +196,11 @@ namespace FFXIVClassic_Map_Server
string query = @"
SELECT
id,
- name,
- zoneId,
- positionX,
- positionY,
- positionZ,
- rotation,
- actorState,
- animationId,
+ classPath,
displayNameId,
- customDisplayName,
- actorClassName,
eventConditions
FROM gamedata_actor_class
- WHERE name is not NULL AND zoneId > 0
+ WHERE classPath <> ''
";
MySqlCommand cmd = new MySqlCommand(query, conn);
@@ -215,45 +209,35 @@ namespace FFXIVClassic_Map_Server
{
while (reader.Read())
{
- string customName = null;
- if (!reader.IsDBNull(10))
- customName = reader.GetString(10);
+ uint id = reader.GetUInt32("id");
+ string classPath = reader.GetString("classPath");
+ uint nameId = reader.GetUInt32("displayNameId");
+ string eventConditions = null;
+
+ if (!reader.IsDBNull(3))
+ eventConditions = reader.GetString("eventConditions");
+ else
+ eventConditions = "{}";
- Npc npc = new Npc(reader.GetUInt32(0), reader.GetString(1), reader.GetUInt32(2), reader.GetFloat(3), reader.GetFloat(4), reader.GetFloat(5), reader.GetFloat(6), reader.GetUInt16(7), reader.GetUInt32(8), reader.GetUInt32(9), customName, reader.GetString(11));
-
- if (!reader.IsDBNull(12))
- {
- string eventConditions = reader.GetString(12);
- npc.LoadEventConditions(eventConditions);
- }
-
- if (!zoneList.ContainsKey(npc.zoneId))
- continue;
- Zone zone = zoneList[npc.zoneId];
- if (zone == null)
- continue;
- npc.zone = zone;
- zone.AddActorToZone(npc);
+ ActorClass actorClass = new ActorClass(id, classPath, nameId, eventConditions);
+ actorClasses.Add(id, actorClass);
count++;
-
}
}
}
catch (MySqlException e)
- {
- Program.Log.Error(e.ToString());
- }
+ { Console.WriteLine(e); }
finally
{
conn.Dispose();
}
}
- Program.Log.Info("Loaded {0} npc(s).", count);
+ Program.Log.Info(String.Format("Loaded {0} actor classes.", count));
}
- public void LoadNPCs(uint zoneId)
+ public void LoadSpawnLocations()
{
int count = 0;
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
@@ -264,69 +248,80 @@ namespace FFXIVClassic_Map_Server
string query = @"
SELECT
- id,
- name,
- zoneId,
+ actorClassId,
+ uniqueId,
+ zoneId,
+ privateAreaName,
+ privateAreaLevel,
positionX,
positionY,
positionZ,
rotation,
actorState,
animationId,
- displayNameId,
- customDisplayName,
- actorClassName,
- eventConditions
- FROM gamedata_actor_class
- WHERE name is not NULL AND zoneId = @zoneId
+ customDisplayName
+ FROM server_spawn_locations
";
MySqlCommand cmd = new MySqlCommand(query, conn);
- cmd.Parameters.AddWithValue("@zoneId", zoneId);
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
string customName = null;
- if (!reader.IsDBNull(10))
- customName = reader.GetString(10);
+ if (!reader.IsDBNull(11))
+ customName = reader.GetString("customDisplayName");
- Npc npc = new Npc(reader.GetUInt32(0), reader.GetString(1), reader.GetUInt32(2), reader.GetFloat(3), reader.GetFloat(4), reader.GetFloat(5), reader.GetFloat(6), reader.GetUInt16(7), reader.GetUInt32(8), reader.GetUInt32(9), customName, reader.GetString(11));
+ uint classId = reader.GetUInt32("actorClassId");
+ string uniqueId = reader.GetString("uniqueId");
+ uint zoneId = reader.GetUInt32("zoneId");
+ string privAreaName = reader.GetString("privateAreaName");
+ uint privAreaLevel = reader.GetUInt32("privateAreaLevel");
+ float x = reader.GetFloat("positionX");
+ float y = reader.GetFloat("positionY");
+ float z = reader.GetFloat("positionZ");
+ float rot = reader.GetFloat("rotation");
+ ushort state = reader.GetUInt16("actorState");
+ uint animId = reader.GetUInt32("animationId");
- if (!reader.IsDBNull(12))
- {
- string eventConditions = reader.GetString(12);
- npc.LoadEventConditions(eventConditions);
- }
-
- if (!zoneList.ContainsKey(npc.zoneId))
+ if (!actorClasses.ContainsKey(classId))
continue;
- Zone zone = zoneList[npc.zoneId];
+ if (!zoneList.ContainsKey(zoneId))
+ continue;
+
+ Zone zone = zoneList[zoneId];
if (zone == null)
continue;
- npc.zone = zone;
- zone.AddActorToZone(npc);
- count++;
+ SpawnLocation spawn = new SpawnLocation(classId, uniqueId, zoneId, privAreaName, privAreaLevel, x, y, z, rot, state, animId);
+
+ zone.AddSpawnLocation(spawn);
+
+ count++;
}
}
-
+
}
catch (MySqlException e)
- {
- Program.Log.Error(e.ToString());
- }
+ { Console.WriteLine(e); }
finally
{
conn.Dispose();
}
}
- Program.Log.Info("Loaded {0} npc(s).", count);
+ Program.Log.Info(String.Format("Loaded {0} spawn(s).", count));
}
- //Moves the actor to the new zone if exists. No packets are sent nor position Changed.
+ public void SpawnAllActors()
+ {
+ Program.Log.Info("Spawning actors...");
+ foreach (Zone z in zoneList.Values)
+ z.SpawnAllActors(true);
+ }
+
+ //Moves the actor to the new zone if exists. No packets are sent nor position changed.
public void DoSeamlessZoneChange(Player player, uint destinationZoneId)
{
Area oldZone;
@@ -340,7 +335,7 @@ namespace FFXIVClassic_Map_Server
//Add player to new zone and update
Zone newZone = GetZone(destinationZoneId);
- //This server Does not contain that zoneId
+ //This server does not contain that zoneId
if (newZone == null)
return;
@@ -381,7 +376,7 @@ namespace FFXIVClassic_Map_Server
newArea = GetZone(destinationZoneId);
else
newArea = GetZone(destinationZoneId).GetPrivateArea(destinationPrivateArea, 0);
- //This server Does not contain that zoneId
+ //This server does not contain that zoneId
if (newArea == null)
return;
@@ -451,11 +446,11 @@ namespace FFXIVClassic_Map_Server
//Add player to new zone and update
Zone zone = GetZone(player.zoneId);
- //This server Does not contain that zoneId
+ //This server does not contain that zoneId
if (zone == null)
return;
- //Set the current zone and Add player
+ //Set the current zone and add player
player.zone = zone;
LuaEngine.OnBeginLogin(player);
@@ -469,14 +464,14 @@ namespace FFXIVClassic_Map_Server
LuaEngine.OnZoneIn(player);
}
- public void ReloadZone(uint zoneId)
+ public void reloadZone(uint zoneId)
{
if (!zoneList.ContainsKey(zoneId))
return;
Zone zone = zoneList[zoneId];
- //zone.Clear();
- LoadNPCs(zone.actorId);
+ //zone.clear();
+ //LoadNPCs(zone.actorId);
}
@@ -559,6 +554,15 @@ namespace FFXIVClassic_Map_Server
else
return null;
}
+
+ public ActorClass GetActorClass(uint id)
+ {
+ if (actorClasses.ContainsKey(id))
+ return actorClasses[id];
+ else
+ return null;
+ }
+
}
}
diff --git a/FFXIVClassic Map Server/actors/Actor.cs b/FFXIVClassic Map Server/actors/Actor.cs
index 53e2c9b2..c323d980 100644
--- a/FFXIVClassic Map Server/actors/Actor.cs
+++ b/FFXIVClassic Map Server/actors/Actor.cs
@@ -3,13 +3,15 @@ using FFXIVClassic_Map_Server.actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.packets.send.actor.events;
+using FFXIVClassic.Common;
using System;
using System.Collections.Generic;
-
+using FFXIVClassic_Map_Server.actors.area;
+
namespace FFXIVClassic_Map_Server.Actors
{
class Actor
- {
+ {
public uint actorId;
public string actorName;
@@ -29,6 +31,7 @@ namespace FFXIVClassic_Map_Server.Actors
public bool spawnedFirstTime = false;
+ public string classPath;
public string className;
public List classParams;
@@ -298,6 +301,53 @@ namespace FFXIVClassic_Map_Server.Actors
SubPacket ChangeSpeedPacket = SetActorSpeedPacket.BuildPacket(actorId, actorId, moveSpeeds[0], moveSpeeds[1], moveSpeeds[2]);
zone.BroadcastPacketAroundActor(this, ChangeSpeedPacket);
}
+
+ public void generateActorName(int actorNumber)
+ {
+ //Format Class Name
+ string className = this.className.Replace("Populace", "Ppl")
+ .Replace("Monster", "Mon")
+ .Replace("Crowd", "Crd")
+ .Replace("MapObj", "Map")
+ .Replace("Object", "Obj")
+ .Replace("Retainer", "Rtn")
+ .Replace("Standard", "Std");
+ className = Char.ToLowerInvariant(className[0]) + className.Substring(1);
+
+ //Format Zone Name
+ string zoneName = zone.zoneName.Replace("Field", "Fld")
+ .Replace("Dungeon", "Dgn")
+ .Replace("Town", "Twn")
+ .Replace("Battle", "Btl")
+ .Replace("Test", "Tes")
+ .Replace("Event", "Evt")
+ .Replace("Ship", "Shp")
+ .Replace("Office", "Ofc");
+ if (zone is PrivateArea)
+ {
+ //Check if "normal"
+ zoneName = zoneName.Remove(zoneName.Length - 1, 1) + "P";
+ }
+ zoneName = Char.ToLowerInvariant(zoneName[0]) + zoneName.Substring(1);
+
+ try
+ {
+ className = className.Substring(0, 20 - zoneName.Length);
+ }
+ catch (ArgumentOutOfRangeException e)
+ {}
+
+ //Convert actor number to base 63
+ string classNumber = Utils.ToStringBase63(actorNumber);
+
+ //Get stuff after @
+ uint zoneId = zone.actorId;
+ uint privLevel = 0;
+ if (zone is PrivateArea)
+ privLevel = ((PrivateArea)zone).GetPrivateAreaLevel();
+
+ actorName = String.Format("{0}_{1}_{2}@{3:X3}{4:X2}", className, zoneName, classNumber, zoneId, privLevel);
+ }
}
}
diff --git a/FFXIVClassic Map Server/actors/area/Area.cs b/FFXIVClassic Map Server/actors/area/Area.cs
index 9d66bc23..5b510fce 100644
--- a/FFXIVClassic Map Server/actors/area/Area.cs
+++ b/FFXIVClassic Map Server/actors/area/Area.cs
@@ -1,9 +1,18 @@
-using FFXIVClassic_Map_Server.packets;
+using FFXIVClassic_Map_Server;
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.packets;
+using FFXIVClassic_Map_Server.actors.area;
+using FFXIVClassic_Map_Server.actors.chara.npc;
+using FFXIVClassic_Map_Server.dataobjects;
+using FFXIVClassic_Map_Server.dataobjects.chara;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
using MoonSharp.Interpreter;
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.Actors
{
@@ -15,15 +24,16 @@ namespace FFXIVClassic_Map_Server.Actors
public ushort weatherNormal, weatherCommon, weatherRare;
public ushort bgmDay, bgmNight, bgmBattle;
- private string classPath;
+ protected string classPath;
public int boundingGridSize = 50;
public int minX = -1000, minY = -1000, maxX = 1000, maxY = 1000;
- private int numXBlocks, numYBlocks;
- private int halfWidth, halfHeight;
+ protected int numXBlocks, numYBlocks;
+ protected int halfWidth, halfHeight;
- private Dictionary mActorList = new Dictionary();
- private List[,] mActorBlock;
+ protected List mSpawnLocations = new List();
+ protected Dictionary mActorList = new Dictionary();
+ protected List[,] mActorBlock;
Script areaScript;
@@ -329,5 +339,18 @@ namespace FFXIVClassic_Map_Server.Actors
}
}
+ public void SpawnActor(SpawnLocation location)
+ {
+ ActorClass actorClass = Server.GetWorldManager().GetActorClass(location.classId);
+
+ if (actorClass == null)
+ return;
+
+ Npc npc = new Npc(mActorList.Count + 1, actorClass.actorClassId, location.uniqueId, actorId, location.x, location.y, location.z, location.rot, location.state, location.animId, actorClass.displayNameId, null, actorClass.classPath);
+ npc.loadEventConditions(actorClass.eventConditions);
+
+ AddActorToZone(npc);
+ }
+
}
}
diff --git a/FFXIVClassic Map Server/actors/area/PrivateArea.cs b/FFXIVClassic Map Server/actors/area/PrivateArea.cs
index 997adb2c..dd7cf9de 100644
--- a/FFXIVClassic Map Server/actors/area/PrivateArea.cs
+++ b/FFXIVClassic Map Server/actors/area/PrivateArea.cs
@@ -2,7 +2,11 @@
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
+using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.area
{
@@ -10,12 +14,14 @@ namespace FFXIVClassic_Map_Server.actors.area
{
private Zone parentZone;
private string privateAreaName;
+ private uint privateAreaLevel;
- public PrivateArea(Zone parent, uint id, string className, string privateAreaName,ushort bgmDay, ushort bgmNight, ushort bgmBattle)
+ public PrivateArea(Zone parent, uint id, string className, string privateAreaName, uint privateAreaLevel, ushort bgmDay, ushort bgmNight, ushort bgmBattle)
: base(id, parent.zoneName, parent.regionId, className, bgmDay, bgmNight, bgmBattle, parent.isIsolated, parent.isInn, parent.canRideChocobo, parent.canStealth, true)
{
this.parentZone = parent;
this.privateAreaName = privateAreaName;
+ this.privateAreaLevel = privateAreaLevel;
}
public string GetPrivateAreaName()
@@ -23,6 +29,11 @@ namespace FFXIVClassic_Map_Server.actors.area
return privateAreaName;
}
+ public uint GetPrivateAreaLevel()
+ {
+ return privateAreaLevel;
+ }
+
public Zone GetParentZone()
{
return parentZone;
@@ -41,6 +52,17 @@ namespace FFXIVClassic_Map_Server.actors.area
ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams).DebugPrintSubPacket();
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
}
-
+
+
+ public void AddSpawnLocation(SpawnLocation spawn)
+ {
+ mSpawnLocations.Add(spawn);
+ }
+
+ public void SpawnAllActors()
+ {
+ foreach (SpawnLocation spawn in mSpawnLocations)
+ SpawnActor(spawn);
+ }
}
}
diff --git a/FFXIVClassic Map Server/actors/area/SpawnLocation.cs b/FFXIVClassic Map Server/actors/area/SpawnLocation.cs
new file mode 100644
index 00000000..87c36f76
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/area/SpawnLocation.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.area
+{
+ class SpawnLocation
+ {
+ public uint classId;
+ public string uniqueId;
+ public uint zoneId;
+ public string privAreaName;
+ public uint privAreaLevel;
+ public float x;
+ public float y;
+ public float z;
+ public float rot;
+ public ushort state;
+ public uint animId;
+
+ public SpawnLocation(uint classId, string uniqueId, uint zoneId, string privAreaName, uint privAreaLevel, float x, float y, float z, float rot, ushort state, uint animId)
+ {
+ this.classId = classId;
+ this.uniqueId = uniqueId;
+ this.zoneId = zoneId;
+ this.privAreaName = privAreaName;
+ this.privAreaLevel = privAreaLevel;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.rot = rot;
+ this.state = state;
+ this.animId = animId;
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/area/Zone.cs b/FFXIVClassic Map Server/actors/area/Zone.cs
index 24e8fa0a..51622b36 100644
--- a/FFXIVClassic Map Server/actors/area/Zone.cs
+++ b/FFXIVClassic Map Server/actors/area/Zone.cs
@@ -1,13 +1,20 @@
-using FFXIVClassic_Map_Server.packets;
+using FFXIVClassic_Map_Server;
+using FFXIVClassic.Common;
+using FFXIVClassic_Map_Server.packets;
+using FFXIVClassic_Map_Server.actors.chara.npc;
using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor;
+using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.actors.area
{
class Zone : Area
- {
+ {
Dictionary> privateAreas = new Dictionary>();
public Zone(uint id, string zoneName, ushort regionId, string className, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid)
@@ -50,5 +57,40 @@ namespace FFXIVClassic_Map_Server.actors.area
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
}
+ public void AddSpawnLocation(SpawnLocation spawn)
+ {
+ //Is it in a private area?
+ if (!spawn.privAreaName.Equals(""))
+ {
+ if (privateAreas.ContainsKey(spawn.privAreaName))
+ {
+ Dictionary levels = privateAreas[spawn.privAreaName];
+ if (levels.ContainsKey(spawn.privAreaLevel))
+ levels[spawn.privAreaLevel].AddSpawnLocation(spawn);
+ else
+ Program.Log.Error("Tried to add a spawn location to non-existing private area level \"{0}\" in area {1} in zone {2}", spawn.privAreaName, spawn.privAreaLevel, zoneName);
+ }
+ else
+ Program.Log.Error("Tried to add a spawn location to non-existing private area \"{0}\" in zone {1}", spawn.privAreaName, zoneName);
+ }
+ else
+ mSpawnLocations.Add(spawn);
+ }
+
+ public void SpawnAllActors(bool doPrivAreas)
+ {
+ foreach (SpawnLocation spawn in mSpawnLocations)
+ SpawnActor(spawn);
+
+ if (doPrivAreas)
+ {
+ foreach (Dictionary areas in privateAreas.Values)
+ {
+ foreach (PrivateArea pa in areas.Values)
+ pa.SpawnAllActors();
+ }
+ }
+ }
+
}
}
diff --git a/FFXIVClassic Map Server/actors/chara/ParameterTemp.cs b/FFXIVClassic Map Server/actors/chara/ParameterTemp.cs
index 399e7e84..71f71767 100644
--- a/FFXIVClassic Map Server/actors/chara/ParameterTemp.cs
+++ b/FFXIVClassic Map Server/actors/chara/ParameterTemp.cs
@@ -4,7 +4,7 @@
{
public short tp = 0;
- public int targetInformation = 0;
+ public int tarGetInformation = 0;
public ushort[] maxCommandRecastTime = new ushort[40];
diff --git a/FFXIVClassic Map Server/actors/chara/npc/ActorClass.cs b/FFXIVClassic Map Server/actors/chara/npc/ActorClass.cs
new file mode 100644
index 00000000..6d3da091
--- /dev/null
+++ b/FFXIVClassic Map Server/actors/chara/npc/ActorClass.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FFXIVClassic_Map_Server.actors.chara.npc
+{
+ class ActorClass
+ {
+ public readonly uint actorClassId;
+ public readonly string classPath;
+ public readonly uint displayNameId;
+ public readonly string eventConditions;
+
+ public ActorClass(uint id, string classPath, uint nameId, string eventConditions)
+ {
+ this.actorClassId = id;
+ this.classPath = classPath;
+ this.displayNameId = nameId;
+ this.eventConditions = eventConditions;
+ }
+ }
+}
diff --git a/FFXIVClassic Map Server/actors/chara/npc/Npc.cs b/FFXIVClassic Map Server/actors/chara/npc/Npc.cs
index 83e10097..eb4aea77 100644
--- a/FFXIVClassic Map Server/actors/chara/npc/Npc.cs
+++ b/FFXIVClassic Map Server/actors/chara/npc/Npc.cs
@@ -1,41 +1,54 @@
using FFXIVClassic.Common;
-using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.actors;
using FFXIVClassic_Map_Server.Actors.Chara;
+using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.lua;
+using FFXIVClassic_Map_Server.packets;
+using FFXIVClassic_Map_Server.packets.receive.events;
using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.utils;
+using MoonSharp.Interpreter;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
namespace FFXIVClassic_Map_Server.Actors
{
class Npc : Character
{
private uint actorClassId;
+ private string uniqueIdentifier;
public NpcWork npcWork = new NpcWork();
- public Npc(uint id, string actorName, uint zoneId, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, uint displayNameId, string customDisplayName, string className)
- : base(id)
+ public Npc(int actorNumber, uint classId, string uniqueId, uint zoneId, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, uint displayNameId, string customDisplayName, string classPath)
+ : base((4 << 28 | zoneId << 19 | (uint)actorNumber))
{
- this.actorName = actorName;
- this.actorClassId = id;
this.positionX = posX;
this.positionY = posY;
this.positionZ = posZ;
this.rotation = rot;
this.animationId = animationId;
- this.className = className;
this.displayNameId = displayNameId;
this.customDisplayName = customDisplayName;
- this.zoneId = zoneId;
+ this.uniqueIdentifier = uniqueId;
- LoadNpcTemplate(id);
+ this.zoneId = zoneId;
+ this.zone = Server.GetWorldManager().GetZone(zoneId);
+
+ this.actorClassId = classId;
+
+ loadNpcAppearance(classId);
+
+ this.classPath = classPath;
+ className = classPath.Substring(classPath.LastIndexOf("/")+1);
charaWork.battleSave.potencial = 1.0f;
@@ -56,6 +69,11 @@ namespace FFXIVClassic_Map_Server.Actors
charaWork.property[3] = 1;
charaWork.property[4] = 1;
+
+ npcWork.pushCommand = 0x271D;
+ npcWork.pushCommandPriority = 1;
+
+ generateActorName((int)actorNumber);
}
public SubPacket CreateAddActorPacket(uint playerActorId)
@@ -63,19 +81,34 @@ namespace FFXIVClassic_Map_Server.Actors
return AddActorPacket.BuildPacket(actorId, playerActorId, 8);
}
+ // actorClassId, [], [], numBattleCommon, [battleCommon], numEventCommon, [eventCommon], args for either initForBattle/initForEvent
public override SubPacket CreateScriptBindPacket(uint playerActorId)
{
List lParams;
Player player = Server.GetWorldManager().GetPCInWorld(playerActorId);
- lParams = LuaEngine.DoActorInstantiate(player, this);
+ lParams = DoActorInit(player);
if (lParams == null)
{
- className = "PopulaceStandard";
- lParams = LuaUtils.CreateLuaParamList("/Chara/Npc/Populace/PopulaceStandard", false, false, false, false, false, 0xF47F6, false, false, 0, 1, "TEST");
+ string classPathFake = "/Chara/Npc/Populace/PopulaceStandard";
+ string classNameFake = "PopulaceStandard";
+ lParams = LuaUtils.CreateLuaParamList(classPathFake, false, false, false, false, false, 0xF47F6, false, false, 0, 0);
+ ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, classNameFake, lParams).DebugPrintSubPacket();
+ return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, classNameFake, lParams);
+ }
+ else
+ {
+ lParams.Insert(0, new LuaParam(2, classPath));
+ lParams.Insert(1, new LuaParam(4, 4));
+ lParams.Insert(2, new LuaParam(4, 4));
+ lParams.Insert(3, new LuaParam(4, 4));
+ lParams.Insert(4, new LuaParam(4, 4));
+ lParams.Insert(5, new LuaParam(4, 4));
+ lParams.Insert(6, new LuaParam(0, (int)actorClassId));
}
+ ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams).DebugPrintSubPacket();
return ActorInstantiatePacket.BuildPacket(actorId, playerActorId, actorName, className, lParams);
}
@@ -142,6 +175,8 @@ namespace FFXIVClassic_Map_Server.Actors
}
propPacketUtil.AddProperty("npcWork.hateType");
+ propPacketUtil.AddProperty("npcWork.pushCommand");
+ propPacketUtil.AddProperty("npcWork.pushCommandPriority");
return BasePacket.CreatePacket(propPacketUtil.Done(), true, false);
}
@@ -151,7 +186,7 @@ namespace FFXIVClassic_Map_Server.Actors
return actorClassId;
}
- public void LoadNpcTemplate(uint id)
+ public void loadNpcAppearance(uint id)
{
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)))
{
@@ -166,7 +201,7 @@ namespace FFXIVClassic_Map_Server.Actors
hairStyle,
hairHighlightColor,
hairVariation,
- faceType,
+ faceType,
characteristics,
characteristicsColor,
faceEyebrows,
@@ -220,26 +255,32 @@ namespace FFXIVClassic_Map_Server.Actors
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.MAINHAND] = reader.GetUInt32(19);
- //appearanceIds[Character.WEAPON2] = reader.GetUInt32(22);
+ appearanceIds[Character.OFFHAND] = reader.GetUInt32(20);
+ appearanceIds[Character.SPMAINHAND] = reader.GetUInt32(21);
+ appearanceIds[Character.SPOFFHAND] = reader.GetUInt32(22);
+ appearanceIds[Character.THROWING] = reader.GetUInt32(23);
+ appearanceIds[Character.PACK] = reader.GetUInt32(24);
+ appearanceIds[Character.POUCH] = reader.GetUInt32(25);
appearanceIds[Character.HEADGEAR] = reader.GetUInt32(26);
appearanceIds[Character.BODYGEAR] = reader.GetUInt32(27);
appearanceIds[Character.LEGSGEAR] = reader.GetUInt32(28);
appearanceIds[Character.HANDSGEAR] = reader.GetUInt32(29);
appearanceIds[Character.FEETGEAR] = reader.GetUInt32(30);
appearanceIds[Character.WAISTGEAR] = reader.GetUInt32(31);
- appearanceIds[Character.R_EAR] = reader.GetUInt32(32);
- appearanceIds[Character.L_EAR] = reader.GetUInt32(33);
- appearanceIds[Character.R_RINGFINGER] = reader.GetUInt32(36);
- appearanceIds[Character.L_RINGFINGER] = reader.GetUInt32(37);
+ appearanceIds[Character.NECKGEAR] = reader.GetUInt32(32);
+ appearanceIds[Character.R_EAR] = reader.GetUInt32(33);
+ appearanceIds[Character.L_EAR] = reader.GetUInt32(34);
+ appearanceIds[Character.R_INDEXFINGER] = reader.GetUInt32(35);
+ appearanceIds[Character.L_INDEXFINGER] = reader.GetUInt32(36);
+ appearanceIds[Character.R_RINGFINGER] = reader.GetUInt32(37);
+ appearanceIds[Character.L_RINGFINGER] = reader.GetUInt32(38);
}
}
}
catch (MySqlException e)
- {
- Program.Log.Error(e.ToString());
- }
+ { Console.WriteLine(e); }
finally
{
conn.Dispose();
@@ -247,10 +288,132 @@ namespace FFXIVClassic_Map_Server.Actors
}
}
- public void LoadEventConditions(string eventConditions)
+ public void loadEventConditions(string eventConditions)
{
EventList conditions = JsonConvert.DeserializeObject(eventConditions);
this.eventConditions = conditions;
}
+
+ public List DoActorInit(Player player)
+ {
+ Script parent = null, child = null;
+
+ if (File.Exists("./scripts/base/" + classPath + ".lua"))
+ parent = LuaEngine.LoadScript("./scripts/base/" + classPath + ".lua");
+ if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)))
+ child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier));
+
+ if (parent == null && child == null)
+ {
+ LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", GetName()));
+ return null;
+ }
+
+ DynValue result;
+
+ if (child != null && child.Globals["init"] != null)
+ result = child.Call(child.Globals["init"], this);
+ else if (parent != null && parent.Globals["init"] != null)
+ result = parent.Call(parent.Globals["init"], this);
+ else
+ return null;
+
+ List lparams = LuaUtils.CreateLuaParamList(result);
+ return lparams;
+ }
+
+ public void DoEventStart(Player player, EventStartPacket eventStart)
+ {
+ Script parent = null, child = null;
+
+ if (File.Exists("./scripts/base/" + classPath + ".lua"))
+ parent = LuaEngine.LoadScript("./scripts/base/" + classPath + ".lua");
+ if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)))
+ child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier));
+
+ if (parent == null)
+ {
+ LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", GetName()));
+ return;
+ }
+
+ //Have to do this to combine LuaParams
+ List