BizHawk/BizHawk.Client.Common/lua/LuaHelper.cs

97 lines
3.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using NLua;
namespace BizHawk.Client.Common
{
public static class LuaExtensions
{
/// <remarks><c>-0x1FFFFFFFFFFFFF..0x1FFFFFFFFFFFFF</c></remarks>
private static readonly Range<double> PrecisionLimits = (-9007199254740991.0).RangeTo(9007199254740991.0);
/// <remarks>
/// Lua numbers are always double-length floats, so integers whose magnitude is at least 2^53 may not fit in the 53-bit mantissa (the sign is stored separately).
/// These extremely large values aren't that useful, so we'll just assume they're erroneous and give the script author an error.
/// </remarks>
/// <exception cref="ArithmeticException"><paramref name="d"/> &ge; 2^53 or <paramref name="d"/> &le; -2^53</exception>
public static long AsInteger(this double d) => PrecisionLimits.Contains(d) ? (long) d : throw new ArithmeticException("integer value exceeds the precision of Lua's integer-as-double");
public static LuaTable EnumerateToLuaTable<T>(this IEnumerable<T> list, Lua lua) => list.ToList().ToLuaTable(lua);
public static LuaTable ToLuaTable<T>(this IList<T> list, Lua lua, int indexFrom = 0)
{
var table = lua.NewTable();
var indexAfterLast = indexFrom + list.Count;
for (var i = indexFrom; i != indexAfterLast; i++)
{
table[i] = list[i];
}
return table;
}
public static LuaTable ToLuaTable<T>(this IDictionary<string, T> dictionary, Lua lua)
{
var table = lua.NewTable();
foreach (var kvp in dictionary)
{
table[kvp.Key] = kvp.Value;
}
return table;
}
public static LuaTable TableFromObject(this Lua lua, object obj)
{
var table = lua.NewTable();
foreach (var method in obj.GetType().GetMethods())
{
if (!method.IsPublic) continue;
var foundAttrs = method.GetCustomAttributes(typeof(LuaMethodAttribute), false);
table[method.Name] = lua.RegisterFunction(
foundAttrs.Length == 0 ? string.Empty : ((LuaMethodAttribute) foundAttrs[0]).Name, // empty string will default to the actual method name
obj,
method
);
}
return table;
}
public static IDictionary<string, dynamic> ToDictionary(this IController controller, int? controllerNum = null)
{
var buttons = new Dictionary<string, dynamic>();
foreach (var button in controller.Definition.BoolButtons)
{
if (controllerNum == null)
{
buttons[button] = controller.IsPressed(button);
}
else if (button.Length > 2 && button.Substring(0, 2) == $"P{controllerNum}")
{
var sub = button.Substring(3);
buttons[sub] = controller.IsPressed($"P{controllerNum} {sub}");
}
}
foreach (var button in controller.Definition.FloatControls)
{
if (controllerNum == null)
{
buttons[button] = controller.GetFloat(button);
}
else if (button.Length > 2 && button.Substring(0, 2) == $"P{controllerNum}")
{
var sub = button.Substring(3);
buttons[sub] = controller.GetFloat($"P{controllerNum} {sub}");
}
}
return buttons;
}
}
}