2013-10-28 19:13:01 +00:00
|
|
|
|
using System;
|
2017-05-07 21:33:35 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
2014-06-01 22:02:59 +00:00
|
|
|
|
using System.Linq;
|
2017-05-07 21:33:35 +00:00
|
|
|
|
using System.Reflection;
|
2013-10-28 19:13:01 +00:00
|
|
|
|
using System.Threading;
|
2013-10-31 16:58:56 +00:00
|
|
|
|
|
2017-07-10 04:51:02 +00:00
|
|
|
|
using NLua;
|
2017-05-07 21:33:35 +00:00
|
|
|
|
|
|
|
|
|
using BizHawk.Common.ReflectionExtensions;
|
2014-12-17 23:03:58 +00:00
|
|
|
|
using BizHawk.Emulation.Common;
|
2017-05-07 21:33:35 +00:00
|
|
|
|
using BizHawk.Client.Common;
|
2013-10-28 19:13:01 +00:00
|
|
|
|
|
2013-11-03 03:54:37 +00:00
|
|
|
|
namespace BizHawk.Client.EmuHawk
|
2013-10-28 19:13:01 +00:00
|
|
|
|
{
|
2013-11-25 00:55:56 +00:00
|
|
|
|
public class EmuLuaLibrary
|
2013-10-28 19:13:01 +00:00
|
|
|
|
{
|
2014-01-21 00:43:57 +00:00
|
|
|
|
public EmuLuaLibrary()
|
|
|
|
|
{
|
|
|
|
|
Docs = new LuaDocumentation();
|
2017-07-23 04:41:12 +00:00
|
|
|
|
//if(NLua.Lua.WhichLua == "NLua")
|
2017-07-15 21:36:18 +00:00
|
|
|
|
_lua["keepalives"] = _lua.NewTable();
|
2014-01-21 00:43:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-22 16:11:08 +00:00
|
|
|
|
public EmuLuaLibrary(IEmulatorServiceProvider serviceProvider)
|
2014-01-25 21:10:51 +00:00
|
|
|
|
: this()
|
2014-01-21 16:31:12 +00:00
|
|
|
|
{
|
|
|
|
|
LuaWait = new AutoResetEvent(false);
|
|
|
|
|
Docs.Clear();
|
2014-05-21 00:17:35 +00:00
|
|
|
|
|
|
|
|
|
// Register lua libraries
|
2014-06-01 22:02:59 +00:00
|
|
|
|
var libs = Assembly
|
|
|
|
|
.Load("BizHawk.Client.Common")
|
|
|
|
|
.GetTypes()
|
|
|
|
|
.Where(t => typeof(LuaLibraryBase).IsAssignableFrom(t))
|
|
|
|
|
.Where(t => t.IsSealed)
|
2016-12-06 16:35:11 +00:00
|
|
|
|
.Where(t => ServiceInjector.IsAvailable(serviceProvider, t))
|
2014-06-01 22:02:59 +00:00
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
libs.AddRange(
|
|
|
|
|
Assembly
|
|
|
|
|
.GetAssembly(typeof(EmuLuaLibrary))
|
|
|
|
|
.GetTypes()
|
|
|
|
|
.Where(t => typeof(LuaLibraryBase).IsAssignableFrom(t))
|
|
|
|
|
.Where(t => t.IsSealed)
|
2017-05-19 14:47:18 +00:00
|
|
|
|
.Where(t => ServiceInjector.IsAvailable(serviceProvider, t)));
|
2014-06-01 22:02:59 +00:00
|
|
|
|
|
|
|
|
|
foreach (var lib in libs)
|
2014-05-21 01:15:52 +00:00
|
|
|
|
{
|
2014-09-20 01:00:50 +00:00
|
|
|
|
bool addLibrary = true;
|
2017-07-10 19:02:00 +00:00
|
|
|
|
var attributes = lib.GetCustomAttributes(typeof(LuaLibraryAttribute), false);
|
2014-09-20 01:00:50 +00:00
|
|
|
|
if (attributes.Any())
|
|
|
|
|
{
|
2017-07-10 19:02:00 +00:00
|
|
|
|
addLibrary = VersionInfo.DeveloperBuild || (attributes.First() as LuaLibraryAttribute).Released;
|
2014-09-20 01:00:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (addLibrary)
|
|
|
|
|
{
|
|
|
|
|
var instance = (LuaLibraryBase)Activator.CreateInstance(lib, _lua);
|
|
|
|
|
instance.LuaRegister(lib, Docs);
|
2014-11-08 14:54:00 +00:00
|
|
|
|
instance.LogOutputCallback = ConsoleLuaLibrary.LogOutput;
|
2016-12-06 16:35:11 +00:00
|
|
|
|
ServiceInjector.UpdateServices(serviceProvider, instance);
|
2014-09-20 01:00:50 +00:00
|
|
|
|
Libraries.Add(lib, instance);
|
|
|
|
|
}
|
2014-06-01 22:02:59 +00:00
|
|
|
|
}
|
2014-05-21 00:17:35 +00:00
|
|
|
|
|
2014-06-01 22:02:59 +00:00
|
|
|
|
_lua.RegisterFunction("print", this, GetType().GetMethod("Print"));
|
2014-05-21 00:17:35 +00:00
|
|
|
|
|
2014-06-01 22:02:59 +00:00
|
|
|
|
EmulatorLuaLibrary.FrameAdvanceCallback = Frameadvance;
|
|
|
|
|
EmulatorLuaLibrary.YieldCallback = EmuYield;
|
2017-05-07 21:33:35 +00:00
|
|
|
|
|
|
|
|
|
// Add LuaCanvas to Docs
|
|
|
|
|
Type luaCanvas = typeof(LuaCanvas);
|
|
|
|
|
|
|
|
|
|
var methods = luaCanvas
|
|
|
|
|
.GetMethods()
|
2017-07-10 19:02:00 +00:00
|
|
|
|
.Where(m => m.GetCustomAttributes(typeof(LuaMethodAttribute), false).Any());
|
2017-05-07 21:33:35 +00:00
|
|
|
|
|
|
|
|
|
foreach (var method in methods)
|
|
|
|
|
{
|
|
|
|
|
Docs.Add(new LibraryFunction(nameof(LuaCanvas), luaCanvas.Description(), method));
|
|
|
|
|
}
|
2014-01-21 16:31:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-23 23:06:27 +00:00
|
|
|
|
public bool IsRebootingCore { get; set; } // pretty hacky.. we dont want a lua script to be able to restart itself by rebooting the core
|
|
|
|
|
|
2017-05-22 21:47:27 +00:00
|
|
|
|
private readonly Dictionary<Type, LuaLibraryBase> Libraries = new Dictionary<Type, LuaLibraryBase>();
|
|
|
|
|
public LuaFileList ScriptList { get; } = new LuaFileList();
|
2017-05-23 23:06:27 +00:00
|
|
|
|
|
|
|
|
|
public IEnumerable<LuaFile> RunningScripts
|
|
|
|
|
{
|
|
|
|
|
get { return ScriptList.Where(lf => lf.Enabled); }
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-22 21:47:27 +00:00
|
|
|
|
private Lua _lua = new Lua();
|
|
|
|
|
private Lua _currThread;
|
|
|
|
|
|
|
|
|
|
private FormsLuaLibrary FormsLibrary => (FormsLuaLibrary)Libraries[typeof(FormsLuaLibrary)];
|
|
|
|
|
|
|
|
|
|
private EventLuaLibrary EventsLibrary => (EventLuaLibrary)Libraries[typeof(EventLuaLibrary)];
|
|
|
|
|
|
|
|
|
|
private EmulatorLuaLibrary EmulatorLuaLibrary => (EmulatorLuaLibrary)Libraries[typeof(EmulatorLuaLibrary)];
|
|
|
|
|
|
|
|
|
|
public GuiLuaLibrary GuiLibrary => (GuiLuaLibrary)Libraries[typeof(GuiLuaLibrary)];
|
|
|
|
|
|
2016-12-06 16:35:11 +00:00
|
|
|
|
public void Restart(IEmulatorServiceProvider newServiceProvider)
|
2016-08-28 16:07:26 +00:00
|
|
|
|
{
|
|
|
|
|
foreach (var lib in Libraries)
|
|
|
|
|
{
|
2016-12-06 16:35:11 +00:00
|
|
|
|
ServiceInjector.UpdateServices(newServiceProvider, lib.Value);
|
2016-08-28 16:07:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-23 17:40:40 +00:00
|
|
|
|
public void StartLuaDrawing()
|
|
|
|
|
{
|
|
|
|
|
if (ScriptList.Any() && GuiLibrary.SurfaceIsNull)
|
|
|
|
|
{
|
|
|
|
|
GuiLibrary.DrawNew("emu");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void EndLuaDrawing()
|
|
|
|
|
{
|
|
|
|
|
if (ScriptList.Any())
|
|
|
|
|
{
|
|
|
|
|
GuiLibrary.DrawFinish();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-19 14:47:18 +00:00
|
|
|
|
public LuaDocumentation Docs { get; }
|
2014-01-21 00:43:57 +00:00
|
|
|
|
public bool IsRunning { get; set; }
|
|
|
|
|
public EventWaitHandle LuaWait { get; private set; }
|
|
|
|
|
public bool FrameAdvanceRequested { get; private set; }
|
2013-10-28 19:13:01 +00:00
|
|
|
|
|
2017-05-19 14:47:18 +00:00
|
|
|
|
public LuaFunctionList RegisteredFunctions => EventsLibrary.RegisteredFunctions;
|
2014-02-14 01:27:38 +00:00
|
|
|
|
|
2013-10-31 16:45:08 +00:00
|
|
|
|
public void WindowClosed(IntPtr handle)
|
|
|
|
|
{
|
2014-06-01 22:02:59 +00:00
|
|
|
|
FormsLibrary.WindowClosed(handle);
|
2013-10-31 16:45:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-31 16:58:56 +00:00
|
|
|
|
public void CallSaveStateEvent(string name)
|
|
|
|
|
{
|
2014-06-01 22:02:59 +00:00
|
|
|
|
EventsLibrary.CallSaveStateEvent(name);
|
2013-10-31 16:58:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void CallLoadStateEvent(string name)
|
|
|
|
|
{
|
2014-06-01 22:02:59 +00:00
|
|
|
|
EventsLibrary.CallLoadStateEvent(name);
|
2013-10-31 16:58:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void CallFrameBeforeEvent()
|
|
|
|
|
{
|
2014-06-01 22:02:59 +00:00
|
|
|
|
EventsLibrary.CallFrameBeforeEvent();
|
2013-10-31 16:58:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void CallFrameAfterEvent()
|
|
|
|
|
{
|
2014-06-01 22:02:59 +00:00
|
|
|
|
EventsLibrary.CallFrameAfterEvent();
|
2013-10-31 16:58:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-26 03:08:16 +00:00
|
|
|
|
public void CallExitEvent(Lua thread)
|
|
|
|
|
{
|
2014-06-01 22:02:59 +00:00
|
|
|
|
EventsLibrary.CallExitEvent(thread);
|
2014-05-26 03:08:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-28 19:13:01 +00:00
|
|
|
|
public void Close()
|
|
|
|
|
{
|
2015-11-06 15:08:44 +00:00
|
|
|
|
FormsLibrary.DestroyAll();
|
2016-10-06 20:17:05 +00:00
|
|
|
|
_lua.Close();
|
2013-10-28 19:13:01 +00:00
|
|
|
|
_lua = new Lua();
|
2014-06-01 22:02:59 +00:00
|
|
|
|
GuiLibrary.Dispose();
|
2013-10-31 18:43:01 +00:00
|
|
|
|
}
|
2013-10-28 19:13:01 +00:00
|
|
|
|
|
2013-11-25 00:55:56 +00:00
|
|
|
|
public Lua SpawnCoroutine(string file)
|
2013-10-28 19:13:01 +00:00
|
|
|
|
{
|
2013-11-26 01:21:24 +00:00
|
|
|
|
var lua = _lua.NewThread();
|
2015-12-20 03:14:00 +00:00
|
|
|
|
var content = File.ReadAllText(file);
|
|
|
|
|
var main = lua.LoadString(content, "main");
|
2014-01-21 00:43:57 +00:00
|
|
|
|
lua.Push(main); // push main function on to stack for subsequent resuming
|
2017-07-23 04:41:12 +00:00
|
|
|
|
//if (NLua.Lua.WhichLua == "NLua")
|
2017-07-15 21:36:18 +00:00
|
|
|
|
{
|
|
|
|
|
_lua.GetTable("keepalives")[lua] = 1;
|
|
|
|
|
//this not being run is the origin of a memory leak if you restart scripts too many times
|
|
|
|
|
_lua.Pop();
|
|
|
|
|
}
|
2013-11-25 00:44:18 +00:00
|
|
|
|
return lua;
|
2013-10-28 19:13:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 23:26:07 +00:00
|
|
|
|
public void ExecuteString(string command)
|
|
|
|
|
{
|
|
|
|
|
_currThread = _lua.NewThread();
|
|
|
|
|
_currThread.DoString(command);
|
2017-07-23 04:41:12 +00:00
|
|
|
|
//if (NLua.Lua.WhichLua == "NLua")
|
2017-07-15 21:36:18 +00:00
|
|
|
|
_lua.Pop();
|
2015-10-15 23:26:07 +00:00
|
|
|
|
}
|
2015-01-02 19:36:32 +00:00
|
|
|
|
|
2013-10-28 19:13:01 +00:00
|
|
|
|
public ResumeResult ResumeScript(Lua script)
|
|
|
|
|
{
|
2013-11-25 00:55:56 +00:00
|
|
|
|
_currThread = script;
|
2015-03-28 05:53:03 +00:00
|
|
|
|
|
2016-02-01 01:54:48 +00:00
|
|
|
|
try
|
2013-10-28 19:13:01 +00:00
|
|
|
|
{
|
2016-02-01 01:54:48 +00:00
|
|
|
|
LuaLibraryBase.SetCurrentThread(_currThread);
|
|
|
|
|
|
|
|
|
|
var execResult = script.Resume(0);
|
|
|
|
|
|
2017-07-10 17:58:52 +00:00
|
|
|
|
_lua.RunScheduledDisposes();
|
2017-05-19 14:47:18 +00:00
|
|
|
|
|
|
|
|
|
// not sure how this is going to work out, so do this too
|
2017-07-10 17:58:52 +00:00
|
|
|
|
script.RunScheduledDisposes();
|
2016-02-01 01:54:48 +00:00
|
|
|
|
|
|
|
|
|
_currThread = null;
|
|
|
|
|
var result = new ResumeResult();
|
|
|
|
|
if (execResult == 0)
|
|
|
|
|
{
|
|
|
|
|
// terminated
|
|
|
|
|
result.Terminated = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// yielded
|
|
|
|
|
result.WaitForFrame = FrameAdvanceRequested;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FrameAdvanceRequested = false;
|
|
|
|
|
return result;
|
2013-10-28 19:13:01 +00:00
|
|
|
|
}
|
2016-02-01 01:54:48 +00:00
|
|
|
|
finally
|
2013-10-28 19:13:01 +00:00
|
|
|
|
{
|
2016-02-01 01:54:48 +00:00
|
|
|
|
LuaLibraryBase.ClearCurrentThread();
|
2013-10-28 19:13:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 05:07:43 +00:00
|
|
|
|
public static void Print(params object[] outputs)
|
2013-10-28 19:13:01 +00:00
|
|
|
|
{
|
2014-04-29 05:07:43 +00:00
|
|
|
|
ConsoleLuaLibrary.Log(outputs);
|
2013-10-28 19:13:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-31 18:09:40 +00:00
|
|
|
|
private void Frameadvance()
|
|
|
|
|
{
|
|
|
|
|
FrameAdvanceRequested = true;
|
2013-11-25 00:55:56 +00:00
|
|
|
|
_currThread.Yield(0);
|
2013-10-31 18:09:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EmuYield()
|
|
|
|
|
{
|
2013-11-25 00:55:56 +00:00
|
|
|
|
_currThread.Yield(0);
|
2013-10-31 18:09:40 +00:00
|
|
|
|
}
|
2014-02-14 01:27:38 +00:00
|
|
|
|
|
|
|
|
|
public class ResumeResult
|
|
|
|
|
{
|
|
|
|
|
public bool WaitForFrame { get; set; }
|
|
|
|
|
public bool Terminated { get; set; }
|
|
|
|
|
}
|
2013-10-28 19:13:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|