more work on commands

- moved script object to wrapper class to catch and log exceptions
- added loggers for basepacket/subpacket (todo: colour and use them in NLog.config)
- finished up most commands (todo: !property and !property2)
- todo: create and use mysql wrapper class to log exceptions
This commit is contained in:
Tahir Akhlaq 2016-06-17 05:05:31 +01:00
parent 57b9d5ab99
commit 1ad2b5d7d0
35 changed files with 780 additions and 958 deletions

View File

@ -35,6 +35,14 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<HintPath>..\packages\MySql.Data.6.9.8\lib\net45\MySql.Data.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.5\lib\net45\NLog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
@ -49,10 +57,12 @@
<Compile Include="Blowfish.cs" /> <Compile Include="Blowfish.cs" />
<Compile Include="EfficientHashTables.cs" /> <Compile Include="EfficientHashTables.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sql.cs" />
<Compile Include="STA_INIFile.cs" /> <Compile Include="STA_INIFile.cs" />
<Compile Include="Utils.cs" /> <Compile Include="Utils.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

View File

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using NLog;
namespace FFXIVClassic.Common
{
/*
class SqlCommand
{
public static Logger Log = LogManager.GetCurrentClassLogger();
public SqlCommand()
{
}
public SqlCommand(string cmdText)
{
try
{
MySqlCommand.MySqlCommand("");
}
}
public SqlCommand(string cmdText, MySqlConnection connection);
public SqlCommand(string cmdText, MySqlConnection connection, MySqlTransaction transaction);
~SqlCommand()
{
}
public int CacheAge { get; set; }
public string CommandText { get; set; }
public int CommandTimeout { get; set; }
public CommandType CommandType { get; set; }
public MySqlConnection Connection { get; set; }
public bool DesignTimeVisible { get; set; }
public bool EnableCaching { get; set; }
public bool IsPrepared { get; }
public long LastInsertedId { get; }
public MySqlParameterCollection Parameters { get; }
public MySqlTransaction Transaction { get; set; }
public UpdateRowSource UpdatedRowSource { get; set; }
protected DbConnection DbConnection { get; set; }
protected DbParameterCollection DbParameterCollection { get; }
protected DbTransaction DbTransaction { get; set; }
public IAsyncResult BeginExecuteNonQuery();
public IAsyncResult BeginExecuteNonQuery(AsyncCallback callback, object stateObject);
public IAsyncResult BeginExecuteReader();
public IAsyncResult BeginExecuteReader(CommandBehavior behavior);
public void Cancel();
public SqlCommand Clone();
public MySqlParameter CreateParameter();
public void Dispose();
public int EndExecuteNonQuery(IAsyncResult asyncResult);
public MySqlDataReader EndExecuteReader(IAsyncResult result);
public int ExecuteNonQuery();
public MySqlDataReader ExecuteReader();
public MySqlDataReader ExecuteReader(CommandBehavior behavior);
public object ExecuteScalar();
public void Prepare();
protected DbParameter CreateDbParameter();
protected void Dispose(bool disposing);
protected DbDataReader ExecuteDbDataReader(CommandBehavior behavior);
}
*/
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.9.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>
</configuration>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="NLog" version="4.3.5" tarGetFramework="net45" /> <package id="MySql.Data" version="6.9.8" targetFramework="net45" />
<package id="NLog" version="4.3.5" tarGetFramework="net45" targetFramework="net45" />
</packages> </packages>

View File

@ -12,13 +12,13 @@ namespace FFXIVClassic_Lobby_Server
public static Logger Log; public static Logger Log;
static void Main(string[] args) static void Main(string[] args)
{ {
// set up logging // set up logging
Log = LogManager.GetCurrentClassLogger(); Log = LogManager.GetCurrentClassLogger();
#if DEBUG #if DEBUG
TextWriterTraceListener myWriter = new TextWriterTraceListener(System.Console.Out); TextWriterTraceListener myWriter = new TextWriterTraceListener(System.Console.Out);
Debug.Listeners.Add(myWriter); Debug.Listeners.Add(myWriter);
#endif #endif
Program.Log.Info("--------FFXIV 1.0 Lobby Server--------"); Program.Log.Info("--------FFXIV 1.0 Lobby Server--------");
@ -55,6 +55,9 @@ namespace FFXIVClassic_Lobby_Server
{ {
Server server = new Server(); Server server = new Server();
server.StartServer(); server.StartServer();
while (true)
Thread.Sleep(1000);
} }
Program.Log.Info("Press any key to continue..."); Program.Log.Info("Press any key to continue...");

View File

@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
using System.Diagnostics; using System.Diagnostics;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using System.IO; using System.IO;
using NLog;
namespace FFXIVClassic_Lobby_Server.packets namespace FFXIVClassic_Lobby_Server.packets
{ {
@ -21,7 +22,7 @@ namespace FFXIVClassic_Lobby_Server.packets
public class BasePacket public class BasePacket
{ {
public static Logger Log = LogManager.GetCurrentClassLogger();
public const int TYPE_ZONE = 1; public const int TYPE_ZONE = 1;
public const int TYPE_CHAT = 2; public const int TYPE_CHAT = 2;
public const int BASEPACKET_SIZE = 0x10; public const int BASEPACKET_SIZE = 0x10;
@ -332,12 +333,12 @@ namespace FFXIVClassic_Lobby_Server.packets
#endregion #endregion
public void DebugPrintPacket() public void DebugPrintPacket()
{ {
#if DEBUG #if DEBUG
// todo: create new target for colourful packet logging // todo: create new target for colourful packet logging
//Console.BackgroundColor = ConsoleColor.DarkYellow; //Console.BackgroundColor = ConsoleColor.DarkYellow;
Program.Log.Debug("IsAuth: {0} Size: 0x{1:X}, NumSubpackets: {2}{3}{4}", header.isAuthenticated, header.packetSize, header.numSubpackets, Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes())); Log.Debug("IsAuth: {0} Size: 0x{1:X}, NumSubpackets: {2}{3}{4}", header.isAuthenticated, header.packetSize, header.numSubpackets, Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes()));
foreach (SubPacket sub in GetSubpackets()) foreach (SubPacket sub in GetSubpackets())
{ {

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using NLog;
namespace FFXIVClassic_Lobby_Server.packets namespace FFXIVClassic_Lobby_Server.packets
{ {
@ -26,6 +27,7 @@ namespace FFXIVClassic_Lobby_Server.packets
public class SubPacket public class SubPacket
{ {
public static Logger Log = LogManager.GetCurrentClassLogger();
public const int SUBPACKET_SIZE = 0x10; public const int SUBPACKET_SIZE = 0x10;
public const int GAMEMESSAGE_SIZE = 0x10; public const int GAMEMESSAGE_SIZE = 0x10;
@ -141,14 +143,14 @@ namespace FFXIVClassic_Lobby_Server.packets
{ {
#if DEBUG #if DEBUG
// todo: create new target for colourful packet logging // todo: create new target for colourful packet logging
Program.Log.Debug("Size: 0x{0:X}{1}{2}", header.subpacketSize, Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes())); Log.Debug("Size: 0x{0:X}{1}{2}", header.subpacketSize, Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes()));
if (header.type == 0x03) if (header.type == 0x03)
{ {
Program.Log.Debug("Opcode: 0x{0:X}{1}{2}", gameMessage.opcode, Environment.NewLine, Utils.ByteArrayToHex(GetGameMessageBytes(), SUBPACKET_SIZE)); Log.Debug("Opcode: 0x{0:X}{1}{2}", gameMessage.opcode, Environment.NewLine, Utils.ByteArrayToHex(GetGameMessageBytes(), SUBPACKET_SIZE));
} }
Program.Log.Debug("Data: {0}{1}", Environment.NewLine, Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE)); Log.Debug("Data: {0}{1}", Environment.NewLine, Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE));
#endif #endif
} }

View File

@ -73,418 +73,6 @@ namespace FFXIVClassic_Map_Server
} }
} }
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<uint, ConnectedPlayer> entry in mConnectedPlayerList)
{
BasePacket musicPacket = BasePacket.CreatePacket(SetMusicPacket.BuildPacket(entry.Value.actorID, musicId, 1), true, false);
entry.Value.QueuePacket(musicPacket);
}
}
}
/// <summary>
/// Teleports player to a location on a predefined list
/// </summary>
/// <param name="client">The current player</param>
/// <param name="id">Predefined list: &lt;ffxiv_database&gt;\server_zones_spawnlocations</param>
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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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<uint, ConnectedPlayer> 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);
}
}
}
*/
}
/// <summary> /// <summary>
/// We only use the default options for SendMessagePacket. /// We only use the default options for SendMessagePacket.
/// May as well make it less unwieldly to view /// May as well make it less unwieldly to view
@ -512,8 +100,8 @@ namespace FFXIVClassic_Map_Server
) )
.SelectMany(str => str).ToArray(); .SelectMany(str => str).ToArray();
split = split.Select(temp => temp.ToLower()).ToArray(); // Ignore case on commands split = split.Select(temp => temp.ToLower()).ToArray(); // Ignore case on commands
var cmd = split?.ElementAt(0); var cmd = split?.ElementAt(0);
if (cmd.Any()) if (cmd.Any())
@ -543,334 +131,63 @@ namespace FFXIVClassic_Map_Server
LuaEngine.RunGMCommand(player, cmd.ToString(), split.ToArray()); LuaEngine.RunGMCommand(player, cmd.ToString(), split.ToArray());
return true; return true;
} }
// Debug // Debug
//SendMessage(client, string.Join(",", split)); //SendMessage(client, string.Join(",", split));
if (split.Length >= 1) if (split.Length >= 1)
{ {
#region !help
if (split[0].Equals("help")) #region !reloaditems
{ if (split[0].Equals("reloaditems"))
if (split.Length == 1) {
{ Program.Log.Info(String.Format("Got request to reload item gamedata"));
SendMessage(client, Resources.CPhelp); SendMessage(client, "Reloading Item Gamedata...");
} gamedataItems.Clear();
if (split.Length == 2) gamedataItems = Database.GetItemGamedata();
{ Program.Log.Info(String.Format("Loaded {0} items.", gamedataItems.Count));
if (split[1].Equals("mypos")) SendMessage(client, String.Format("Loaded {0} items.", gamedataItems.Count));
SendMessage(client, Resources.CPmypos); return true;
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 #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 #region !sendpacket
else if (split[0].Equals("sendpacket")) else if (split[0].Equals("sendpacket"))
{ {
if (split.Length < 2) if (split.Length < 2)
return false; return false;
try try
{ {
SendPacket(client, "./packets/" + split[1]); SendPacket(client, "./packets/" + split[1]);
return true; return true;
} }
catch (Exception e) catch (Exception e)
{ {
Program.Log.Error("Could not load packet: " + e); Program.Log.Error("Could not load packet: " + e);
} }
} }
#endregion #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 #region !property
else if (split[0].Equals("property")) else if (split[0].Equals("property"))
{ {
if (split.Length == 4) if (split.Length == 4)
{ {
ChangeProperty(Utils.MurmurHash2(split[1], 0), Convert.ToUInt32(split[2], 16), split[3]); ChangeProperty(Utils.MurmurHash2(split[1], 0), Convert.ToUInt32(split[2], 16), split[3]);
} }
return true; return true;
} }
#endregion #endregion
#region !property2 #region !property2
else if (split[0].Equals("property2")) else if (split[0].Equals("property2"))
{ {
if (split.Length == 4) if (split.Length == 4)
{ {
ChangeProperty(Convert.ToUInt32(split[1], 16), Convert.ToUInt32(split[2], 16), split[3]); ChangeProperty(Convert.ToUInt32(split[1], 16), Convert.ToUInt32(split[2], 16), split[3]);
} }
return true; return true;
} }
#endregion #endregion
} }

View File

@ -119,6 +119,7 @@
<Compile Include="lua\LuaParam.cs" /> <Compile Include="lua\LuaParam.cs" />
<Compile Include="lua\LuaNpc.cs" /> <Compile Include="lua\LuaNpc.cs" />
<Compile Include="lua\LuaPlayer.cs" /> <Compile Include="lua\LuaPlayer.cs" />
<Compile Include="lua\LuaScript.cs" />
<Compile Include="PacketProcessor.cs" /> <Compile Include="PacketProcessor.cs" />
<Compile Include="packets\BasePacket.cs" /> <Compile Include="packets\BasePacket.cs" />
<Compile Include="packets\receive\ChatMessagePacket.cs" /> <Compile Include="packets\receive\ChatMessagePacket.cs" />

View File

@ -29,8 +29,11 @@
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log" <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}" /> layout="${longdate} ${uppercase:${level}} ${message}" />
--> -->
<target xsi:type="ColoredConsole" name="console" layout="[${longdate}] [${uppercase:${level}}] ${message}" /> <!--<target xsi:type="ColoredConsole" name="console" layout="[${longdate}] [${uppercase:${level}}] ${message}" />-->
<target xsi:type="File" name="file" fileName="${basedir}/logs/${shortdate}/map.log" layout="[${longdate}] [${uppercase:${level}}] ${message}"/> <target xsi:type="File" name="file" fileName="${basedir}/logs/${shortdate}/map.log" layout="[${longdate}] [${uppercase:${level}}] ${message}"/>
<target xsi:type="ColoredConsole" name="console" layout="[${longdate}] [${uppercase:${level}}] ${message}">
<highlight-row condition="equals('${logger}','FFXIVClassic_Map_Server.lua.LuaScript') and equals('${event-context:item=color}','5')" foregroundColor="DarkMagenta" backgroundColor="NoChange" />
</target>
</targets> </targets>
<rules> <rules>

View File

@ -377,6 +377,16 @@ namespace FFXIVClassic_Map_Server.Actors
// todo: handle zone? // todo: handle zone?
zone.BroadcastPacketAroundActor(this, MoveActorToPositionPacket.BuildPacket(this.actorId, this.actorId, x, y, z, rot, moveState)); zone.BroadcastPacketAroundActor(this, MoveActorToPositionPacket.BuildPacket(this.actorId, this.actorId, x, y, z, rot, moveState));
} }
public Area GetZone()
{
return zone;
}
public uint GetZoneID()
{
return zoneId;
}
} }
} }

View File

@ -13,7 +13,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFXIVClassic_Map_Server.packets.send;
namespace FFXIVClassic_Map_Server.Actors namespace FFXIVClassic_Map_Server.Actors
{ {
class Area : Actor class Area : Actor
@ -352,5 +353,25 @@ namespace FFXIVClassic_Map_Server.Actors
AddActorToZone(npc); AddActorToZone(npc);
} }
public void ChangeWeather(ushort weather, ushort transitionTime, Player player, bool zoneWide = false)
{
weatherNormal = weather;
if (player != null && !zoneWide)
{
player.QueuePacket(BasePacket.CreatePacket(SetWeatherPacket.BuildPacket(player.actorId, weather, transitionTime), true, false));
}
if (zoneWide)
{
foreach (var actor in mActorList)
{
if (actor.Value is Player)
{
player = ((Player)actor.Value);
player.QueuePacket(BasePacket.CreatePacket(SetWeatherPacket.BuildPacket(player.actorId, weather, transitionTime), true, false));
}
}
}
}
} }
} }

View File

@ -3,7 +3,7 @@ using FFXIVClassic_Map_Server.actors;
using FFXIVClassic_Map_Server.Actors.Chara; using FFXIVClassic_Map_Server.Actors.Chara;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets; using FFXIVClassic_Map_Server.packets;
using FFXIVClassic_Map_Server.packets.receive.events; using FFXIVClassic_Map_Server.packets.receive.events;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
using FFXIVClassic_Map_Server.utils; using FFXIVClassic_Map_Server.utils;

View File

@ -87,15 +87,21 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
AddItem(itemId, quantity, 1); AddItem(itemId, quantity, 1);
} }
public void AddItem(uint itemId, int quantity, byte quality) public bool AddItem(uint itemId, int quantity, byte quality)
{ {
if (!IsSpaceForAdd(itemId, quantity)) if (!IsSpaceForAdd(itemId, quantity))
return; return false;
Item gItem = Server.GetItemGamedata(itemId); Item gItem = Server.GetItemGamedata(itemId);
List<ushort> slotsToUpdate = new List<ushort>(); List<ushort> slotsToUpdate = new List<ushort>();
List<SubPacket> addItemPackets = new List<SubPacket>(); List<SubPacket> addItemPackets = new List<SubPacket>();
if (gItem == null)
{
Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId);
return false;
}
//Check if item id exists //Check if item id exists
int quantityCount = quantity; int quantityCount = quantity;
for (int i = 0; i < list.Count; i++) for (int i = 0; i < list.Count; i++)
@ -152,6 +158,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId)); owner.QueuePacket(InventorySetEndPacket.BuildPacket(owner.actorId));
owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); owner.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
return true;
} }
public void AddItem(uint[] itemId) public void AddItem(uint[] itemId)

View File

@ -749,6 +749,26 @@ namespace FFXIVClassic_Map_Server.Actors
//zone.BroadcastPacketAroundActor(this, worldMasterMessage); //zone.BroadcastPacketAroundActor(this, worldMasterMessage);
} }
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<uint, ConnectedPlayer> 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 GraphicChange(uint slot, uint graphicId) public void GraphicChange(uint slot, uint graphicId)
{ {
appearanceIds[slot] = graphicId; appearanceIds[slot] = graphicId;

View File

@ -12,6 +12,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Diagnostics; using System.Diagnostics;
using FFXIVClassic_Map_Server.lua;
namespace FFXIVClassic_Map_Server.lua namespace FFXIVClassic_Map_Server.lua
{ {
@ -37,12 +38,12 @@ namespace FFXIVClassic_Map_Server.lua
luaPath = String.Format(FILEPATH_NPCS, target.zoneId, target.GetName()); luaPath = String.Format(FILEPATH_NPCS, target.zoneId, target.GetName());
if (File.Exists(luaPath)) if (File.Exists(luaPath))
{ {
Script script = LoadScript(luaPath); LuaScript script = LoadScript(luaPath);
if (script == null) if (script == null)
return null; return null;
DynValue result = RunScript(script, script.Globals["init"], target); DynValue result = script.Call(script.Globals["init"], target);
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result); List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
return lparams; return lparams;
} }
@ -79,7 +80,7 @@ namespace FFXIVClassic_Map_Server.lua
if (File.Exists(luaPath)) if (File.Exists(luaPath))
{ {
Script script = LoadScript(luaPath); LuaScript script = LoadScript(luaPath);
if (script == null) if (script == null)
return; return;
@ -95,7 +96,7 @@ namespace FFXIVClassic_Map_Server.lua
//Run Script //Run Script
if (!script.Globals.Get("onEventStarted").IsNil()) if (!script.Globals.Get("onEventStarted").IsNil())
RunScript(script, script.Globals["onEventStarted"], objects.ToArray()); script.Call(script.Globals["onEventStarted"], objects.ToArray());
} }
else else
{ {
@ -110,14 +111,14 @@ namespace FFXIVClassic_Map_Server.lua
if (File.Exists(luaPath)) if (File.Exists(luaPath))
{ {
Script script = LoadScript(luaPath); LuaScript script = LoadScript(luaPath);
if (script == null) if (script == null)
return; return;
//Run Script //Run Script
if (!script.Globals.Get("onSpawn").IsNil()) if (!script.Globals.Get("onSpawn").IsNil())
RunScript(script, script.Globals["onSpawn"], player, target); script.Call(script.Globals["onSpawn"], player, target);
} }
else else
{ {
@ -145,7 +146,7 @@ namespace FFXIVClassic_Map_Server.lua
if (File.Exists(luaPath)) if (File.Exists(luaPath))
{ {
Script script = LoadScript(luaPath); LuaScript script = LoadScript(luaPath);
if (script == null) if (script == null)
return; return;
@ -159,7 +160,7 @@ namespace FFXIVClassic_Map_Server.lua
//Run Script //Run Script
if (!script.Globals.Get("onEventUpdate").IsNil()) if (!script.Globals.Get("onEventUpdate").IsNil())
RunScript(script, script.Globals["onEventUpdate"], objects.ToArray()); script.Call(script.Globals["onEventUpdate"], objects.ToArray());
} }
else else
{ {
@ -173,14 +174,14 @@ namespace FFXIVClassic_Map_Server.lua
if (File.Exists(luaPath)) if (File.Exists(luaPath))
{ {
Script script = LoadScript(luaPath); LuaScript script = LoadScript(luaPath);
if (script == null) if (script == null)
return; return;
//Run Script //Run Script
if (!script.Globals.Get("onZoneIn").IsNil()) if (!script.Globals.Get("onZoneIn").IsNil())
RunScript(script, script.Globals["onZoneIn"], player); script.Call(script.Globals["onZoneIn"], player);
} }
} }
@ -188,14 +189,14 @@ namespace FFXIVClassic_Map_Server.lua
{ {
if (File.Exists(FILEPATH_PLAYER)) if (File.Exists(FILEPATH_PLAYER))
{ {
Script script = LoadScript(FILEPATH_PLAYER); LuaScript script = LoadScript(FILEPATH_PLAYER);
if (script == null) if (script == null)
return; return;
//Run Script //Run Script
if (!script.Globals.Get("onBeginLogin").IsNil()) if (!script.Globals.Get("onBeginLogin").IsNil())
RunScript(script, script.Globals["onBeginLogin"], player); script.Call(script.Globals["onBeginLogin"], player);
} }
} }
@ -203,14 +204,14 @@ namespace FFXIVClassic_Map_Server.lua
{ {
if (File.Exists(FILEPATH_PLAYER)) if (File.Exists(FILEPATH_PLAYER))
{ {
Script script = LoadScript(FILEPATH_PLAYER); LuaScript script = LoadScript(FILEPATH_PLAYER);
if (script == null) if (script == null)
return; return;
//Run Script //Run Script
if (!script.Globals.Get("onLogin").IsNil()) if (!script.Globals.Get("onLogin").IsNil())
RunScript(script, script.Globals["onLogin"], player); script.Call(script.Globals["onLogin"], player);
} }
} }
@ -224,7 +225,7 @@ namespace FFXIVClassic_Map_Server.lua
if (File.Exists(path)) if (File.Exists(path))
{ {
// load global functions // load global functions
Script script = LoadGlobals(); LuaScript script = LoadGlobals();
// see if this script has any syntax errors // see if this script has any syntax errors
try try
@ -275,7 +276,7 @@ namespace FFXIVClassic_Map_Server.lua
} }
} }
} }
catch (Exception e) { Program.Log.Error("LuaEngine.RunGMCommand: " + e.Message); return; } catch (Exception e) { LuaScript.Log.Error("LuaEngine.RunGMCommand: " + e.Message); return; }
} }
// if this isnt a console command, make sure player exists // if this isnt a console command, make sure player exists
@ -295,7 +296,7 @@ namespace FFXIVClassic_Map_Server.lua
} }
else if (help) else if (help)
{ {
Program.Log.Info("[Commands] [{0}]: {1}", cmd, description); LuaScript.Log.Info("[Commands] [{0}]: {1}", cmd, description);
return; return;
} }
@ -323,7 +324,7 @@ namespace FFXIVClassic_Map_Server.lua
LuaParam.Add(param[i + 1]); LuaParam.Add(param[i + 1]);
continue; continue;
default: default:
Program.Log.Info("LuaEngine.RunGMCommand: {0} unknown parameter {1}.", path, parameters[i]); LuaScript.Log.Info("LuaEngine.RunGMCommand: {0} unknown parameter {1}.", path, parameters[i]);
LuaParam.Add(param[i + 1]); LuaParam.Add(param[i + 1]);
continue; continue;
} }
@ -341,18 +342,18 @@ namespace FFXIVClassic_Map_Server.lua
LuaParam.Insert(1, i); LuaParam.Insert(1, i);
// run the script // run the script
RunScript(script, script.Globals["onTrigger"], LuaParam.ToArray()); script.Call(script.Globals["onTrigger"], LuaParam.ToArray());
return; return;
} }
} }
Program.Log.Error("LuaEngine.RunGMCommand: Unable to find script {0}", path); LuaScript.Log.Error("LuaEngine.RunGMCommand: Unable to find script {0}", path);
return; return;
} }
#endregion #endregion
public static Script LoadScript(string filename) public static LuaScript LoadScript(string filename)
{ {
Script script = LoadGlobals(); LuaScript script = LoadGlobals();
try try
{ {
@ -366,9 +367,9 @@ namespace FFXIVClassic_Map_Server.lua
return script; return script;
} }
public static Script LoadGlobals(Script script = null) public static LuaScript LoadGlobals(LuaScript script = null)
{ {
script = script ?? new Script(); script = script ?? new LuaScript();
// register and load all global functions here // register and load all global functions here
((FileSystemScriptLoader)script.Options.ScriptLoader).ModulePaths = FileSystemScriptLoader.UnpackStringPaths("./scripts/?;./scripts/?.lua"); ((FileSystemScriptLoader)script.Options.ScriptLoader).ModulePaths = FileSystemScriptLoader.UnpackStringPaths("./scripts/?;./scripts/?.lua");
@ -396,14 +397,14 @@ namespace FFXIVClassic_Map_Server.lua
if (File.Exists(luaPath)) if (File.Exists(luaPath))
{ {
Script script = LoadScript(luaPath); LuaScript script = LoadScript(luaPath);
if (script == null) if (script == null)
return; return;
//Run Script //Run Script
if (!script.Globals.Get("onTalked").IsNil()) if (!script.Globals.Get("onTalked").IsNil())
RunScript(script, script.Globals["onTalked"], player, npc); script.Call(script.Globals["onTalked"], player, npc);
} }
else else
{ {
@ -417,161 +418,19 @@ namespace FFXIVClassic_Map_Server.lua
if (File.Exists(luaPath)) if (File.Exists(luaPath))
{ {
Script script = LoadScript(luaPath); LuaScript script = LoadScript(luaPath);
if (script == null) if (script == null)
return; return;
//Run Script //Run Script
if (!script.Globals.Get("onCommand").IsNil()) if (!script.Globals.Get("onCommand").IsNil())
RunScript(script, script.Globals["onCommand"], player, command); script.Call(script.Globals["onCommand"], player, command);
} }
else else
{ {
SendError(player, String.Format("ERROR: Could not find script for director {0}.", director.GetName())); SendError(player, String.Format("ERROR: Could not find script for director {0}.", director.GetName()));
} }
} }
#region RunScript
//
// Summary:
// Calls the specified function.
//
// Parameters:
// function:
// The Lua/MoonSharp function to be called
//
// Returns:
// The return value(s) of the function call.
//
// Exceptions:
// T:System.ArgumentException:
// Thrown if function is not of DataType.Function
public static DynValue RunScript(Script script, DynValue function)
{
DynValue res = null;
try
{
res = script.Call(function);
}
catch (InterpreterException e)
{
Program.Log.Error(e.DecoratedMessage);
}
return res;
}
//
// Summary:
// Calls the specified function.
//
// Parameters:
// function:
// The Lua/MoonSharp function to be called
//
// Exceptions:
// T:System.ArgumentException:
// Thrown if function is not of DataType.Function
public static DynValue RunScript(Script script, object function)
{
DynValue res = null;
try
{
res = script.Call(function);
}
catch (InterpreterException e)
{
Program.Log.Error(e.DecoratedMessage);
}
return res;
}
//
// Summary:
// Calls the specified function.
//
// Parameters:
// function:
// The Lua/MoonSharp function to be called
//
// args:
// The arguments to pass to the function.
//
// Exceptions:
// T:System.ArgumentException:
// Thrown if function is not of DataType.Function
public static DynValue RunScript(Script script, object function, params object[] args)
{
DynValue res = null;
try
{
res = script.Call(function, args);
}
catch (InterpreterException e)
{
Program.Log.Error(e.DecoratedMessage);
}
return res;
}
//
// Summary:
// Calls the specified function.
//
// Parameters:
// function:
// The Lua/MoonSharp function to be called
//
// args:
// The arguments to pass to the function.
//
// Returns:
// The return value(s) of the function call.
//
// Exceptions:
// T:System.ArgumentException:
// Thrown if function is not of DataType.Function
public static DynValue RunScript(Script script, DynValue function, params DynValue[] args)
{
DynValue res = null;
try
{
res = script.Call(function, args);
}
catch (InterpreterException e)
{
Program.Log.Error(e.DecoratedMessage);
}
return res;
}
//
// Summary:
// Calls the specified function.
//
// Parameters:
// function:
// The Lua/MoonSharp function to be called
//
// args:
// The arguments to pass to the function.
//
// Returns:
// The return value(s) of the function call.
//
// Exceptions:
// T:System.ArgumentException:
// Thrown if function is not of DataType.Function
public static DynValue RunScript(Script script, DynValue function, params object[] args)
{
DynValue res = null;
try
{
res = script.Call(function, args);
}
catch (InterpreterException e)
{
Program.Log.Error(e.DecoratedMessage);
}
return res;
}
#endregion
} }
} }

View File

@ -0,0 +1,240 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MoonSharp;
using MoonSharp.Interpreter;
using NLog;
using MoonSharp.Interpreter.Debugging;
using System.IO;
namespace FFXIVClassic_Map_Server.lua
{
class LuaScript : Script
{
public static Logger Log = LogManager.GetCurrentClassLogger();
public LuaScript()
{
this.Options.DebugPrint = s => { Log.Debug(s); };
}
public new static DynValue RunFile(string filename)
{
try
{
return Script.RunFile(filename);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new void AttachDebugger(IDebugger debugger)
{
try
{
((Script)this).AttachDebugger(debugger);
}
catch (Exception e)
{
Log.Debug(e.Message);
}
}
public new DynValue Call(DynValue function)
{
try
{
return ((Script)this).Call(function);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new DynValue Call(object function)
{
try
{
return ((Script)this).Call(function);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new DynValue Call(object function, params object[] args)
{
try
{
return ((Script)this).Call(function, args);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new DynValue Call(DynValue function, params DynValue[] args)
{
try
{
return ((Script)this).Call(function, args);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new DynValue Call(DynValue function, params object[] args)
{
try
{
return ((Script)this).Call(function, args);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new DynValue CreateCoroutine(DynValue function)
{
try
{
return ((Script)this).CreateCoroutine(function);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new DynValue CreateCoroutine(object function)
{
try
{
return ((Script)this).CreateCoroutine(function);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new DynValue DoString(string code, Table globalContext = null)
{
try
{
return ((Script)this).DoString(code, globalContext);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new DynValue DoFile(string filename, Table globalContext = null)
{
try
{
return ((Script)this).DoFile(filename, globalContext);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new void Dump(DynValue function, Stream stream)
{
try
{
((Script)this).Dump(function, stream);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
}
}
public new DynValue RequireModule(string modname, Table globalContext = null)
{
try
{
return ((Script)this).RequireModule(modname, globalContext);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
return null;
}
}
public new void SetTypeMetatable(DataType type, Table metatable)
{
try
{
((Script)this).SetTypeMetatable(type, metatable);
}
catch (Exception e)
{
if (e is InterpreterException)
Log.Debug(((InterpreterException)e).DecoratedMessage);
else
Log.Debug(e.Message);
}
}
}
}

View File

@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using NLog;
namespace FFXIVClassic_Map_Server.packets namespace FFXIVClassic_Map_Server.packets
{ {
@ -19,7 +20,9 @@ namespace FFXIVClassic_Map_Server.packets
public ulong timestamp; //Miliseconds public ulong timestamp; //Miliseconds
} }
public class BasePacket{ public class BasePacket
{
public static Logger Log = LogManager.GetCurrentClassLogger();
public const int TYPE_ZONE = 1; public const int TYPE_ZONE = 1;
public const int TYPE_CHAT = 2; public const int TYPE_CHAT = 2;
@ -335,7 +338,7 @@ namespace FFXIVClassic_Map_Server.packets
// todo: create new target for colourful packet logging // todo: create new target for colourful packet logging
//Console.BackgroundColor = ConsoleColor.DarkYellow; //Console.BackgroundColor = ConsoleColor.DarkYellow;
Program.Log.Debug("IsAuth: {0} IsEncrypted: {1}, Size: 0x{2:X}, NumSubpackets: {3}{4}{5}", header.isAuthenticated, header.isCompressed, header.packetSize, header.numSubpackets, Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes())); Log.Debug("IsAuth: {0} IsEncrypted: {1}, Size: 0x{2:X}, NumSubpackets: {3}{4}{5}", header.isAuthenticated, header.isCompressed, header.packetSize, header.numSubpackets, Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes()));
foreach (SubPacket sub in GetSubpackets()) foreach (SubPacket sub in GetSubpackets())
{ {

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using FFXIVClassic.Common; using FFXIVClassic.Common;
using NLog;
namespace FFXIVClassic_Map_Server.packets namespace FFXIVClassic_Map_Server.packets
{ {
@ -26,6 +27,7 @@ namespace FFXIVClassic_Map_Server.packets
public class SubPacket public class SubPacket
{ {
public static Logger Log = LogManager.GetCurrentClassLogger();
public const int SUBPACKET_SIZE = 0x10; public const int SUBPACKET_SIZE = 0x10;
public const int GAMEMESSAGE_SIZE = 0x10; public const int GAMEMESSAGE_SIZE = 0x10;
@ -143,15 +145,15 @@ namespace FFXIVClassic_Map_Server.packets
// todo: create new target for colourful packet logging // todo: create new target for colourful packet logging
//Console.BackgroundColor = ConsoleColor.DarkRed; //Console.BackgroundColor = ConsoleColor.DarkRed;
Program.Log.Debug("Size: 0x{0:X}{1}{2}", header.subpacketSize, Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes())); Log.Debug("Size: 0x{0:X}{1}{2}", header.subpacketSize, Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes()));
if (header.type == 0x03) if (header.type == 0x03)
{ {
Program.Log.Debug("Opcode: 0x{0:X}{1}{2}", gameMessage.opcode, Environment.NewLine, Utils.ByteArrayToHex(GetGameMessageBytes(), SUBPACKET_SIZE)); Log.Debug("Opcode: 0x{0:X}{1}{2}", gameMessage.opcode, Environment.NewLine, Utils.ByteArrayToHex(GetGameMessageBytes(), SUBPACKET_SIZE));
//Console.BackgroundColor = ConsoleColor.DarkMagenta; //Console.BackgroundColor = ConsoleColor.DarkMagenta;
Program.Log.Debug("Data: {0}{1}", Environment.NewLine, Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE)); Log.Debug("Data: {0}{1}", Environment.NewLine, Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE));
} }
//Console.BackgroundColor = ConsoleColor.Black; //Console.BackgroundColor = ConsoleColor.Black;

View File

@ -0,0 +1,37 @@
require("global");
properties = {
permissions = 0,
parameters = "sssss",
description = "removes <currency> <qty> from <target>, currency is removed from user if <target> is nil",
}
function onTrigger(player, argc, currency, qty, location, name, lastName)
local sender = "[delcurrency] ";
if name then
if lastName then
player = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil;
else
player = GetWorldManager():GetPCInWorld(name) or nil;
end;
end;
if player then
currency = tonumber(currency) or nil;
qty = 1;
location = INVENTORY_CURRENCY;
local removed = player:GetInventory(location):removecurrency(currency, qty);
local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
local message = "unable to remove currency";
if currency and removed then
message = string.format("removed currency %u from %s", currency, player:GetName());
end
player:SendMessage(messageID, sender, message);
print(message);
else
print(sender.."unable to remove currency, ensure player name is valid.");
end;
end;

View File

@ -0,0 +1,37 @@
require("global");
properties = {
permissions = 0,
parameters = "sssss",
description = "removes <item> <qty> from <location> for <target>. <qty> and <location> are optional, item is removed from user if <target> is nil",
}
function onTrigger(player, argc, item, qty, location, name, lastName)
local sender = "[delitem] ";
if name then
if lastName then
player = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil;
else
player = GetWorldManager():GetPCInWorld(name) or nil;
end;
end;
if player then
item = tonumber(item) or nil;
qty = tonumber(qty) or 1;
location = tonumber(itemtype) or INVENTORY_NORMAL;
local removed = player:GetInventory(location):removeItem(item, qty);
local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
local message = "unable to remove item";
if item and removed then
message = string.format("removed item %u from %s", item, player:GetName());
end
player:SendMessage(messageID, sender, message);
print(message);
else
print(sender.."unable to remove item, ensure player name is valid.");
end;
end;

View File

@ -0,0 +1,37 @@
require("global");
properties = {
permissions = 0,
parameters = "ssss",
description = "removes <keyitem> <qty> from <target>, keyitem is removed from user if <target> is nil",
}
function onTrigger(player, argc, keyitem, qty, name, lastName)
local sender = "[delkeyitem] ";
if name then
if lastName then
player = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil;
else
player = GetWorldManager():GetPCInWorld(name) or nil;
end;
end;
if player then
keyitem = tonumber(keyitem) or nil;
qty = 1;
location = INVENTORY_KEYITEMS;
local removed = player:GetInventory(location):removeItem(item, qty);
local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
local message = "unable to remove keyitem";
if keyitem and removed then
message = string.format("removed keyitem %u from %s", keyitem, player:GetName());
end
player:SendMessage(messageID, sender, message);
print(message);
else
print(sender.."unable to remove keyitem, ensure player name is valid.");
end;
end;

View File

@ -0,0 +1,37 @@
require("global");
properties = {
permissions = 0,
parameters = "sss",
description = "adds <currency> to self or <target>.",
}
function onTrigger(player, argc, currency, name, lastName)
local sender = "[givecurrency] ";
if name then
if lastName then
player = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil;
else
player = GetWorldManager():GetPCInWorld(name) or nil;
end;
end;
if player then
currency = tonumber(currency) or nil;
qty = 1;
location = INVENTORY_CURRENCY;
local added = player:GetInventory(location):AddItem(currency, qty);
local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
local message = "unable to add currency";
if currency and added then
message = string.format("added currency %u to %s", currency, player:GetName());
end
player:SendMessage(messageID, sender, message);
print(message);
else
print(sender.."unable to add currency, ensure player name is valid.");
end;
end;

View File

@ -2,21 +2,35 @@ require("global");
properties = { properties = {
permissions = 0, permissions = 0,
parameters = "ssss", parameters = "sssss",
description = "adds <item> <qty> to <location> for <target>. <qty> and <location> are optional, item is added to user if <target> is nil", description = "adds <item> <qty> to <location> for <target>. <qty> and <location> are optional, item is added to user if <target> is nil",
} }
function onTrigger(player, argc, item, qty, location, target) function onTrigger(player, argc, item, qty, location, name, lastName)
local sender = "[giveitem] "; local sender = "[giveitem] ";
player = GetWorldManager():GetPCInWorld(target) or player;
if name then
if lastName then
player = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil;
else
player = GetWorldManager():GetPCInWorld(name) or nil;
end;
end;
if player then if player then
item = tonumber(item) or nil; item = tonumber(item) or nil;
qty = tonumber(qty) or 1; qty = tonumber(qty) or 1;
location = tonumber(itemtype) or INVENTORY_NORMAL; location = tonumber(itemtype) or INVENTORY_NORMAL;
local added = player:GetInventory(location):AddItem(item, qty);
local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
local message = "unable to add item";
if item then if item and added then
player:GetInventory(location):AddItem(item, qty); message = string.format("added item %u to %s", item, player:GetName());
player:SendMessage(MSG_TYPE_SYSTEM_ERROR, "[giveitem] ", string.format("Added item %u to %s", item, player:GetName());
end end
player:SendMessage(messageID, sender, message);
print(message);
else
print(sender.."unable to add item, ensure player name is valid.");
end; end;
end; end;

View File

@ -0,0 +1,37 @@
require("global");
properties = {
permissions = 0,
parameters = "sss",
description = "adds <keyitem> to self or <target>.",
}
function onTrigger(player, argc, keyitem, name, lastName)
local sender = "[givekeyitem] ";
if name then
if lastName then
player = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil;
else
player = GetWorldManager():GetPCInWorld(name) or nil;
end;
end;
if player then
keyitem = tonumber(keyitem) or nil;
qty = 1;
location = INVENTORY_KEYITEMS;
local added = player:GetInventory(location):AddItem(keyitem, qty);
local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
local message = "unable to add keyitem";
if keyitem and added then
message = string.format("added keyitem %u to %s", keyitem, player:GetName());
end
player:SendMessage(messageID, sender, message);
print(message);
else
print(sender.."unable to add keyitem, ensure player name is valid.");
end;
end;

View File

@ -1,8 +1,7 @@
properties = { properties = {
permissions = 0, permissions = 0,
parameters = "sssss", parameters = "sssss",
description = [[changes appearance for equipment in <slot>. Parameters: <slot> <wId> <eId> <vId> <cId>, description = "changes appearance for equipment in <slot>. Parameters: <slot> <wId> <eId> <vId> <cId>, (idk what any of those mean either)",
idk what any of those mean either]],
} }
function onTrigger(player, argc, slot, wId, eId, vId, cId) function onTrigger(player, argc, slot, wId, eId, vId, cId)

View File

@ -7,17 +7,26 @@ properties = {
} }
function onTrigger(player, argc, zone) function onTrigger(player, argc, zone)
if not zone or tonumber(zone) == 0 then if not player and not zone or tonumber(zone) == 0 then
printf("%s is not a valid zone!", zone); printf("No valid zone specified!");
return; return;
end; end;
local sender = "[reloadzones] ";
zone = tonumber(zone); zone = tonumber(zone);
if player then if player then
local messageID = MSG_TYPE_SYSTEM_ERROR; local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
zone = zone or player:GetZoneID();
player:SendMessage(messageID, "[reloadzones] ", string.format("Reloading zone: %u", zone)); player:SendMessage(messageID, "[reloadzones] ", string.format("Reloading zone: %u", zone));
--[[ todo: get this working legit
player:GetZone():Clear();
player:GetZone():AddActorToZone(player);
player:SendInstanceUpdate();
]]
end; end;
GetWorldManager():ReloadZone(zone); GetWorldManager():ReloadZone(zone);
printf("%s reloaded zone %u", sender, zone);
end; end;

View File

@ -1,9 +0,0 @@
properties = {
permissions = 0,
parameters = "sss",
description = "",
}
function onTrigger(player, argc)
-- todo: change weather
end;

View File

@ -3,20 +3,21 @@ require("global");
properties = { properties = {
permissions = 0, permissions = 0,
parameters = "sssssss", parameters = "sssssss",
description = [[ description =
[[
<zone> | <zone> |
<zone> <x> <y> <z> | <zone> <x> <y> <z> |
<x> <y> <z> <zone> <privateArea> <target name>. <x> <y> <z> <zone> <privateArea> <target name>.
]], ]],
} }
function onTrigger(player, argc, p1, p2, p3, p4, privateArea, firstName, lastName) function onTrigger(player, argc, p1, p2, p3, p4, privateArea, name, lastName)
if firstName then if name then
if lastName then if lastName then
player = GetWorldManager():GetPCInWorld(firstName.." "..lastName) or nil; player = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil;
else else
player = GetWorldManager():GetPCInWorld(firstName) or nil; player = GetWorldManager():GetPCInWorld(name) or nil;
end; end;
end; end;
@ -60,7 +61,7 @@ function onTrigger(player, argc, p1, p2, p3, p4, privateArea, firstName, lastNam
local z = tonumber(applyPositionOffset(p4, player_z)) or player_z; local z = tonumber(applyPositionOffset(p4, player_z)) or player_z;
if privateArea == "" then privateArea = nil end; if privateArea == "" then privateArea = nil end;
player:SendMessage(messageID, sender, string.format("setting coordinates X:%d Y:%d Z:%d to new zone (%d) private area:%s", x, y, z, zone, privateArea or "unspecified")); player:SendMessage(messageID, sender, string.format("setting coordinates X:%d Y:%d Z:%d to new zone (%d) private area:%s", x, y, z, zone, privateArea or "unspecified"));
worldManager:DoZoneChange(player, zone, privateArea, 0x0F, x, y, z, 0.00); worldManager:DoZoneChange(player, zone, privateArea, 0x02, x, y, z, 0.00);
end end
else else

View File

@ -0,0 +1,30 @@
require("global");
properties = {
permissions = 0,
parameters = "ssss",
description = "usage: <id> <updateTime> <zonewide>.",
}
function onTrigger(player, argc, weather, updateTime, zonewide)
-- todo: change weather
local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
local sender = "[weather] ";
local message = "unable to change weather";
if player then
weather = tonumber(weather) or 0;
updateTime = tonumber(updateTime) or 0;
zonewide = tonumber(zonewide) or 0;
message = "changed weather to %u ";
if zonewide ~= 0 then
message = string.format(message.."for zone %u", player:GetZoneID());
else
message = string.format(message.."%s", player:GetName());
end;
-- weatherid, updateTime
player:GetZone():ChangeWeather(weather, updateTime, player, zonewide ~= 0);
player:SendMessage(messageID, sender, message);
end;
print(sender..message);
end;

View File

@ -57,5 +57,9 @@ INVENTORY_EQUIPMENT_OTHERPLAYER = 0x00F9; --Max 0x23
function printf(s, ...) function printf(s, ...)
print(s:format(...)); if ... then
print(s:format(...));
else
print(s);
end;
end; end;