2016-08-22 10:43:04 -04:00
|
|
|
|
|
|
|
|
|
using FFXIVClassic_Map_Server.actors.director;
|
|
|
|
|
using FFXIVClassic_Map_Server.Actors;
|
|
|
|
|
using FFXIVClassic_Map_Server.dataobjects;
|
|
|
|
|
using FFXIVClassic_Map_Server.packets.receive.events;
|
|
|
|
|
using FFXIVClassic_Map_Server.packets.send;
|
|
|
|
|
using FFXIVClassic_Map_Server.packets.send.events;
|
|
|
|
|
using MoonSharp.Interpreter;
|
|
|
|
|
using MoonSharp.Interpreter.Interop;
|
|
|
|
|
using MoonSharp.Interpreter.Loaders;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using FFXIVClassic_Map_Server.lua;
|
|
|
|
|
using FFXIVClassic.Common;
|
2017-03-13 14:06:57 -04:00
|
|
|
|
using FFXIVClassic_Map_Server.actors.area;
|
|
|
|
|
using System.Threading;
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
|
|
|
|
namespace FFXIVClassic_Map_Server.lua
|
|
|
|
|
{
|
|
|
|
|
class LuaEngine
|
|
|
|
|
{
|
2017-06-24 15:31:42 -04:00
|
|
|
|
public const string FILEPATH_PLAYER = "./scripts/player.lua";
|
|
|
|
|
public const string FILEPATH_ZONE = "./scripts/unique/{0}/zone.lua";
|
|
|
|
|
public const string FILEPATH_CONTENT = "./scripts/content/{0}.lua";
|
|
|
|
|
public const string FILEPATH_COMMANDS = "./scripts/commands/{0}.lua";
|
|
|
|
|
public const string FILEPATH_DIRECTORS = "./scripts/directors/{0}.lua";
|
|
|
|
|
public const string FILEPATH_NPCS = "./scripts/unique/{0}/{1}/{2}.lua";
|
|
|
|
|
public const string FILEPATH_QUEST = "./scripts/quests/{0}/{1}.lua";
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
private static LuaEngine mThisEngine;
|
|
|
|
|
private Dictionary<Coroutine, ulong> mSleepingOnTime = new Dictionary<Coroutine, ulong>();
|
|
|
|
|
private Dictionary<string, List<Coroutine>> mSleepingOnSignal = new Dictionary<string, List<Coroutine>>();
|
|
|
|
|
private Dictionary<uint, Coroutine> mSleepingOnPlayerEvent = new Dictionary<uint, Coroutine>();
|
|
|
|
|
|
|
|
|
|
private Timer luaTimer;
|
|
|
|
|
|
|
|
|
|
private LuaEngine()
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
|
|
|
|
UserData.RegistrationPolicy = InteropRegistrationPolicy.Automatic;
|
2017-03-13 14:06:57 -04:00
|
|
|
|
|
|
|
|
|
luaTimer = new Timer(new TimerCallback(PulseSleepingOnTime),
|
|
|
|
|
null, TimeSpan.Zero, TimeSpan.FromMilliseconds(50));
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
public static LuaEngine GetInstance()
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (mThisEngine == null)
|
|
|
|
|
mThisEngine = new LuaEngine();
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
return mThisEngine;
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
public void AddWaitCoroutine(Coroutine coroutine, float seconds)
|
|
|
|
|
{
|
|
|
|
|
ulong time = Utils.MilisUnixTimeStampUTC() + (ulong)(seconds * 1000);
|
|
|
|
|
mSleepingOnTime.Add(coroutine, time);
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
public void AddWaitSignalCoroutine(Coroutine coroutine, string signal)
|
|
|
|
|
{
|
|
|
|
|
if (!mSleepingOnSignal.ContainsKey(signal))
|
|
|
|
|
mSleepingOnSignal.Add(signal, new List<Coroutine>());
|
|
|
|
|
mSleepingOnSignal[signal].Add(coroutine);
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
public void AddWaitEventCoroutine(Player player, Coroutine coroutine)
|
|
|
|
|
{
|
|
|
|
|
if (!mSleepingOnPlayerEvent.ContainsKey(player.actorId))
|
|
|
|
|
mSleepingOnPlayerEvent.Add(player.actorId, coroutine);
|
2016-06-16 01:50:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
public void PulseSleepingOnTime(object state)
|
|
|
|
|
{
|
|
|
|
|
ulong currentTime = Utils.MilisUnixTimeStampUTC();
|
|
|
|
|
List<Coroutine> mToAwake = new List<Coroutine>();
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
foreach (KeyValuePair<Coroutine, ulong> entry in mSleepingOnTime)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (entry.Value <= currentTime)
|
|
|
|
|
mToAwake.Add(entry.Key);
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
|
|
|
|
|
foreach (Coroutine key in mToAwake)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
mSleepingOnTime.Remove(key);
|
|
|
|
|
DynValue value = key.Resume();
|
2017-03-14 18:33:33 -04:00
|
|
|
|
ResolveResume(null, key, value);
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
public void OnSignal(string signal)
|
|
|
|
|
{
|
|
|
|
|
List<Coroutine> mToAwake = new List<Coroutine>();
|
|
|
|
|
|
|
|
|
|
if (mSleepingOnSignal.ContainsKey(signal))
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
mToAwake.AddRange(mSleepingOnSignal[signal]);
|
|
|
|
|
mSleepingOnSignal.Remove(signal);
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
foreach (Coroutine key in mToAwake)
|
|
|
|
|
{
|
|
|
|
|
DynValue value = key.Resume();
|
2017-03-14 18:33:33 -04:00
|
|
|
|
ResolveResume(null, key, value);
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-12-10 22:32:24 -05:00
|
|
|
|
public void OnEventUpdate(GameEvent gEvent, List<LuaParam> args)
|
2017-03-13 14:06:57 -04:00
|
|
|
|
{
|
2017-12-10 22:32:24 -05:00
|
|
|
|
if (mSleepingOnPlayerEvent.ContainsKey(gEvent.GetUniqueEventId()))
|
2017-03-13 14:06:57 -04:00
|
|
|
|
{
|
2017-06-25 15:11:35 -04:00
|
|
|
|
try
|
|
|
|
|
{
|
2017-12-10 22:32:24 -05:00
|
|
|
|
Coroutine coroutine = mSleepingOnPlayerEvent[gEvent.GetUniqueEventId()];
|
|
|
|
|
mSleepingOnPlayerEvent.Remove(gEvent.GetUniqueEventId());
|
2017-06-25 15:11:35 -04:00
|
|
|
|
DynValue value = coroutine.Resume(LuaUtils.CreateLuaParamObjectList(args));
|
2017-12-10 22:32:24 -05:00
|
|
|
|
ResolveResume(gEvent.GetPlayerActor(), coroutine, value);
|
2017-06-25 15:11:35 -04:00
|
|
|
|
}
|
|
|
|
|
catch (ScriptRuntimeException e)
|
|
|
|
|
{
|
2017-12-10 22:32:24 -05:00
|
|
|
|
LuaEngine.SendError(gEvent.GetPlayerActor(), String.Format("OnEventUpdated: {0}", e.DecoratedMessage));
|
|
|
|
|
gEvent.GetPlayerActor().EndEvent();
|
2017-06-25 15:11:35 -04:00
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
else
|
2017-12-10 22:32:24 -05:00
|
|
|
|
gEvent.GetPlayerActor().EndEvent();
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string GetScriptPath(Actor target)
|
|
|
|
|
{
|
|
|
|
|
if (target is Player)
|
|
|
|
|
{
|
|
|
|
|
return String.Format(FILEPATH_PLAYER);
|
|
|
|
|
}
|
|
|
|
|
else if (target is Npc)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
else if (target is Command)
|
|
|
|
|
{
|
|
|
|
|
return String.Format(FILEPATH_COMMANDS, target.GetName());
|
|
|
|
|
}
|
|
|
|
|
else if (target is Director)
|
|
|
|
|
{
|
|
|
|
|
return String.Format(FILEPATH_DIRECTORS, ((Director)target).GetScriptPath());
|
|
|
|
|
}
|
2017-04-29 20:30:54 -04:00
|
|
|
|
else if (target is PrivateAreaContent)
|
|
|
|
|
{
|
|
|
|
|
return String.Format(FILEPATH_CONTENT, ((PrivateAreaContent)target).GetPrivateAreaName());
|
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
else if (target is Area)
|
|
|
|
|
{
|
2017-03-19 11:39:21 -04:00
|
|
|
|
return String.Format(FILEPATH_ZONE, ((Area)target).zoneName);
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
2017-04-04 01:10:26 -04:00
|
|
|
|
else if (target is Quest)
|
|
|
|
|
{
|
|
|
|
|
string initial = ((Quest)target).actorName.Substring(0, 3);
|
|
|
|
|
string questName = ((Quest)target).actorName;
|
|
|
|
|
return String.Format(FILEPATH_QUEST, initial, questName);
|
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
else
|
|
|
|
|
return "";
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-29 20:30:54 -04:00
|
|
|
|
private List<LuaParam> CallLuaFunctionNpcForReturn(Player player, Npc target, string funcName, bool optional, params object[] args)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-04-02 12:51:23 -04:00
|
|
|
|
object[] args2 = new object[args.Length + (player == null ? 1 : 2)];
|
|
|
|
|
Array.Copy(args, 0, args2, (player == null ? 1 : 2), args.Length);
|
|
|
|
|
if (player != null)
|
|
|
|
|
{
|
|
|
|
|
args2[0] = player;
|
|
|
|
|
args2[1] = target;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
args2[0] = target;
|
2017-03-20 21:51:43 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
LuaScript parent = null, child = null;
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (File.Exists("./scripts/base/" + target.classPath + ".lua"))
|
|
|
|
|
parent = LuaEngine.LoadScript("./scripts/base/" + target.classPath + ".lua");
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
Area area = target.zone;
|
|
|
|
|
if (area is PrivateArea)
|
|
|
|
|
{
|
2017-04-02 12:51:23 -04:00
|
|
|
|
if (File.Exists(String.Format("./scripts/unique/{0}/privatearea/{1}_{2}/{3}/{4}.lua", area.zoneName, ((PrivateArea)area).GetPrivateAreaName(), ((PrivateArea)area).GetPrivateAreaType(), target.className, target.GetUniqueId())))
|
|
|
|
|
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/privatearea/{1}_{2}/{3}/{4}.lua", area.zoneName, ((PrivateArea)area).GetPrivateAreaName(), ((PrivateArea)area).GetPrivateAreaType(), target.className, target.GetUniqueId()));
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", area.zoneName, target.className, target.GetUniqueId())))
|
|
|
|
|
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", area.zoneName, target.className, target.GetUniqueId()));
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (parent == null && child == null)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.GetName()));
|
2016-06-16 01:50:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
//Run Script
|
|
|
|
|
DynValue result;
|
2016-06-16 01:50:13 +01:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (child != null && child.Globals[funcName] != null)
|
2017-03-20 21:51:43 -04:00
|
|
|
|
result = child.Call(child.Globals[funcName], args2);
|
2017-03-13 14:06:57 -04:00
|
|
|
|
else if (parent != null && parent.Globals[funcName] != null)
|
2017-03-20 21:51:43 -04:00
|
|
|
|
result = parent.Call(parent.Globals[funcName], args2);
|
2016-08-22 10:43:04 -04:00
|
|
|
|
else
|
2017-03-13 14:06:57 -04:00
|
|
|
|
return null;
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
|
|
|
|
|
return lparams;
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-04-29 20:30:54 -04:00
|
|
|
|
private void CallLuaFunctionNpc(Player player, Npc target, string funcName, bool optional, params object[] args)
|
2017-03-13 14:06:57 -04:00
|
|
|
|
{
|
2017-04-02 12:51:23 -04:00
|
|
|
|
object[] args2 = new object[args.Length + (player == null ? 1:2)];
|
|
|
|
|
Array.Copy(args, 0, args2, (player == null ? 1 : 2), args.Length);
|
|
|
|
|
if (player != null)
|
|
|
|
|
{
|
|
|
|
|
args2[0] = player;
|
|
|
|
|
args2[1] = target;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
args2[0] = target;
|
2017-03-14 23:13:54 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
LuaScript parent = null, child = null;
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (File.Exists("./scripts/base/" + target.classPath + ".lua"))
|
|
|
|
|
parent = LuaEngine.LoadScript("./scripts/base/" + target.classPath + ".lua");
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
Area area = target.zone;
|
|
|
|
|
if (area is PrivateArea)
|
|
|
|
|
{
|
2017-04-02 12:51:23 -04:00
|
|
|
|
if (File.Exists(String.Format("./scripts/unique/{0}/privatearea/{1}_{2}/{3}/{4}.lua", area.zoneName, ((PrivateArea)area).GetPrivateAreaName(), ((PrivateArea)area).GetPrivateAreaType(), target.className, target.GetUniqueId())))
|
|
|
|
|
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/privatearea/{1}_{2}/{3}/{4}.lua", area.zoneName, ((PrivateArea)area).GetPrivateAreaName(), ((PrivateArea)area).GetPrivateAreaType(), target.className, target.GetUniqueId()));
|
2016-06-16 01:50:13 +01:00
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
else
|
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", area.zoneName, target.className, target.GetUniqueId())))
|
|
|
|
|
child = LuaEngine.LoadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", area.zoneName, target.className, target.GetUniqueId()));
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
2016-06-16 01:50:13 +01:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (parent == null && child == null)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-04-02 12:51:23 -04:00
|
|
|
|
LuaEngine.SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
|
2017-03-14 18:33:33 -04:00
|
|
|
|
return;
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
//Run Script
|
|
|
|
|
Coroutine coroutine = null;
|
|
|
|
|
|
|
|
|
|
if (child != null && !child.Globals.Get(funcName).IsNil())
|
|
|
|
|
coroutine = child.CreateCoroutine(child.Globals[funcName]).Coroutine;
|
2017-03-20 21:51:43 -04:00
|
|
|
|
else if (parent != null && parent.Globals.Get(funcName) != null && !parent.Globals.Get(funcName).IsNil())
|
2017-03-13 14:06:57 -04:00
|
|
|
|
coroutine = parent.CreateCoroutine(parent.Globals[funcName]).Coroutine;
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (coroutine != null)
|
|
|
|
|
{
|
2017-04-02 12:51:23 -04:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
DynValue value = coroutine.Resume(args2);
|
|
|
|
|
ResolveResume(player, coroutine, value);
|
|
|
|
|
}
|
|
|
|
|
catch (ScriptRuntimeException e)
|
|
|
|
|
{
|
|
|
|
|
SendError(player, e.DecoratedMessage);
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-29 20:30:54 -04:00
|
|
|
|
public List<LuaParam> CallLuaFunctionForReturn(Player player, Actor target, string funcName, bool optional, params object[] args)
|
2017-03-07 00:09:37 -05:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
//Need a seperate case for NPCs cause that child/parent thing.
|
|
|
|
|
if (target is Npc)
|
2017-04-29 20:30:54 -04:00
|
|
|
|
return CallLuaFunctionNpcForReturn(player, (Npc)target, funcName, optional, args);
|
2017-03-07 00:09:37 -05:00
|
|
|
|
|
2017-04-04 01:10:26 -04:00
|
|
|
|
object[] args2 = new object[args.Length + (player == null ? 1 : 2)];
|
|
|
|
|
Array.Copy(args, 0, args2, (player == null ? 1 : 2), args.Length);
|
|
|
|
|
if (player != null)
|
|
|
|
|
{
|
|
|
|
|
args2[0] = player;
|
|
|
|
|
args2[1] = target;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
args2[0] = target;
|
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
string luaPath = GetScriptPath(target);
|
|
|
|
|
LuaScript script = LoadScript(luaPath);
|
|
|
|
|
if (script != null)
|
2017-03-07 00:09:37 -05:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (!script.Globals.Get(funcName).IsNil())
|
|
|
|
|
{
|
|
|
|
|
//Run Script
|
2017-04-04 01:10:26 -04:00
|
|
|
|
DynValue result = script.Call(script.Globals[funcName], args2);
|
2017-03-13 14:06:57 -04:00
|
|
|
|
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
|
|
|
|
|
return lparams;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-04-29 20:30:54 -04:00
|
|
|
|
if (!optional)
|
|
|
|
|
SendError(player, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
2017-03-07 00:09:37 -05:00
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
else
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-04-29 20:30:54 -04:00
|
|
|
|
if (!optional)
|
|
|
|
|
SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<LuaParam> CallLuaFunctionForReturn(string path, string funcName, bool optional, params object[] args)
|
|
|
|
|
{
|
|
|
|
|
string luaPath = path;
|
|
|
|
|
LuaScript script = LoadScript(luaPath);
|
|
|
|
|
if (script != null)
|
|
|
|
|
{
|
|
|
|
|
if (!script.Globals.Get(funcName).IsNil())
|
|
|
|
|
{
|
|
|
|
|
//Run Script
|
|
|
|
|
DynValue result = script.Call(script.Globals[funcName], args);
|
|
|
|
|
List<LuaParam> lparams = LuaUtils.CreateLuaParamList(result);
|
|
|
|
|
return lparams;
|
|
|
|
|
}
|
2016-06-16 01:50:13 +01:00
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
return null;
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-29 20:30:54 -04:00
|
|
|
|
public void CallLuaFunction(Player player, Actor target, string funcName, bool optional, params object[] args)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
//Need a seperate case for NPCs cause that child/parent thing.
|
|
|
|
|
if (target is Npc)
|
2017-03-14 18:33:33 -04:00
|
|
|
|
{
|
2017-04-29 20:30:54 -04:00
|
|
|
|
CallLuaFunctionNpc(player, (Npc)target, funcName, optional, args);
|
2017-03-14 18:33:33 -04:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
|
2017-03-14 23:13:54 -04:00
|
|
|
|
object[] args2 = new object[args.Length + 2];
|
|
|
|
|
Array.Copy(args, 0, args2, 2, args.Length);
|
|
|
|
|
args2[0] = player;
|
|
|
|
|
args2[1] = target;
|
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
string luaPath = GetScriptPath(target);
|
|
|
|
|
LuaScript script = LoadScript(luaPath);
|
|
|
|
|
if (script != null)
|
|
|
|
|
{
|
|
|
|
|
if (!script.Globals.Get(funcName).IsNil())
|
|
|
|
|
{
|
|
|
|
|
Coroutine coroutine = script.CreateCoroutine(script.Globals[funcName]).Coroutine;
|
2017-03-14 23:13:54 -04:00
|
|
|
|
DynValue value = coroutine.Resume(args2);
|
2017-03-14 18:33:33 -04:00
|
|
|
|
ResolveResume(player, coroutine, value);
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-04-29 20:30:54 -04:00
|
|
|
|
if (!optional)
|
|
|
|
|
SendError(player, String.Format("Could not find function '{0}' for actor {1}.", funcName, target.GetName()));
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
else
|
|
|
|
|
{
|
2017-04-29 20:30:54 -04:00
|
|
|
|
if (!(target is Area) && !optional)
|
2017-04-02 12:51:23 -04:00
|
|
|
|
SendError(player, String.Format("Could not find script for actor {0}.", target.GetName()));
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-10 22:32:24 -05:00
|
|
|
|
public void EventStarted(GameEvent gEvent, EventStartPacket eventStart)
|
2017-01-16 19:14:13 -05:00
|
|
|
|
{
|
2017-03-14 23:13:54 -04:00
|
|
|
|
List<LuaParam> lparams = eventStart.luaParams;
|
|
|
|
|
lparams.Insert(0, new LuaParam(2, eventStart.triggerName));
|
2017-12-10 22:32:24 -05:00
|
|
|
|
|
|
|
|
|
if (mSleepingOnPlayerEvent.ContainsKey(gEvent.GetUniqueEventId()))
|
2017-03-14 18:33:33 -04:00
|
|
|
|
{
|
2017-12-10 22:32:24 -05:00
|
|
|
|
Coroutine coroutine = mSleepingOnPlayerEvent[gEvent.GetUniqueEventId()];
|
|
|
|
|
mSleepingOnPlayerEvent.Remove(gEvent.GetUniqueEventId());
|
2017-06-25 15:11:35 -04:00
|
|
|
|
|
|
|
|
|
try{
|
|
|
|
|
DynValue value = coroutine.Resume();
|
|
|
|
|
ResolveResume(null, coroutine, value);
|
|
|
|
|
}
|
|
|
|
|
catch (ScriptRuntimeException e)
|
|
|
|
|
{
|
2017-12-10 22:32:24 -05:00
|
|
|
|
LuaEngine.SendError(gEvent.GetPlayerActor(), String.Format("OnEventStarted: {0}", e.DecoratedMessage));
|
|
|
|
|
gEvent.GetPlayerActor().EndEvent();
|
2017-06-25 15:11:35 -04:00
|
|
|
|
}
|
2017-03-14 18:33:33 -04:00
|
|
|
|
}
|
2017-07-09 18:38:01 -04:00
|
|
|
|
else
|
|
|
|
|
{
|
2017-12-10 22:32:24 -05:00
|
|
|
|
if (gEvent.GetOwnerActor() is Director)
|
|
|
|
|
((Director)gEvent.GetOwnerActor()).OnEventStart(gEvent.GetPlayerActor(), LuaUtils.CreateLuaParamObjectList(lparams));
|
2017-07-09 18:38:01 -04:00
|
|
|
|
else
|
2017-12-10 22:32:24 -05:00
|
|
|
|
CallLuaFunction(gEvent.GetPlayerActor(), gEvent.GetOwnerActor(), "onEventStarted", false, LuaUtils.CreateLuaParamObjectList(lparams));
|
2017-07-09 18:38:01 -04:00
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
}
|
2017-01-16 19:14:13 -05:00
|
|
|
|
|
2017-06-24 16:58:02 -04:00
|
|
|
|
public DynValue ResolveResume(Player player, Coroutine coroutine, DynValue value)
|
2017-03-13 14:06:57 -04:00
|
|
|
|
{
|
|
|
|
|
if (value == null || value.IsVoid())
|
|
|
|
|
return value;
|
2017-01-16 19:14:13 -05:00
|
|
|
|
|
2017-06-24 16:58:02 -04:00
|
|
|
|
if (player != null && value.String != null && value.String.Equals("_WAIT_EVENT"))
|
2017-03-14 18:33:33 -04:00
|
|
|
|
{
|
|
|
|
|
GetInstance().AddWaitEventCoroutine(player, coroutine);
|
|
|
|
|
}
|
|
|
|
|
else if (value.Tuple != null && value.Tuple.Length >= 1 && value.Tuple[0].String != null)
|
2017-03-13 14:06:57 -04:00
|
|
|
|
{
|
|
|
|
|
switch (value.Tuple[0].String)
|
|
|
|
|
{
|
|
|
|
|
case "_WAIT_TIME":
|
|
|
|
|
GetInstance().AddWaitCoroutine(coroutine, (float)value.Tuple[1].Number);
|
|
|
|
|
break;
|
|
|
|
|
case "_WAIT_SIGNAL":
|
|
|
|
|
GetInstance().AddWaitSignalCoroutine(coroutine, (string)value.Tuple[1].String);
|
|
|
|
|
break;
|
|
|
|
|
case "_WAIT_EVENT":
|
2017-03-14 18:33:33 -04:00
|
|
|
|
GetInstance().AddWaitEventCoroutine((Player)value.Tuple[1].UserData.Object, coroutine);
|
2017-03-13 14:06:57 -04:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return value;
|
|
|
|
|
}
|
2017-01-16 19:14:13 -05:00
|
|
|
|
}
|
2017-03-13 14:06:57 -04:00
|
|
|
|
|
|
|
|
|
return value;
|
2017-01-16 19:14:13 -05:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-16 01:50:13 +01:00
|
|
|
|
#region RunGMCommand
|
|
|
|
|
public static void RunGMCommand(Player player, String cmd, string[] param, bool help = false)
|
|
|
|
|
{
|
2017-05-16 23:43:07 -04:00
|
|
|
|
bool playerNull = player == null;
|
2017-08-26 10:23:13 -04:00
|
|
|
|
if (playerNull && param.Length >= 3)
|
2017-05-16 23:43:07 -04:00
|
|
|
|
player = Server.GetWorldManager().GetPCInWorld(param[1] + " " + param[2]);
|
|
|
|
|
|
2016-06-16 01:50:13 +01:00
|
|
|
|
// load from scripts/commands/gm/ directory
|
2016-12-04 21:41:34 +00:00
|
|
|
|
var path = String.Format("./scripts/commands/gm/{0}.lua", cmd.ToLower());
|
2016-06-16 01:50:13 +01:00
|
|
|
|
|
|
|
|
|
// check if the file exists
|
|
|
|
|
if (File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
// load global functions
|
2016-06-17 05:05:31 +01:00
|
|
|
|
LuaScript script = LoadGlobals();
|
2016-06-16 01:50:13 +01:00
|
|
|
|
|
|
|
|
|
// see if this script has any syntax errors
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
script.DoFile(path);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Program.Log.Error("LuaEngine.RunGMCommand: {0}.", e.Message);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// can we run this script
|
|
|
|
|
if (!script.Globals.Get("onTrigger").IsNil())
|
|
|
|
|
{
|
|
|
|
|
// can i run this command
|
|
|
|
|
var permissions = 0;
|
|
|
|
|
|
|
|
|
|
// parameter types (string, integer, double, float)
|
|
|
|
|
var parameters = "";
|
|
|
|
|
var description = "!" + cmd + ": ";
|
|
|
|
|
|
|
|
|
|
// get the properties table
|
|
|
|
|
var res = script.Globals.Get("properties");
|
|
|
|
|
|
|
|
|
|
// make sure properties table exists
|
|
|
|
|
if (!res.IsNil())
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// returns table if one is found
|
|
|
|
|
var table = res.Table;
|
|
|
|
|
|
|
|
|
|
// find each key/value pair
|
|
|
|
|
foreach (var pair in table.Pairs)
|
|
|
|
|
{
|
|
|
|
|
if (pair.Key.String == "permissions")
|
|
|
|
|
{
|
|
|
|
|
permissions = (int)pair.Value.Number;
|
|
|
|
|
}
|
|
|
|
|
else if (pair.Key.String == "parameters")
|
|
|
|
|
{
|
|
|
|
|
parameters = pair.Value.String;
|
|
|
|
|
}
|
|
|
|
|
else if (pair.Key.String == "description")
|
|
|
|
|
{
|
|
|
|
|
description = pair.Value.String;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-17 05:05:31 +01:00
|
|
|
|
catch (Exception e) { LuaScript.Log.Error("LuaEngine.RunGMCommand: " + e.Message); return; }
|
2016-06-16 01:50:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if this isnt a console command, make sure player exists
|
|
|
|
|
if (player != null)
|
|
|
|
|
{
|
|
|
|
|
if (permissions > 0 && !player.isGM)
|
|
|
|
|
{
|
|
|
|
|
Program.Log.Info("LuaEngine.RunGMCommand: {0}'s GM level is too low to use command {1}.", player.actorName, cmd);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// i hate to do this, but cant think of a better way to keep !help
|
|
|
|
|
else if (help)
|
|
|
|
|
{
|
|
|
|
|
player.SendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, String.Format("[Commands] [{0}]", cmd), description);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (help)
|
|
|
|
|
{
|
2016-06-17 05:05:31 +01:00
|
|
|
|
LuaScript.Log.Info("[Commands] [{0}]: {1}", cmd, description);
|
2016-06-16 01:50:13 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we'll push our lua params here
|
|
|
|
|
List<object> LuaParam = new List<object>();
|
|
|
|
|
|
2017-05-16 23:43:07 -04:00
|
|
|
|
var i = playerNull ? 2 : 0;
|
2016-06-16 01:50:13 +01:00
|
|
|
|
for (; i < parameters.Length; ++i)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// convert chat parameters to command parameters
|
|
|
|
|
switch (parameters[i])
|
|
|
|
|
{
|
|
|
|
|
case 'i':
|
|
|
|
|
LuaParam.Add(Convert.ChangeType(param[i + 1], typeof(int)));
|
|
|
|
|
continue;
|
|
|
|
|
case 'd':
|
|
|
|
|
LuaParam.Add(Convert.ChangeType(param[i + 1], typeof(double)));
|
|
|
|
|
continue;
|
|
|
|
|
case 'f':
|
|
|
|
|
LuaParam.Add(Convert.ChangeType(param[i + 1], typeof(float)));
|
|
|
|
|
continue;
|
|
|
|
|
case 's':
|
|
|
|
|
LuaParam.Add(param[i + 1]);
|
|
|
|
|
continue;
|
|
|
|
|
default:
|
2016-06-17 05:05:31 +01:00
|
|
|
|
LuaScript.Log.Info("LuaEngine.RunGMCommand: {0} unknown parameter {1}.", path, parameters[i]);
|
2016-06-16 01:50:13 +01:00
|
|
|
|
LuaParam.Add(param[i + 1]);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
if (e is IndexOutOfRangeException) break;
|
|
|
|
|
LuaParam.Add(param[i + 1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// the script can double check the player exists, we'll push them anyways
|
|
|
|
|
LuaParam.Insert(0, player);
|
|
|
|
|
// push the arg count too
|
2017-05-16 23:43:07 -04:00
|
|
|
|
LuaParam.Insert(1, i - (playerNull ? 2 : 0));
|
2016-06-16 01:50:13 +01:00
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
// run the script
|
|
|
|
|
//script.Call(script.Globals["onTrigger"], LuaParam.ToArray());
|
|
|
|
|
|
|
|
|
|
Coroutine coroutine = script.CreateCoroutine(script.Globals["onTrigger"]).Coroutine;
|
2017-03-19 11:39:21 -04:00
|
|
|
|
DynValue value = coroutine.Resume(LuaParam.ToArray());
|
2017-03-14 18:33:33 -04:00
|
|
|
|
GetInstance().ResolveResume(player, coroutine, value);
|
2016-06-16 01:50:13 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-17 05:05:31 +01:00
|
|
|
|
LuaScript.Log.Error("LuaEngine.RunGMCommand: Unable to find script {0}", path);
|
2016-06-16 01:50:13 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-08-22 10:43:04 -04:00
|
|
|
|
#endregion
|
|
|
|
|
|
2017-03-13 14:06:57 -04:00
|
|
|
|
public static LuaScript LoadScript(string path)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (!File.Exists(path))
|
|
|
|
|
return null;
|
|
|
|
|
|
2016-08-22 10:43:04 -04:00
|
|
|
|
LuaScript script = LoadGlobals();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2017-03-13 14:06:57 -04:00
|
|
|
|
script.DoFile(path);
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
catch (SyntaxErrorException e)
|
|
|
|
|
{
|
2017-04-02 12:51:23 -04:00
|
|
|
|
Program.Log.Error("{0}.", e.DecoratedMessage);
|
2016-08-22 10:43:04 -04:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return script;
|
2016-06-16 01:50:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-17 05:05:31 +01:00
|
|
|
|
public static LuaScript LoadGlobals(LuaScript script = null)
|
2016-06-16 01:50:13 +01:00
|
|
|
|
{
|
2016-06-17 05:05:31 +01:00
|
|
|
|
script = script ?? new LuaScript();
|
2016-06-16 01:50:13 +01:00
|
|
|
|
|
|
|
|
|
// register and load all global functions here
|
|
|
|
|
((FileSystemScriptLoader)script.Options.ScriptLoader).ModulePaths = FileSystemScriptLoader.UnpackStringPaths("./scripts/?;./scripts/?.lua");
|
|
|
|
|
script.Globals["GetWorldManager"] = (Func<WorldManager>)Server.GetWorldManager;
|
|
|
|
|
script.Globals["GetStaticActor"] = (Func<string, Actor>)Server.GetStaticActors;
|
2017-01-08 21:42:43 -05:00
|
|
|
|
script.Globals["GetStaticActorById"] = (Func<uint, Actor>)Server.GetStaticActors;
|
2016-06-16 01:50:13 +01:00
|
|
|
|
script.Globals["GetWorldMaster"] = (Func<Actor>)Server.GetWorldManager().GetActor;
|
2017-06-24 14:12:52 -04:00
|
|
|
|
script.Globals["GetItemGamedata"] = (Func<uint, ItemData>)Server.GetItemGamedata;
|
2017-06-24 15:31:42 -04:00
|
|
|
|
script.Globals["GetGuildleveGamedata"] = (Func<uint, GuildleveData>)Server.GetGuildleveGamedata;
|
2017-03-13 14:06:57 -04:00
|
|
|
|
script.Globals["GetLuaInstance"] = (Func<LuaEngine>)LuaEngine.GetInstance;
|
2016-06-16 01:50:13 +01:00
|
|
|
|
|
|
|
|
|
script.Options.DebugPrint = s => { Program.Log.Debug(s); };
|
|
|
|
|
return script;
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-24 15:31:42 -04:00
|
|
|
|
public static void SendError(Player player, string message)
|
2016-08-22 10:43:04 -04:00
|
|
|
|
{
|
2017-04-02 12:51:23 -04:00
|
|
|
|
message = "[LuaError] " + message;
|
2017-03-13 14:06:57 -04:00
|
|
|
|
if (player == null)
|
|
|
|
|
return;
|
2016-08-22 10:43:04 -04:00
|
|
|
|
List<SubPacket> SendError = new List<SubPacket>();
|
|
|
|
|
player.SendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", message);
|
2017-12-10 22:32:24 -05:00
|
|
|
|
player.EndEvent();
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
2017-03-07 00:09:37 -05:00
|
|
|
|
|
2016-08-22 10:43:04 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-04-02 12:51:23 -04:00
|
|
|
|
|