a better way to set up lua libraries, including a proof of concept for callbacks (in this case passing in a method for logging to an output window, but there can be other applications as well)

This commit is contained in:
adelikat 2013-10-31 00:31:25 +00:00
parent 0db498ae58
commit 6e3d55372f
10 changed files with 221 additions and 168 deletions

View File

@ -460,6 +460,7 @@
<Compile Include="tools\Lua\Libraries\EmuLuaLibrary.NES.cs" />
<Compile Include="tools\Lua\Libraries\EmuLuaLibrary.Savestate.cs" />
<Compile Include="tools\Lua\Libraries\EmuLuaLibrary.SNES.cs" />
<Compile Include="tools\Lua\Libraries\LuaLibraryBase.cs" />
<Compile Include="tools\Lua\LuaButton.cs">
<SubType>Component</SubType>
</Compile>

View File

@ -2,61 +2,67 @@
namespace BizHawk.MultiClient
{
public static class BitLuaLibrary
public class BitLuaLibrary : LuaLibraryBase
{
public static string Name = "bit";
public static string[] Functions = new[]
public override string Name { get { return "bit"; } }
public override string[] Functions
{
"band",
"bnot",
"bor",
"bxor",
"lshift",
"rol",
"ror",
"rshift",
};
get
{
return new[]
{
"band",
"bnot",
"bor",
"bxor",
"lshift",
"rol",
"ror",
"rshift",
};
}
}
public static uint bit_band(object val, object amt)
{
return (uint)(LuaCommon.LuaInt(val) & LuaCommon.LuaInt(amt));
return (uint)(LuaInt(val) & LuaInt(amt));
}
public static uint bit_bnot(object val)
{
return (uint)(~LuaCommon.LuaInt(val));
return (uint)(~LuaInt(val));
}
public static uint bit_bor(object val, object amt)
{
return (uint)(LuaCommon.LuaInt(val) | LuaCommon.LuaInt(amt));
return (uint)(LuaInt(val) | LuaInt(amt));
}
public static uint bit_bxor(object val, object amt)
{
return (uint)(LuaCommon.LuaInt(val) ^ LuaCommon.LuaInt(amt));
return (uint)(LuaInt(val) ^ LuaInt(amt));
}
public static uint bit_lshift(object val, object amt)
{
return (uint)(LuaCommon.LuaInt(val) << LuaCommon.LuaInt(amt));
return (uint)(LuaInt(val) << LuaInt(amt));
}
public static uint bit_rol(object val, object amt)
{
return (uint)((LuaCommon.LuaInt(val) << LuaCommon.LuaInt(amt))
| (LuaCommon.LuaInt(val) >> (32 - LuaCommon.LuaInt(amt))));
return (uint)((LuaInt(val) << LuaInt(amt))
| (LuaInt(val) >> (32 - LuaInt(amt))));
}
public static uint bit_ror(object val, object amt)
{
return (uint)((LuaCommon.LuaInt(val) >> LuaCommon.LuaInt(amt))
| (LuaCommon.LuaInt(val) << (32 - LuaCommon.LuaInt(amt))));
return (uint)((LuaInt(val) >> LuaInt(amt))
| (LuaInt(val) << (32 - LuaInt(amt))));
}
public static uint bit_rshift(object val, object amt)
{
return (uint)(LuaCommon.LuaInt(val) >> LuaCommon.LuaInt(amt));
return (uint)(LuaInt(val) >> LuaInt(amt));
}
}
}

View File

@ -3,33 +3,49 @@ using BizHawk.Client.Common;
namespace BizHawk.MultiClient
{
public static class MultiClientLuaLibrary
public class MultiClientLuaLibrary : LuaLibraryBase
{
public static string Name = "client";
public static string[] Functions = new[]
public MultiClientLuaLibrary(Action<string> logOutputCallback)
: this()
{
"closerom",
"getwindowsize",
"opencheats",
"openhexeditor",
"openramwatch",
"openramsearch",
"openrom",
"opentasstudio",
"opentoolbox",
"opentracelogger",
"pause_av",
"reboot_core",
"screenheight",
"screenshot",
"screenshottoclipboard",
"screenwidth",
"setscreenshotosd",
"setwindowsize",
"unpause_av",
"xpos",
"ypos",
};
LogOutputCallback = logOutputCallback;
}
public MultiClientLuaLibrary() : base() { }
public override string Name { get { return "client"; } }
public override string[] Functions
{
get
{
return new []
{
"closerom",
"getwindowsize",
"opencheats",
"openhexeditor",
"openramwatch",
"openramsearch",
"openrom",
"opentasstudio",
"opentoolbox",
"opentracelogger",
"pause_av",
"reboot_core",
"screenheight",
"screenshot",
"screenshottoclipboard",
"screenwidth",
"setscreenshotosd",
"setwindowsize",
"unpause_av",
"xpos",
"ypos",
};
}
}
public Action<string> LogOutputCallback = null;
public static void client_closerom()
{
@ -123,7 +139,7 @@ namespace BizHawk.MultiClient
return GlobalWinF.RenderPanel.NativeSize.Width;
}
public static void client_setwindowsize(object window_size)
public void client_setwindowsize(object window_size)
{
try
{
@ -137,12 +153,15 @@ namespace BizHawk.MultiClient
}
else
{
ConsoleLuaLibrary.console_log("Invalid window size");
if (LogOutputCallback != null)
{
LogOutputCallback("Invalid window size");
}
}
}
catch
{
ConsoleLuaLibrary.console_log("Invalid window size");
LogOutputCallback("Invalid window size");
}
}

View File

@ -6,16 +6,22 @@ using LuaInterface;
namespace BizHawk.MultiClient
{
public static class ConsoleLuaLibrary
public class ConsoleLuaLibrary : LuaLibraryBase
{
public static string Name = "console";
public static string[] Functions = new[]
public override string Name { get { return "console"; } }
public override string[] Functions
{
"clear",
"getluafunctionslist",
"log",
"output",
};
get
{
return new[]
{
"clear",
"getluafunctionslist",
"log",
"output",
};
}
}
public static void console_clear()
{
@ -24,13 +30,12 @@ namespace BizHawk.MultiClient
public static string console_getluafunctionslist()
{
string list = "";
foreach (LuaDocumentation.LibraryFunction l in GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList)
StringBuilder list = new StringBuilder();
foreach (var function in GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList)
{
list += l.name + "\n";
list.AppendLine(function.Name);
}
return list;
return list.ToString();
}
public static void console_log(object lua_input)

View File

@ -4,25 +4,31 @@ using BizHawk.Emulation.Consoles.Nintendo;
namespace BizHawk.MultiClient
{
public static class NESLuaLibrary
public class NESLuaLibrary : LuaLibraryBase
{
public static string Name = "nes";
public static string[] Functions = new[]
public override string Name { get { return "nes"; } }
public override string[] Functions
{
"addgamegenie",
"getallowmorethaneightsprites",
"getbottomscanline",
"getclipleftandright",
"getdispbackground",
"getdispsprites",
"gettopscanline",
"removegamegenie",
"setallowmorethaneightsprites",
"setclipleftandright",
"setdispbackground",
"setdispsprites",
"setscanlines",
};
get
{
return new[]
{
"addgamegenie",
"getallowmorethaneightsprites",
"getbottomscanline",
"getclipleftandright",
"getdispbackground",
"getdispsprites",
"gettopscanline",
"removegamegenie",
"setallowmorethaneightsprites",
"setclipleftandright",
"setdispbackground",
"setdispsprites",
"setscanlines",
};
}
}
public static void nes_addgamegenie(string code)
{
@ -145,8 +151,8 @@ namespace BizHawk.MultiClient
public static void nes_setscanlines(object top, object bottom, bool pal = false)
{
int first = LuaCommon.LuaInt(top);
int last = LuaCommon.LuaInt(bottom);
int first = LuaInt(top);
int last = LuaInt(bottom);
if (first > 127)
{
first = 127;

View File

@ -2,28 +2,34 @@
namespace BizHawk.MultiClient
{
public static class SNESLuaLibrary
public class SNESLuaLibrary : LuaLibraryBase
{
public static string Name = "snes";
public static string[] Functions = new[]
public override string Name { get { return "snes"; } }
public override string[] Functions
{
"getlayer_bg_1",
"getlayer_bg_2",
"getlayer_bg_3",
"getlayer_bg_4",
"getlayer_obj_1",
"getlayer_obj_2",
"getlayer_obj_3",
"getlayer_obj_4",
"setlayer_bg_1",
"setlayer_bg_2",
"setlayer_bg_3",
"setlayer_bg_4",
"setlayer_obj_1",
"setlayer_obj_2",
"setlayer_obj_3",
"setlayer_obj_4",
};
get
{
return new[]
{
"getlayer_bg_1",
"getlayer_bg_2",
"getlayer_bg_3",
"getlayer_bg_4",
"getlayer_obj_1",
"getlayer_obj_2",
"getlayer_obj_3",
"getlayer_obj_4",
"setlayer_bg_1",
"setlayer_bg_2",
"setlayer_bg_3",
"setlayer_bg_4",
"setlayer_obj_1",
"setlayer_obj_2",
"setlayer_obj_3",
"setlayer_obj_4",
};
}
}
public static bool snes_getlayer_bg_1()
{

View File

@ -231,50 +231,11 @@ namespace BizHawk.MultiClient
{
lua.RegisterFunction("print", this, GetType().GetMethod("print"));
lua.NewTable("bit");
foreach (var funcName in BitLuaLibrary.Functions)
{
string libName = BitLuaLibrary.Name + "." + funcName;
var method = (typeof(BitLuaLibrary)).GetMethod(BitLuaLibrary.Name + "_" + funcName);
lua.RegisterFunction(libName, this, method);
Docs.Add(BitLuaLibrary.Name, funcName, method);
}
lua.NewTable("client");
foreach (var funcName in MultiClientLuaLibrary.Functions)
{
string libName = MultiClientLuaLibrary.Name + "." + funcName;
var method = (typeof(MultiClientLuaLibrary)).GetMethod(MultiClientLuaLibrary.Name + "_" + funcName);
lua.RegisterFunction(libName, this, method);
Docs.Add(MultiClientLuaLibrary.Name, funcName, method);
}
lua.NewTable("console");
foreach (var funcName in ConsoleLuaLibrary.Functions)
{
string libName = ConsoleLuaLibrary.Name + "." + funcName;
var method = (typeof(ConsoleLuaLibrary)).GetMethod(ConsoleLuaLibrary.Name + "_" + funcName);
lua.RegisterFunction(libName, this, method);
Docs.Add(ConsoleLuaLibrary.Name, funcName, method);
}
lua.NewTable("nes");
foreach (var funcName in NESLuaLibrary.Functions)
{
string libName = NESLuaLibrary.Name + "." + funcName;
var method = (typeof(NESLuaLibrary)).GetMethod(NESLuaLibrary.Name + "_" + funcName);
lua.RegisterFunction(libName, this, method);
Docs.Add(NESLuaLibrary.Name, funcName, method);
}
lua.NewTable("snes");
foreach (var funcName in SNESLuaLibrary.Functions)
{
string libName = SNESLuaLibrary.Name + "." + funcName;
var method = (typeof(SNESLuaLibrary)).GetMethod(SNESLuaLibrary.Name + "_" + funcName);
lua.RegisterFunction(libName, this, method);
Docs.Add(SNESLuaLibrary.Name, funcName, method);
}
new BitLuaLibrary().LuaRegister(lua, Docs);
new MultiClientLuaLibrary(ConsoleLuaLibrary.console_log).LuaRegister(lua, Docs);
new ConsoleLuaLibrary().LuaRegister(lua, Docs);
new NESLuaLibrary().LuaRegister(lua, Docs);
new SNESLuaLibrary().LuaRegister(lua, Docs);
lua.NewTable("gui");
foreach (string t in GuiFunctions)

View File

@ -0,0 +1,43 @@
using System;
using LuaInterface;
namespace BizHawk.MultiClient
{
public abstract class LuaLibraryBase
{
public abstract string Name { get; }
public abstract string[] Functions { get; }
public virtual void LuaRegister(Lua lua, ILuaDocumentation docs = null)
{
lua.NewTable(Name);
foreach (string methodName in Functions)
{
string func = Name + "." + methodName;
var method = GetType().GetMethod(Name + "_" + methodName);
lua.RegisterFunction(
Name + "." + methodName,
this,
GetType().GetMethod(Name + "_" + methodName)
);
if (docs != null)
{
docs.Add(Name, methodName, method);
}
}
}
protected static int LuaInt(object lua_arg)
{
return Convert.ToInt32((double)lua_arg);
}
protected static uint LuaUInt(object lua_arg)
{
return Convert.ToUInt32((double)lua_arg);
}
}
}

View File

@ -1,11 +1,17 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.MultiClient
{
public class LuaDocumentation
public interface ILuaDocumentation
{
void Add(string method_lib, string method_name, System.Reflection.MethodInfo method);
}
public class LuaDocumentation : ILuaDocumentation
{
public List<LibraryFunction> FunctionList = new List<LibraryFunction>();
@ -22,7 +28,7 @@ namespace BizHawk.MultiClient
public void Sort()
{
FunctionList = FunctionList.OrderBy(x => x.library).ThenBy(x => x.name).ToList();
FunctionList = FunctionList.OrderBy(x => x.Library).ThenBy(x => x.Name).ToList();
}
public List<string> GetLibraryList()
@ -30,7 +36,7 @@ namespace BizHawk.MultiClient
HashSet<string> libs = new HashSet<string>();
foreach (LibraryFunction function in FunctionList)
{
libs.Add(function.library);
libs.Add(function.Library);
}
return libs.ToList();
@ -38,27 +44,27 @@ namespace BizHawk.MultiClient
public List<string> GetFunctionsByLibrary(string library)
{
return (from t in FunctionList where t.library == library select t.name).ToList();
return (from t in FunctionList where t.Library == library select t.Name).ToList();
}
public class LibraryFunction
{
public LibraryFunction(string method_lib, string method_name, System.Reflection.MethodInfo method)
{
library = method_lib;
name = method_name;
Library = method_lib;
Name = method_name;
System.Reflection.ParameterInfo[] info = method.GetParameters();
foreach (System.Reflection.ParameterInfo p in info)
{
parameters.Add(p.ToString());
Parameters.Add(p.ToString());
}
return_type = method.ReturnType.ToString();
}
public string library = "";
public string name = "";
public List<string> parameters = new List<string>();
public string return_type = "";
public string Library = String.Empty;
public string Name = String.Empty;
public List<string> Parameters = new List<string>();
public string return_type = String.Empty;
public string ParameterList
{
@ -66,11 +72,11 @@ namespace BizHawk.MultiClient
{
StringBuilder list = new StringBuilder();
list.Append('(');
for (int i = 0; i < parameters.Count; i++)
for (int i = 0; i < Parameters.Count; i++)
{
string param = parameters[i].Replace("System", "").Replace("Object", "").Replace(" ", "").Replace(".", "").Replace("LuaInterface", "");
string param = Parameters[i].Replace("System", "").Replace("Object", "").Replace(" ", "").Replace(".", "").Replace("LuaInterface", "");
list.Append(param);
if (i < parameters.Count - 1)
if (i < Parameters.Count - 1)
{
list.Append(',');
}

View File

@ -26,8 +26,8 @@ namespace BizHawk.MultiClient
foreach (LuaDocumentation.LibraryFunction l in GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList)
{
ListViewItem item = new ListViewItem {Text = l.ReturnType};
item.SubItems.Add(l.library + ".");
item.SubItems.Add(l.name);
item.SubItems.Add(l.Library + ".");
item.SubItems.Add(l.Name);
item.SubItems.Add(l.ParameterList);
FunctionView.Items.Add(item);
}
@ -44,10 +44,10 @@ namespace BizHawk.MultiClient
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderByDescending(x => x.ReturnType).ToList();
break;
case 1: //Library
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderByDescending(x => x.library).ToList();
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderByDescending(x => x.Library).ToList();
break;
case 2: //Name
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderByDescending(x => x.name).ToList();
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderByDescending(x => x.Name).ToList();
break;
case 3: //Parameters
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderByDescending(x => x.ParameterList).ToList();
@ -62,10 +62,10 @@ namespace BizHawk.MultiClient
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderBy(x => x.ReturnType).ToList();
break;
case 1: //Library
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderBy(x => x.library).ToList();
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderBy(x => x.Library).ToList();
break;
case 2: //Name
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderBy(x => x.name).ToList();
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderBy(x => x.Name).ToList();
break;
case 3: //Parameters
GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList.OrderBy(x => x.ParameterList).ToList();
@ -133,7 +133,7 @@ namespace BizHawk.MultiClient
foreach (int index in indexes)
{
var library_function = GlobalWinF.MainForm.LuaConsole1.LuaImp.Docs.FunctionList[index];
sb.Append(library_function.library).Append('.').Append(library_function.name).Append("()\n");
sb.Append(library_function.Library).Append('.').Append(library_function.Name).Append("()\n");
}
if (sb.Length > 0)