Skip to content

Commit 5a1d127

Browse files
committed
Heres a unfinished lua thing im not going to finish so if anyone wants it here it is
1 parent 2839b19 commit 5a1d127

File tree

4 files changed

+144
-25
lines changed

4 files changed

+144
-25
lines changed

src/LuaManager.cs

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
using Il2CppInterop.Runtime.InteropTypes.Arrays;
55
using Il2CppSystem.Collections;
66
using MoonSharp.Interpreter;
7+
using MoonSharp.Interpreter.Debugging;
78
using MoonSharp.Interpreter.Interop;
89
using Newtonsoft.Json.Linq;
910
using PolyMod.modApi;
1011
using Polytopia.Data;
12+
using PolytopiaBackendBase.Game;
1113
using UnityEngine;
1214
using IDisposable = Il2CppSystem.IDisposable;
1315
using Input = PolyMod.modApi.Input;
@@ -21,24 +23,7 @@ public class LuaManager
2123
private ManualLogSource logger;
2224
static LuaManager()
2325
{
24-
Script.GlobalOptions.CustomConverters.SetClrToScriptCustomConversion(typeof(IEnumerable<>), (_, enumerable) =>
25-
{
26-
IEnumerator enumerator = ((IEnumerable) enumerable).GetEnumerator();
27-
return DynValue.NewCallback((context, args) =>
28-
{
29-
if (enumerator.MoveNext())
30-
{
31-
// Return the current item as a single value tuple
32-
return DynValue.NewTuple(DynValue.FromObject(context.GetScript(), enumerator.Current));
33-
}
34-
else
35-
{
36-
// Iterator is finished
37-
((object)enumerator as IDisposable).Dispose();
38-
return DynValue.Nil;
39-
}
40-
});
41-
});
26+
4227
}
4328
public LuaManager(string modName)
4429
{
@@ -71,18 +56,46 @@ void RegisterTypesAndExtensions(IEnumerable<Type> types)
7156
RegisterTypesAndExtensions(typeof(Enumerable).Assembly.GetTypes()); // linq
7257

7358
#region PolyMod.*
59+
60+
UserData.RegisterType(typeof(Registry));
61+
lua.Globals["Registry"] = typeof(Registry);
62+
7463
UserData.RegisterType(typeof(Patch));
7564
lua.Globals["Patch"] = typeof(Patch);
7665

7766
UserData.RegisterType(typeof(General));
7867
lua.Globals["General"] = typeof(General);
7968

69+
UserData.RegisterType(typeof(LuaEnumCache));
70+
lua.Globals["EnumCache"] = typeof(LuaEnumCache);
71+
72+
LuaEnumCache.RegisterEnum<GameMode>("GameMode");
73+
LuaEnumCache.RegisterEnum<TribeData.Type>("TribeType");
74+
LuaEnumCache.RegisterEnum<TechData.Type>("TechType");
75+
LuaEnumCache.RegisterEnum<UnitData.Type>("UnitType");
76+
LuaEnumCache.RegisterEnum<ImprovementData.Type>("ImprovementType");
77+
LuaEnumCache.RegisterEnum<Polytopia.Data.TerrainData.Type>("TerrainType");
78+
LuaEnumCache.RegisterEnum<ResourceData.Type>("ResourceType");
79+
LuaEnumCache.RegisterEnum<TaskData.Type>("TaskType");
80+
LuaEnumCache.RegisterEnum<TribeAbility.Type>("TribeAbilityType");
81+
LuaEnumCache.RegisterEnum<UnitAbility.Type>("UnitAbilityType");
82+
LuaEnumCache.RegisterEnum<ImprovementAbility.Type>("ImprovementAbilityType");
83+
LuaEnumCache.RegisterEnum<PlayerAbility.Type>("PlayerAbilityType");
84+
LuaEnumCache.RegisterEnum<UnitData.WeaponEnum>("WeaponType");
85+
LuaEnumCache.RegisterEnum<KeyCode>("KeyCode");
86+
LuaEnumCache.RegisterEnum<SkinType>("SkinType");
87+
88+
8089
UserData.RegisterType<LuaConfig>();
8190
lua.Globals["Config"] = new LuaConfig(modName, Config<JsonNode>.ConfigTypes.PerMod, lua);
8291
lua.Globals["ExposedConfig"] = new LuaConfig(modName, Config<JsonNode>.ConfigTypes.Exposed, lua);
8392

8493
UserData.RegisterType(typeof(Input));
8594
lua.Globals["Input"] = typeof(Input);
95+
96+
UserData.RegisterExtensionType(typeof(Il2cppEnumerableExtensions));
97+
98+
lua.Globals["clrTypeOf"] = DynValue.NewCallback((_, args) => DynValue.NewString(args[0].ToObject().GetType().FullName));
8699
#endregion
87100

88101
#region Il2cppSystem.*
@@ -147,7 +160,11 @@ public void Execute(string code, string fileName)
147160
}
148161
catch (ScriptRuntimeException e)
149162
{
150-
logger.LogError(e.DecoratedMessage);
163+
logger.LogError(e.DecoratedMessage ?? e.Message);
164+
foreach (var item in e.CallStack)
165+
{
166+
logger.LogError($"AT {item.Location}");
167+
}
151168
}
152169
}
153170
public void ExecuteFile(string path)
@@ -162,3 +179,15 @@ public void ExecuteFile(string path)
162179
}
163180
}
164181
}
182+
183+
public static class Il2cppEnumerableExtensions
184+
{
185+
public static System.Collections.IEnumerable ToMono<T>(this Il2CppSystem.Collections.Generic.IEnumerable<T> enumerable)
186+
{
187+
var list = Il2CppSystem.Linq.Enumerable.ToList(enumerable);
188+
foreach (T v in list)
189+
{
190+
yield return v;
191+
}
192+
}
193+
}

src/Registry.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace PolyMod;
1111
/// </summary>
1212
public static class Registry
1313
{
14-
internal static int autoidx = Constants.AUTOIDX_STARTS_FROM;
14+
public static int autoidx = Constants.AUTOIDX_STARTS_FROM;
1515

1616
/// <summary>The registry for custom sprites.</summary>
1717
internal static Dictionary<string, Sprite> sprites = new();
@@ -49,8 +49,8 @@ public static class Registry
4949
/// <summary>The registry for custom skin information.</summary>
5050
internal static List<Visual.SkinInfo> skinInfo = new();
5151

52-
internal static int climateAutoidx = (int)Enum.GetValues(typeof(TribeData.Type)).Cast<TribeData.Type>().Last();
53-
internal static int gameModesAutoidx = Enum.GetValues(typeof(GameMode)).Length;
52+
public static int climateAutoidx = (int)Enum.GetValues(typeof(TribeData.Type)).Cast<TribeData.Type>().Last();
53+
public static int gameModesAutoidx = Enum.GetValues(typeof(GameMode)).Length;
5454

5555
/// <summary>
5656
/// Retrieves a sprite from the registry based on its name, style, and level.

src/modApi/EnumCache.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using Polytopia.Data;
2+
3+
namespace PolyMod.modApi;
4+
5+
public static class LuaEnumCache
6+
{
7+
// Store delegates for each enum type
8+
private static readonly Dictionary<string, Func<string, object>> _getTypeFuncs = new();
9+
private static readonly Dictionary<string, Action<string, object>> _addMappingFuncs = new();
10+
private static readonly Dictionary<string, Type> _enumTypes = new();
11+
12+
// Register a type for Lua use
13+
public static void RegisterEnum<T>(string typeName) where T : struct, Enum
14+
{
15+
_enumTypes[typeName] = typeof(T);
16+
// Add GetType function
17+
_getTypeFuncs[typeName] = (string name) =>
18+
{
19+
if (EnumCache<T>.TryGetType(name, out var value))
20+
return value;
21+
return null;
22+
};
23+
24+
// Add AddMapping function
25+
_addMappingFuncs[typeName] = (string name, object val) =>
26+
{
27+
if (val is T enumVal)
28+
EnumCache<T>.AddMapping(name, enumVal);
29+
else
30+
throw new ArgumentException($"Value must be of type {typeof(T)} but is of type {val.GetType()}");
31+
};
32+
}
33+
34+
// Lua-friendly GetType
35+
public static object GetType(string typeName, string name)
36+
{
37+
if (_getTypeFuncs.TryGetValue(typeName, out var func))
38+
return func(name);
39+
throw new Exception($"Enum type '{typeName}' not registered.");
40+
}
41+
42+
// Lua-friendly TryGetType
43+
public static bool TryGetType(string typeName, string name, out object value)
44+
{
45+
if (_getTypeFuncs.TryGetValue(typeName, out var func))
46+
{
47+
value = func(name);
48+
return value != null;
49+
}
50+
value = null;
51+
return false;
52+
}
53+
54+
// Lua-friendly AddMapping
55+
public static void AddMapping(string typeName, string name, object value)
56+
{
57+
58+
if (!_addMappingFuncs.TryGetValue(typeName, out var func))
59+
{
60+
throw new Exception($"Enum type '{typeName}' not registered.");
61+
}
62+
63+
// If the value is a double, attempt to convert it to the underlying type of the enum
64+
if (value is double doubleValue)
65+
{
66+
if (!_enumTypes.TryGetValue(typeName, out var enumType))
67+
{
68+
// This should not happen if func was found, but for safety.
69+
throw new Exception($"Enum type '{typeName}' not registered correctly (type info missing).");
70+
}
71+
var underlyingType = Enum.GetUnderlyingType(enumType);
72+
var valueInUnderlyingType = Convert.ChangeType(doubleValue, underlyingType);
73+
value = Enum.ToObject(enumType, valueInUnderlyingType);
74+
}
75+
76+
func(name, value);
77+
}
78+
}

src/modApi/Patch.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
using System;
33
using System.Collections.Generic;
4+
using System.Linq;
45
using System.Linq.Expressions;
56
using System.Reflection;
67
using HarmonyLib;
@@ -119,7 +120,15 @@ DynValue ExecuteChain(int i)
119120
{
120121
try
121122
{
122-
normalizedArgs[idx] = Convert.ChangeType(arg, expectedType);
123+
if (expectedType.IsEnum)
124+
{
125+
var underlyingValue = Convert.ChangeType(arg, Enum.GetUnderlyingType(expectedType));
126+
normalizedArgs[idx] = Enum.ToObject(expectedType, underlyingValue);
127+
}
128+
else
129+
{
130+
normalizedArgs[idx] = Convert.ChangeType(arg, expectedType);
131+
}
123132
}
124133
catch
125134
{
@@ -155,7 +164,10 @@ DynValue ExecuteChain(int i)
155164
{
156165
Plugin.logger.LogError($"IN METHOD {__originalMethod.DeclaringType.FullName}.{__originalMethod.Name}({string.Join(", ", __originalMethod.GetParameters().Select(p => p.ParameterType))}):");
157166
Plugin.logger.LogError(e.DecoratedMessage ?? e.Message);
158-
Plugin.logger.LogError(e.InnerException);
167+
foreach (var item in e.CallStack)
168+
{
169+
Plugin.logger.LogError($"AT {item.Location}");
170+
}
159171
return true;
160172
}
161173
catch (Exception e)
@@ -174,4 +186,4 @@ private static bool PrefixVoid(MethodBase __originalMethod, object[] __args, obj
174186
object? nothing = null;
175187
return Prefix(__originalMethod, ref nothing, __args, __instance);
176188
}
177-
}
189+
}

0 commit comments

Comments
 (0)