Skip to content

Commit

Permalink
make Traverse into a proxy for proper type conversions
Browse files Browse the repository at this point in the history
a
  • Loading branch information
Eddio0141 committed Aug 27, 2024
1 parent 04b8af6 commit db3f831
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
using System;
using HarmonyLib;
using MoonSharp.Interpreter;
using UniTAS.Patcher.Interfaces.GUI;
using UniTAS.Patcher.Utils;

namespace UniTAS.Patcher.Implementations.GUI.TerminalCommands;

public class Traverse : TerminalCmd
public class TraverseCmd : TerminalCmd
{
public override string Name => "traverse";
public override string Description => "traverse API wrapper";
public override Delegate Callback => Execute;

private HarmonyLib.Traverse Execute(Script script, object arg)
private static Traverse Execute(Script script, object arg)
{
if (arg is string s)
{
Expand All @@ -23,16 +24,16 @@ private HarmonyLib.Traverse Execute(Script script, object arg)
return null;
}

return new HarmonyLib.Traverse(type);
return new Traverse(type);
}

return new HarmonyLib.Traverse(arg);
return new Traverse(arg);
}

public override void Setup()
{
base.Setup();

UserData.RegisterType<HarmonyLib.Traverse>();
UserData.RegisterType<Traverse>();
}
}
5 changes: 5 additions & 0 deletions UniTAS/Patcher/Implementations/LiveScripting.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using HarmonyLib;
using MoonSharp.Interpreter;
using MoonSharp.Interpreter.Interop;
using MoonSharp.Interpreter.Interop.RegistrationPolicies;
using MoonSharp.Interpreter.Loaders;
using UniTAS.Patcher.Implementations.Proxies;
using UniTAS.Patcher.Interfaces.DependencyInjection;
using UniTAS.Patcher.Services;
using UniTAS.Patcher.Services.Logging;
Expand Down Expand Up @@ -36,6 +38,9 @@ public bool AllowTypeAutoRegistration(Type type)
public LiveScripting(ILogger logger)
{
UserData.RegistrationPolicy = new CustomInteropRegistrationPolicy();
// TODO: movie proxies should be registered here instead
// TODO: proxies must be gathered with some attribute
UserData.RegisterProxyType<TraverseProxy, Traverse>(x => new TraverseProxy(x));
_logger = logger;
}

Expand Down
90 changes: 90 additions & 0 deletions UniTAS/Patcher/Implementations/Proxies/TraverseProxy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using HarmonyLib;
using MoonSharp.Interpreter;

namespace UniTAS.Patcher.Implementations.Proxies;

[method: MoonSharpHidden]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public class TraverseProxy(Traverse traverse)
{
private static readonly AccessTools.FieldRef<object, MethodBase> TraverseMethodField =
AccessTools.FieldRefAccess<MethodBase>(typeof(Traverse), "_method");

private static readonly AccessTools.FieldRef<object, MemberInfo> TraverseInfoField =
AccessTools.FieldRefAccess<MemberInfo>(typeof(Traverse), "_info");

public object GetValue(params object[] args) => traverse.GetValue(args);

public object GetValue() => traverse.GetValue();

public Traverse SetValue(DynValue value)
{
var memberInfo = TraverseInfoField(traverse);

switch (memberInfo)
{
case FieldInfo f:
return traverse.SetValue(value.ToObject(f.FieldType));
case PropertyInfo p:
return traverse.SetValue(value.ToObject(p.PropertyType));
}

var args = TraverseMethodField(traverse).GetParameters();
var argsLength = args.Length;
var argTypes = args.Select(x => x.ParameterType);

object valueConverted;
if (argsLength == 1)
{
valueConverted = value.ToObject(argTypes.First());
}
else if (value.Type is not (DataType.Table or DataType.UserData))
{
throw new Exception("Traverse has more than 1 arguments required, but didn't receive a table or UserData");
}
else if (value.Type is DataType.Table && value.Table.Length != argsLength)
{
throw new Exception($"Mismatch in traverse method argument count, expected {argsLength} arguments");
}
else
{
var convertedArray = new object[argsLength];
var table = value.Table;
var values = table.Values.GetEnumerator();
var argTypesEnumerator = argTypes.GetEnumerator();
for (var i = 0; i < table.Length; i++)
{
// wont fail
values.MoveNext();
argTypesEnumerator.MoveNext();

var item = values.Current;
var argType = argTypesEnumerator.Current;

convertedArray[i] = item!.ToObject(argType);
}

values.Dispose();
argTypesEnumerator.Dispose();

valueConverted = convertedArray;
}

return traverse.SetValue(valueConverted);
}

public Traverse Field(string name) => traverse.Field(name);

public Traverse Property(string name, object[] index = null) => traverse.Property(name, index);

public Traverse Method(string name, params object[] arguments) => traverse.Method(name, arguments);

public Traverse Method(string name, Type[] paramTypes, object[] arguments = null) =>
traverse.Method(name, paramTypes, arguments);

public bool PropertyExists() => traverse.PropertyExists();
}

0 comments on commit db3f831

Please sign in to comment.