BizHawk/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.cs

203 lines
4.8 KiB
C#

using System;
using System.Linq;
using System.Threading;
using BizHawk.Client.Common;
using LuaInterface;
using System.Reflection;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
using System.IO;
namespace BizHawk.Client.EmuHawk
{
public class EmuLuaLibrary
{
private readonly Dictionary<Type, LuaLibraryBase> Libraries = new Dictionary<Type, LuaLibraryBase>();
private readonly LuaConsole _caller;
private Lua _lua = new Lua();
private Lua _currThread;
public EmuLuaLibrary()
{
Docs = new LuaDocumentation();
}
private FormsLuaLibrary FormsLibrary
{
get { return (FormsLuaLibrary)Libraries[typeof(FormsLuaLibrary)]; }
}
private EventLuaLibrary EventsLibrary
{
get { return (EventLuaLibrary)Libraries[typeof(EventLuaLibrary)]; }
}
private EmulatorLuaLibrary EmulatorLuaLibrary
{
get { return (EmulatorLuaLibrary)Libraries[typeof(EmulatorLuaLibrary)]; }
}
public GuiLuaLibrary GuiLibrary
{
get { return (GuiLuaLibrary)Libraries[typeof(GuiLuaLibrary)]; }
}
public EmuLuaLibrary(LuaConsole passed)
: this()
{
LuaWait = new AutoResetEvent(false);
Docs.Clear();
_caller = passed.Get();
// Register lua libraries
var libs = Assembly
.Load("BizHawk.Client.Common")
.GetTypes()
.Where(t => typeof(LuaLibraryBase).IsAssignableFrom(t))
.Where(t => t.IsSealed)
.Where(t => ServiceInjector.IsAvailable(Global.Emulator.ServiceProvider, t))
.ToList();
libs.AddRange(
Assembly
.GetAssembly(typeof(EmuLuaLibrary))
.GetTypes()
.Where(t => typeof(LuaLibraryBase).IsAssignableFrom(t))
.Where(t => t.IsSealed)
.Where(t => ServiceInjector.IsAvailable(Global.Emulator.ServiceProvider, t))
);
foreach (var lib in libs)
{
bool addLibrary = true;
var attributes = lib.GetCustomAttributes(typeof(LuaLibraryAttributes), false);
if (attributes.Any())
{
addLibrary = VersionInfo.DeveloperBuild || (attributes.First() as LuaLibraryAttributes).Released;
}
if (addLibrary)
{
var instance = (LuaLibraryBase)Activator.CreateInstance(lib, _lua);
instance.LuaRegister(lib, Docs);
instance.LogOutputCallback = ConsoleLuaLibrary.LogOutput;
ServiceInjector.UpdateServices(Global.Emulator.ServiceProvider, instance);
Libraries.Add(lib, instance);
}
}
_lua.RegisterFunction("print", this, GetType().GetMethod("Print"));
EmulatorLuaLibrary.FrameAdvanceCallback = Frameadvance;
EmulatorLuaLibrary.YieldCallback = EmuYield;
}
public LuaDocumentation Docs { get; private set; }
public bool IsRunning { get; set; }
public EventWaitHandle LuaWait { get; private set; }
public bool FrameAdvanceRequested { get; private set; }
public LuaFunctionList RegisteredFunctions
{
get { return EventsLibrary.RegisteredFunctions; }
}
public void WindowClosed(IntPtr handle)
{
FormsLibrary.WindowClosed(handle);
}
public void CallSaveStateEvent(string name)
{
EventsLibrary.CallSaveStateEvent(name);
}
public void CallLoadStateEvent(string name)
{
EventsLibrary.CallLoadStateEvent(name);
}
public void CallFrameBeforeEvent()
{
EventsLibrary.CallFrameBeforeEvent();
}
public void CallFrameAfterEvent()
{
EventsLibrary.CallFrameAfterEvent();
}
public void CallExitEvent(Lua thread)
{
EventsLibrary.CallExitEvent(thread);
}
public void Close()
{
_lua = new Lua();
GuiLibrary.Dispose();
}
public Lua SpawnCoroutine(string file)
{
var lua = _lua.NewThread();
var main = lua.LoadString(File.ReadAllText(file), "main");
lua.Push(main); // push main function on to stack for subsequent resuming
return lua;
}
public void ExecuteString(string command)
{
_currThread = _lua.NewThread();
_currThread.DoString(command);
}
public ResumeResult ResumeScript(Lua script)
{
EventsLibrary.CurrentThread = script;
_currThread = script;
var execResult = script.Resume(0);
_currThread = null;
var result = new ResumeResult();
if (execResult == 0)
{
// terminated
result.Terminated = true;
}
else
{
// yielded
result.WaitForFrame = FrameAdvanceRequested;
}
FrameAdvanceRequested = false;
return result;
}
public static void Print(params object[] outputs)
{
ConsoleLuaLibrary.Log(outputs);
}
private void Frameadvance()
{
FrameAdvanceRequested = true;
_currThread.Yield(0);
}
private void EmuYield()
{
GlobalWin.DisplayManager.NeedsToPaint = true;
_currThread.Yield(0);
}
public class ResumeResult
{
public bool WaitForFrame { get; set; }
public bool Terminated { get; set; }
}
}
}