Merge pull request #108 from notpeelz/feat-patch-ctor
Add constructor support to Hook.Patch
This commit is contained in:
@@ -3,6 +3,6 @@
|
|||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0" />
|
||||||
<PackageReference Include="Lib.Harmony" Version="2.2.2" />
|
<PackageReference Include="Lib.Harmony" Version="2.2.2" />
|
||||||
<PackageReference Include="Sigil" Version="5.0.0" />
|
<PackageReference Include="Sigil" Version="5.0.0" />
|
||||||
<ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Libraries\moonsharp\src\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.netcore\MoonSharp.Interpreter.netcore.csproj" />
|
<ProjectReference Include="$(MSBuildThisFileDirectory)..\..\Libraries\moonsharp\MoonSharp.Interpreter\MoonSharp.Interpreter.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copied from https://github.com/evilfactory/moonsharp/blob/5264656c6442e783f3c75082cce69a93d66d4cc0/src/MoonSharp.Interpreter/Interop/Converters/ScriptToClrConversions.cs#L79-L99
|
// Copied from https://github.com/evilfactory/moonsharp/blob/5264656c6442e783f3c75082cce69a93d66d4cc0/src/MoonSharp.Interpreter/Interop/Converters/ScriptToClrConversions.cs#L79-L99
|
||||||
private static MethodInfo HasImplicitConversion(Type baseType, Type targetType)
|
private static MethodInfo GetImplicitOperatorMethod(Type baseType, Type targetType)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -101,12 +101,12 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (baseType.BaseType != null)
|
if (baseType.BaseType != null)
|
||||||
{
|
{
|
||||||
return HasImplicitConversion(baseType.BaseType, targetType);
|
return GetImplicitOperatorMethod(baseType.BaseType, targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetType.BaseType != null)
|
if (targetType.BaseType != null)
|
||||||
{
|
{
|
||||||
return HasImplicitConversion(baseType, targetType.BaseType);
|
return GetImplicitOperatorMethod(baseType, targetType.BaseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -141,18 +141,18 @@ namespace Barotrauma
|
|||||||
il.Call(typeof(object).GetMethod("GetType"));
|
il.Call(typeof(object).GetMethod("GetType"));
|
||||||
il.StoreLocal(baseType);
|
il.StoreLocal(baseType);
|
||||||
|
|
||||||
// IL: var implicitConversionMethod = SigilExtensions.HasImplicitConversion(baseType, <targetType>);
|
// IL: var implicitOperatorMethod = SigilExtensions.GetImplicitOperatorMethod(baseType, <targetType>);
|
||||||
var implicitConversionMethod = il.DeclareLocal(typeof(MethodInfo), $"cast_implicitConversionMethod_{guid}");
|
var implicitOperatorMethod = il.DeclareLocal(typeof(MethodInfo), $"cast_implicitOperatorMethod_{guid}");
|
||||||
il.LoadLocal(baseType);
|
il.LoadLocal(baseType);
|
||||||
il.LoadType(targetType);
|
il.LoadType(targetType);
|
||||||
il.Call(typeof(SigilExtensions).GetMethod(nameof(HasImplicitConversion), BindingFlags.NonPublic | BindingFlags.Static));
|
il.Call(typeof(SigilExtensions).GetMethod(nameof(GetImplicitOperatorMethod), BindingFlags.NonPublic | BindingFlags.Static));
|
||||||
il.StoreLocal(implicitConversionMethod);
|
il.StoreLocal(implicitOperatorMethod);
|
||||||
|
|
||||||
// IL: <TargetType> castValue;
|
// IL: <TargetType> castValue;
|
||||||
var castValue = il.DeclareLocal(targetType, $"cast_castValue_{guid}");
|
var castValue = il.DeclareLocal(targetType, $"cast_castValue_{guid}");
|
||||||
|
|
||||||
// IL: if (implicitConversionMethod != null)
|
// IL: if (implicitConversionMethod != null)
|
||||||
il.LoadLocal(implicitConversionMethod);
|
il.LoadLocal(implicitOperatorMethod);
|
||||||
il.Branch((il) =>
|
il.Branch((il) =>
|
||||||
{
|
{
|
||||||
// IL: var methodInvokeParams = new object[1];
|
// IL: var methodInvokeParams = new object[1];
|
||||||
@@ -168,7 +168,7 @@ namespace Barotrauma
|
|||||||
il.StoreElement<object>();
|
il.StoreElement<object>();
|
||||||
|
|
||||||
// IL: castValue = (<TargetType>)implicitConversionMethod.Invoke(null, methodInvokeParams);
|
// IL: castValue = (<TargetType>)implicitConversionMethod.Invoke(null, methodInvokeParams);
|
||||||
il.LoadLocal(implicitConversionMethod);
|
il.LoadLocal(implicitOperatorMethod);
|
||||||
il.LoadNull(); // first parameter is null because implicit cast operators are static
|
il.LoadNull(); // first parameter is null because implicit cast operators are static
|
||||||
il.LoadLocal(methodInvokeParams);
|
il.LoadLocal(methodInvokeParams);
|
||||||
il.Call(typeof(MethodInfo).GetMethod("Invoke", new[] { typeof(object), typeof(object[]) }));
|
il.Call(typeof(MethodInfo).GetMethod("Invoke", new[] { typeof(object), typeof(object[]) }));
|
||||||
@@ -519,9 +519,9 @@ namespace Barotrauma
|
|||||||
"ContentPackageManager",
|
"ContentPackageManager",
|
||||||
};
|
};
|
||||||
|
|
||||||
private static void ValidatePatchTarget(MethodInfo methodInfo)
|
private static void ValidatePatchTarget(MethodBase method)
|
||||||
{
|
{
|
||||||
if (prohibitedHooks.Any(h => methodInfo.DeclaringType.FullName.StartsWith(h)))
|
if (prohibitedHooks.Any(h => method.DeclaringType.FullName.StartsWith(h)))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Hooks into the modding environment are prohibited.");
|
throw new ArgumentException("Hooks into the modding environment are prohibited.");
|
||||||
}
|
}
|
||||||
@@ -575,7 +575,7 @@ namespace Barotrauma
|
|||||||
return !(left == right);
|
return !(left == right);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodKey Create(MethodInfo method) => new MethodKey
|
public static MethodKey Create(MethodBase method) => new MethodKey
|
||||||
{
|
{
|
||||||
ModuleHandle = method.Module.ModuleHandle,
|
ModuleHandle = method.Module.ModuleHandle,
|
||||||
MetadataToken = method.MetadataToken,
|
MetadataToken = method.MetadataToken,
|
||||||
@@ -814,30 +814,37 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public object Call(string name, params object[] args) => Call<object>(name, args);
|
public object Call(string name, params object[] args) => Call<object>(name, args);
|
||||||
|
|
||||||
private static MethodInfo ResolveMethod(string className, string methodName, string[] parameterNames)
|
private static MethodBase ResolveMethod(string className, string methodName, string[] parameters)
|
||||||
{
|
{
|
||||||
var classType = LuaUserData.GetType(className);
|
var classType = LuaUserData.GetType(className);
|
||||||
if (classType == null) throw new InvalidOperationException($"Invalid class name '{className}'");
|
if (classType == null) throw new InvalidOperationException($"Invalid class name '{className}'");
|
||||||
|
|
||||||
const BindingFlags BINDING_FLAGS = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
const BindingFlags BINDING_FLAGS = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||||
MethodInfo methodInfo = null;
|
const string CTOR = ".ctor";
|
||||||
if (parameterNames != null)
|
|
||||||
|
MethodBase method = null;
|
||||||
|
if (parameters != null)
|
||||||
{
|
{
|
||||||
var parameterTypes = parameterNames.Select(x => LuaUserData.GetType(x)).ToArray();
|
var parameterTypes = parameters.Select(x => LuaUserData.GetType(x)).ToArray();
|
||||||
methodInfo = classType.GetMethod(methodName, BINDING_FLAGS, null, parameterTypes, null);
|
// TODO: remove the casts once we can use C# 9 features
|
||||||
|
method = methodName == CTOR
|
||||||
|
? (MethodBase)classType.GetConstructor(BINDING_FLAGS, null, parameterTypes, null)
|
||||||
|
: (MethodBase)classType.GetMethod(methodName, BINDING_FLAGS, null, parameterTypes, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
methodInfo = classType.GetMethod(methodName, BINDING_FLAGS);
|
method = methodName == CTOR
|
||||||
|
? (MethodBase)classType.GetConstructor(BINDING_FLAGS, null, Array.Empty<Type>(), null)
|
||||||
|
: (MethodBase)classType.GetMethod(methodName, BINDING_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methodInfo == null)
|
if (method == null)
|
||||||
{
|
{
|
||||||
var parameterNamesStr = parameterNames == null ? "" : string.Join(", ", parameterNames);
|
var parameterNamesStr = parameters == null ? "" : string.Join(", ", parameters);
|
||||||
throw new InvalidOperationException($"Method '{methodName}({parameterNamesStr})' not found in class '{className}'");
|
throw new InvalidOperationException($"Method '{methodName}({parameterNamesStr})' not found in class '{className}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
return methodInfo;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DynamicParameterMapping
|
private class DynamicParameterMapping
|
||||||
@@ -863,7 +870,7 @@ namespace Barotrauma
|
|||||||
// If you need to debug this:
|
// If you need to debug this:
|
||||||
// - use https://sharplab.io ; it's a very useful for resource for writing IL by hand.
|
// - use https://sharplab.io ; it's a very useful for resource for writing IL by hand.
|
||||||
// - use il.NewMessage("") or il.WriteLine("") to see where the IL crashes at runtime.
|
// - use il.NewMessage("") or il.WriteLine("") to see where the IL crashes at runtime.
|
||||||
private MethodInfo CreateDynamicHarmonyPatch(string identifier, MethodInfo original, HookMethodType hookType)
|
private MethodInfo CreateDynamicHarmonyPatch(string identifier, MethodBase original, HookMethodType hookType)
|
||||||
{
|
{
|
||||||
var parameters = new List<DynamicParameterMapping>
|
var parameters = new List<DynamicParameterMapping>
|
||||||
{
|
{
|
||||||
@@ -871,7 +878,7 @@ namespace Barotrauma
|
|||||||
new DynamicParameterMapping("__instance", null, typeof(object)),
|
new DynamicParameterMapping("__instance", null, typeof(object)),
|
||||||
};
|
};
|
||||||
|
|
||||||
var hasReturnType = original.ReturnType != typeof(void);
|
var hasReturnType = original is MethodInfo mi && mi.ReturnType != typeof(void);
|
||||||
if (hasReturnType)
|
if (hasReturnType)
|
||||||
{
|
{
|
||||||
parameters.Add(new DynamicParameterMapping("__result", null, typeof(object).MakeByRefType()));
|
parameters.Add(new DynamicParameterMapping("__result", null, typeof(object).MakeByRefType()));
|
||||||
@@ -919,7 +926,7 @@ namespace Barotrauma
|
|||||||
// IL: var patchKey = MethodKey.Create(__originalMethod);
|
// IL: var patchKey = MethodKey.Create(__originalMethod);
|
||||||
var patchKey = il.DeclareLocal<MethodKey>("patchKey");
|
var patchKey = il.DeclareLocal<MethodKey>("patchKey");
|
||||||
il.LoadArgument(0); // load __originalMethod
|
il.LoadArgument(0); // load __originalMethod
|
||||||
il.CastClass<MethodInfo>();
|
il.CastClass<MethodBase>();
|
||||||
il.Call(typeof(MethodKey).GetMethod(nameof(MethodKey.Create)));
|
il.Call(typeof(MethodKey).GetMethod(nameof(MethodKey.Create)));
|
||||||
il.StoreLocal(patchKey);
|
il.StoreLocal(patchKey);
|
||||||
|
|
||||||
@@ -1032,10 +1039,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
// IL: var csReturnType = Type.GetTypeFromHandle(<original.ReturnType>);
|
// IL: var csReturnType = Type.GetTypeFromHandle(<original.ReturnType>);
|
||||||
var csReturnType = il.DeclareLocal<Type>("csReturnType");
|
var csReturnType = il.DeclareLocal<Type>("csReturnType");
|
||||||
il.LoadType(original.ReturnType);
|
il.LoadType(((MethodInfo)original).ReturnType);
|
||||||
il.StoreLocal(csReturnType);
|
il.StoreLocal(csReturnType);
|
||||||
|
|
||||||
// IL: var csReturnValue = luaReturnValue.ToObject(csReturnValueType);
|
// IL: var csReturnValue = luaReturnValue.ToObject(csReturnType);
|
||||||
var csReturnValue = il.DeclareLocal<object>("csReturnValue");
|
var csReturnValue = il.DeclareLocal<object>("csReturnValue");
|
||||||
il.LoadLocal(luaReturnValue);
|
il.LoadLocal(luaReturnValue);
|
||||||
il.LoadLocal(csReturnType);
|
il.LoadLocal(csReturnType);
|
||||||
@@ -1149,7 +1156,7 @@ namespace Barotrauma
|
|||||||
return type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
|
return type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string Patch(string identifier, MethodInfo method, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
private string Patch(string identifier, MethodBase method, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
||||||
{
|
{
|
||||||
if (method == null) throw new ArgumentNullException(nameof(method));
|
if (method == null) throw new ArgumentNullException(nameof(method));
|
||||||
if (patch == null) throw new ArgumentNullException(nameof(patch));
|
if (patch == null) throw new ArgumentNullException(nameof(patch));
|
||||||
@@ -1199,29 +1206,29 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public string Patch(string identifier, string className, string methodName, string[] parameterTypes, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
public string Patch(string identifier, string className, string methodName, string[] parameterTypes, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
||||||
{
|
{
|
||||||
var methodInfo = ResolveMethod(className, methodName, parameterTypes);
|
var method = ResolveMethod(className, methodName, parameterTypes);
|
||||||
return Patch(identifier, methodInfo, patch, hookType);
|
return Patch(identifier, method, patch, hookType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Patch(string identifier, string className, string methodName, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
public string Patch(string identifier, string className, string methodName, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
||||||
{
|
{
|
||||||
var methodInfo = ResolveMethod(className, methodName, null);
|
var method = ResolveMethod(className, methodName, null);
|
||||||
return Patch(identifier, methodInfo, patch, hookType);
|
return Patch(identifier, method, patch, hookType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Patch(string className, string methodName, string[] parameterTypes, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
public string Patch(string className, string methodName, string[] parameterTypes, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
||||||
{
|
{
|
||||||
var methodInfo = ResolveMethod(className, methodName, parameterTypes);
|
var method = ResolveMethod(className, methodName, parameterTypes);
|
||||||
return Patch(null, methodInfo, patch, hookType);
|
return Patch(null, method, patch, hookType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Patch(string className, string methodName, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
public string Patch(string className, string methodName, LuaCsPatchFunc patch, HookMethodType hookType = HookMethodType.Before)
|
||||||
{
|
{
|
||||||
var methodInfo = ResolveMethod(className, methodName, null);
|
var method = ResolveMethod(className, methodName, null);
|
||||||
return Patch(null, methodInfo, patch, hookType);
|
return Patch(null, method, patch, hookType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool RemovePatch(string identifier, MethodInfo method, HookMethodType hookType)
|
private bool RemovePatch(string identifier, MethodBase method, HookMethodType hookType)
|
||||||
{
|
{
|
||||||
if (identifier == null) throw new ArgumentNullException(nameof(identifier));
|
if (identifier == null) throw new ArgumentNullException(nameof(identifier));
|
||||||
identifier = NormalizeIdentifier(identifier);
|
identifier = NormalizeIdentifier(identifier);
|
||||||
@@ -1242,14 +1249,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public bool RemovePatch(string identifier, string className, string methodName, string[] parameterTypes, HookMethodType hookType)
|
public bool RemovePatch(string identifier, string className, string methodName, string[] parameterTypes, HookMethodType hookType)
|
||||||
{
|
{
|
||||||
var methodInfo = ResolveMethod(className, methodName, parameterTypes);
|
var method = ResolveMethod(className, methodName, parameterTypes);
|
||||||
return RemovePatch(identifier, methodInfo, hookType);
|
return RemovePatch(identifier, method, hookType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RemovePatch(string identifier, string className, string methodName, HookMethodType hookType)
|
public bool RemovePatch(string identifier, string className, string methodName, HookMethodType hookType)
|
||||||
{
|
{
|
||||||
var methodInfo = ResolveMethod(className, methodName, null);
|
var method = ResolveMethod(className, methodName, null);
|
||||||
return RemovePatch(identifier, methodInfo, hookType);
|
return RemovePatch(identifier, method, hookType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MoonSharp.Interpreter;
|
using MoonSharp.Interpreter;
|
||||||
using static Barotrauma.LuaCsSetup;
|
|
||||||
using LuaCsCompatPatchFunc = Barotrauma.LuaCsPatch;
|
using LuaCsCompatPatchFunc = Barotrauma.LuaCsPatch;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
@@ -122,7 +121,7 @@ namespace Barotrauma
|
|||||||
private static MethodInfo _miHookLuaCsPatchRetPostfix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchRetPostfix", BindingFlags.NonPublic | BindingFlags.Static);
|
private static MethodInfo _miHookLuaCsPatchRetPostfix = typeof(LuaCsHook).GetMethod("HookLuaCsPatchRetPostfix", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
|
||||||
// TODO: deprecate this
|
// TODO: deprecate this
|
||||||
public void HookMethod(string identifier, MethodInfo method, LuaCsCompatPatchFunc patch, HookMethodType hookType = HookMethodType.Before, ACsMod owner = null)
|
public void HookMethod(string identifier, MethodBase method, LuaCsCompatPatchFunc patch, HookMethodType hookType = HookMethodType.Before, ACsMod owner = null)
|
||||||
{
|
{
|
||||||
if (identifier == null || method == null || patch == null)
|
if (identifier == null || method == null || patch == null)
|
||||||
{
|
{
|
||||||
@@ -136,7 +135,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (hookType == HookMethodType.Before)
|
if (hookType == HookMethodType.Before)
|
||||||
{
|
{
|
||||||
if (method.ReturnType != typeof(void))
|
if (method is MethodInfo mi && mi.ReturnType != typeof(void))
|
||||||
{
|
{
|
||||||
if (patches == null || patches.Prefixes == null || patches.Prefixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPrefix) == null)
|
if (patches == null || patches.Prefixes == null || patches.Prefixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPrefix) == null)
|
||||||
{
|
{
|
||||||
@@ -168,7 +167,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (hookType == HookMethodType.After)
|
else if (hookType == HookMethodType.After)
|
||||||
{
|
{
|
||||||
if (method.ReturnType != typeof(void))
|
if (method is MethodInfo mi && mi.ReturnType != typeof(void))
|
||||||
{
|
{
|
||||||
if (patches == null || patches.Postfixes == null || patches.Postfixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPostfix) == null)
|
if (patches == null || patches.Postfixes == null || patches.Postfixes.Find(patch => patch.PatchMethod == _miHookLuaCsPatchRetPostfix) == null)
|
||||||
{
|
{
|
||||||
@@ -200,13 +199,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
protected void HookMethod(string identifier, string className, string methodName, string[] parameterNames, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before)
|
protected void HookMethod(string identifier, string className, string methodName, string[] parameterNames, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before)
|
||||||
{
|
{
|
||||||
var methodInfo = ResolveMethod(className, methodName, parameterNames);
|
var method = ResolveMethod(className, methodName, parameterNames);
|
||||||
if (methodInfo == null) return;
|
if (method == null) return;
|
||||||
if (methodInfo.GetParameters().Any(x => x.ParameterType.IsByRef))
|
if (method.GetParameters().Any(x => x.ParameterType.IsByRef))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"{nameof(HookMethod)} doesn't support ByRef parameters; use {nameof(Patch)} instead.");
|
throw new InvalidOperationException($"{nameof(HookMethod)} doesn't support ByRef parameters; use {nameof(Patch)} instead.");
|
||||||
}
|
}
|
||||||
HookMethod(identifier, methodInfo, patch, hookMethodType);
|
HookMethod(identifier, method, patch, hookMethodType);
|
||||||
}
|
}
|
||||||
protected void HookMethod(string identifier, string className, string methodName, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before) =>
|
protected void HookMethod(string identifier, string className, string methodName, LuaCsCompatPatchFunc patch, HookMethodType hookMethodType = HookMethodType.Before) =>
|
||||||
HookMethod(identifier, className, methodName, null, patch, hookMethodType);
|
HookMethod(identifier, className, methodName, null, patch, hookMethodType);
|
||||||
@@ -216,9 +215,9 @@ namespace Barotrauma
|
|||||||
HookMethod("", className, methodName, parameterNames, patch, hookMethodType);
|
HookMethod("", className, methodName, parameterNames, patch, hookMethodType);
|
||||||
|
|
||||||
|
|
||||||
public void UnhookMethod(string identifier, MethodInfo method, HookMethodType hookType = HookMethodType.Before)
|
public void UnhookMethod(string identifier, MethodBase method, HookMethodType hookType = HookMethodType.Before)
|
||||||
{
|
{
|
||||||
var funcAddr = ((long)method.MethodHandle.GetFunctionPointer());
|
var funcAddr = (long)method.MethodHandle.GetFunctionPointer();
|
||||||
|
|
||||||
Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>> methods;
|
Dictionary<long, HashSet<(string, LuaCsCompatPatchFunc, ACsMod)>> methods;
|
||||||
if (hookType == HookMethodType.Before) methods = compatHookPrefixMethods;
|
if (hookType == HookMethodType.Before) methods = compatHookPrefixMethods;
|
||||||
@@ -229,9 +228,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
protected void UnhookMethod(string identifier, string className, string methodName, string[] parameterNames, HookMethodType hookType = HookMethodType.Before)
|
protected void UnhookMethod(string identifier, string className, string methodName, string[] parameterNames, HookMethodType hookType = HookMethodType.Before)
|
||||||
{
|
{
|
||||||
var methodInfo = ResolveMethod(className, methodName, parameterNames);
|
var method = ResolveMethod(className, methodName, parameterNames);
|
||||||
if (methodInfo == null) return;
|
if (method == null) return;
|
||||||
UnhookMethod(identifier, methodInfo, hookType);
|
UnhookMethod(identifier, method, hookType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,6 +320,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public DynValue CallLuaFunction(object function, params object[] args)
|
public DynValue CallLuaFunction(object function, params object[] args)
|
||||||
{
|
{
|
||||||
|
// XXX: `lua` might be null if `LuaCsSetup.Stop()` is called while
|
||||||
|
// a patched function is still running.
|
||||||
|
if (lua == null) return null;
|
||||||
|
|
||||||
lock (lua)
|
lock (lua)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
using Barotrauma;
|
||||||
|
using MoonSharp.Interpreter;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace TestProject.LuaCs
|
||||||
|
{
|
||||||
|
internal static class HookPatchHelpers
|
||||||
|
{
|
||||||
|
public class PatchHandle : IDisposable
|
||||||
|
{
|
||||||
|
private readonly Action disposeAction;
|
||||||
|
|
||||||
|
public PatchHandle(string patchId, Action disposeAction)
|
||||||
|
{
|
||||||
|
this.disposeAction = disposeAction;
|
||||||
|
this.PatchId = patchId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PatchId { get; }
|
||||||
|
|
||||||
|
public void Dispose() => disposeAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> BuildHookPatchArgsList(
|
||||||
|
string? patchId,
|
||||||
|
string className,
|
||||||
|
string methodName,
|
||||||
|
string[]? parameters)
|
||||||
|
{
|
||||||
|
static string Stringify(object value) =>
|
||||||
|
"\"" + value.ToString()!.Replace(@"\", @"\\").Replace("\"", "\\\"") + "\"";
|
||||||
|
|
||||||
|
var args = new List<string>();
|
||||||
|
if (patchId != null) args.Add(Stringify(patchId));
|
||||||
|
args.Add(Stringify(className));
|
||||||
|
args.Add(Stringify(methodName));
|
||||||
|
if (parameters != null && parameters.Length > 0)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append("{ ");
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
sb.Append(Stringify(param));
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
|
sb.Append(" }");
|
||||||
|
args.Add(sb.ToString());
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DynValue DoHookPatch(
|
||||||
|
this LuaCsSetup luaCs,
|
||||||
|
string? patchId,
|
||||||
|
string className,
|
||||||
|
string methodName,
|
||||||
|
string[]? parameters,
|
||||||
|
string function,
|
||||||
|
LuaCsHook.HookMethodType patchType)
|
||||||
|
{
|
||||||
|
var args = BuildHookPatchArgsList(patchId, className, methodName, parameters);
|
||||||
|
args.Add(function);
|
||||||
|
args.Add(patchType switch
|
||||||
|
{
|
||||||
|
LuaCsHook.HookMethodType.Before => "Hook.HookMethodType.Before",
|
||||||
|
LuaCsHook.HookMethodType.After => "Hook.HookMethodType.After",
|
||||||
|
_ => throw new NotImplementedException(),
|
||||||
|
});
|
||||||
|
return luaCs.Lua.DoString($"return Hook.Patch({string.Join(", ", args)})");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DynValue DoHookRemovePatch(
|
||||||
|
this LuaCsSetup luaCs,
|
||||||
|
string? patchId,
|
||||||
|
string className,
|
||||||
|
string methodName,
|
||||||
|
string[]? parameters,
|
||||||
|
LuaCsHook.HookMethodType patchType)
|
||||||
|
{
|
||||||
|
var args = BuildHookPatchArgsList(patchId, className, methodName, parameters);
|
||||||
|
args.Add(patchType switch
|
||||||
|
{
|
||||||
|
LuaCsHook.HookMethodType.Before => "Hook.HookMethodType.Before",
|
||||||
|
LuaCsHook.HookMethodType.After => "Hook.HookMethodType.After",
|
||||||
|
_ => throw new NotImplementedException(),
|
||||||
|
});
|
||||||
|
return luaCs.Lua.DoString($"return Hook.RemovePatch({string.Join(", ", args)})");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PatchHandle AddPrefix<T>(this LuaCsSetup luaCs, string body, string methodName, string[]? parameters = null, string? patchId = null)
|
||||||
|
{
|
||||||
|
var className = typeof(T).FullName!;
|
||||||
|
var returnValue = luaCs.DoHookPatch(patchId, className, methodName, parameters, @$"
|
||||||
|
function(instance, ptable)
|
||||||
|
{body}
|
||||||
|
end
|
||||||
|
", LuaCsHook.HookMethodType.Before);
|
||||||
|
Assert.Equal(DataType.String, returnValue.Type);
|
||||||
|
return new(returnValue.String, () => luaCs.RemovePrefix<T>(returnValue.String, methodName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PatchHandle AddPostfix<T>(this LuaCsSetup luaCs, string body, string methodName, string[]? parameters = null, string? patchId = null)
|
||||||
|
{
|
||||||
|
var className = typeof(T).FullName!;
|
||||||
|
var returnValue = luaCs.DoHookPatch(patchId, className, methodName, parameters, @$"
|
||||||
|
function(instance, ptable)
|
||||||
|
{body}
|
||||||
|
end
|
||||||
|
", LuaCsHook.HookMethodType.After);
|
||||||
|
Assert.Equal(DataType.String, returnValue.Type);
|
||||||
|
return new(returnValue.String, () => luaCs.RemovePostfix<T>(returnValue.String, methodName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RemovePrefix<T>(this LuaCsSetup luaCs, string patchId, string methodName, string[]? parameters = null)
|
||||||
|
{
|
||||||
|
var className = typeof(T).FullName!;
|
||||||
|
var returnValue = luaCs.DoHookRemovePatch(patchId, className, methodName, parameters, LuaCsHook.HookMethodType.Before);
|
||||||
|
Assert.Equal(DataType.Boolean, returnValue.Type);
|
||||||
|
return returnValue.Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool RemovePostfix<T>(this LuaCsSetup luaCs, string patchId, string methodName, string[]? parameters = null)
|
||||||
|
{
|
||||||
|
var className = typeof(T).FullName!;
|
||||||
|
var returnValue = luaCs.DoHookRemovePatch(patchId, className, methodName, parameters, LuaCsHook.HookMethodType.After);
|
||||||
|
Assert.Equal(DataType.Boolean, returnValue.Type);
|
||||||
|
return returnValue.Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PatchTargetHandle : IDisposable
|
||||||
|
{
|
||||||
|
private readonly SemaphoreSlim @lock;
|
||||||
|
|
||||||
|
public PatchTargetHandle(SemaphoreSlim @lock)
|
||||||
|
{
|
||||||
|
this.@lock = @lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() => @lock.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<Type, SemaphoreSlim> PatchTargetLocks = new();
|
||||||
|
|
||||||
|
public static PatchTargetHandle LockPatchTarget<T>()
|
||||||
|
{
|
||||||
|
if (!PatchTargetLocks.TryGetValue(typeof(T), out var @lock))
|
||||||
|
{
|
||||||
|
PatchTargetLocks[typeof(T)] = @lock = new SemaphoreSlim(1);
|
||||||
|
}
|
||||||
|
@lock.Wait();
|
||||||
|
return new(@lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,104 +1,45 @@
|
|||||||
using Barotrauma;
|
using Barotrauma;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using MoonSharp.Interpreter;
|
using MoonSharp.Interpreter;
|
||||||
using System.Runtime.ExceptionServices;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace TestProject.LuaCs
|
namespace TestProject.LuaCs
|
||||||
{
|
{
|
||||||
public class HookPatchTests
|
[Collection("LuaCs")]
|
||||||
|
public class HookPatchTests : IClassFixture<LuaCsFixture>
|
||||||
{
|
{
|
||||||
private readonly LuaCsSetup luaCs = new();
|
private readonly LuaCsSetup luaCs;
|
||||||
|
|
||||||
public HookPatchTests(ITestOutputHelper output)
|
public HookPatchTests(LuaCsFixture luaCsFixture, ITestOutputHelper output)
|
||||||
{
|
{
|
||||||
UserData.RegisterType<TestValueType>();
|
// XXX: we can't have multiple instances of LuaCs patching the
|
||||||
UserData.RegisterType<IBogusInterface>();
|
// same methods, otherwise we get script ownership exceptions.
|
||||||
UserData.RegisterType<InterfaceImplementingType>();
|
luaCs = luaCsFixture.LuaCs;
|
||||||
UserData.RegisterType<PatchTarget1>();
|
|
||||||
UserData.RegisterType<PatchTarget2>();
|
|
||||||
UserData.RegisterType<PatchTarget3>();
|
|
||||||
UserData.RegisterType<PatchTarget4>();
|
|
||||||
UserData.RegisterType<PatchTarget5>();
|
|
||||||
UserData.RegisterType<PatchTarget6>();
|
|
||||||
|
|
||||||
luaCs.MessageLogger = (prefix, o) =>
|
luaCs.MessageLogger = (prefix, o) =>
|
||||||
{
|
{
|
||||||
o ??= "null";
|
o ??= "null";
|
||||||
output.WriteLine(prefix + o);
|
output?.WriteLine(prefix + o);
|
||||||
};
|
|
||||||
luaCs.ExceptionHandler = (ex, _) =>
|
|
||||||
{
|
|
||||||
// Pretend we never caught the exception in the first place
|
|
||||||
// (this allows us to preserve the stack trace)
|
|
||||||
var di = ExceptionDispatchInfo.Capture(ex);
|
|
||||||
di.Throw();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UserData.RegisterType<TestValueType>();
|
||||||
|
UserData.RegisterType<IBogusInterface>();
|
||||||
|
UserData.RegisterType<InterfaceImplementingType>();
|
||||||
|
UserData.RegisterType<PatchTargetSimple>();
|
||||||
|
UserData.RegisterType<PatchTargetReturnsObject>();
|
||||||
|
UserData.RegisterType<PatchTargetReturnsInterface>();
|
||||||
|
UserData.RegisterType<PatchTargetModifyParams>();
|
||||||
|
UserData.RegisterType<PatchTargetVector2>();
|
||||||
|
UserData.RegisterType<PatchTargetConstructor>();
|
||||||
|
UserData.RegisterType<PatchTargetNumbers>();
|
||||||
|
|
||||||
luaCs.Initialize();
|
luaCs.Initialize();
|
||||||
luaCs.Lua.Globals["TestValueType"] = UserData.CreateStatic<TestValueType>();
|
luaCs.Lua.Globals["TestValueType"] = UserData.CreateStatic<TestValueType>();
|
||||||
luaCs.Lua.Globals["InterfaceImplementingType"] = UserData.CreateStatic<InterfaceImplementingType>();
|
luaCs.Lua.Globals["InterfaceImplementingType"] = UserData.CreateStatic<InterfaceImplementingType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private DynValue AddPrefix<T>(string body, string testMethod = "Run", string? patchId = null)
|
private class PatchTargetSimple
|
||||||
{
|
|
||||||
var className = typeof(T).FullName;
|
|
||||||
if (patchId != null)
|
|
||||||
{
|
|
||||||
return luaCs.Lua.DoString(@$"
|
|
||||||
return Hook.Patch('{patchId}', '{className}', '{testMethod}', function(instance, ptable)
|
|
||||||
{body}
|
|
||||||
end, Hook.HookMethodType.Before)
|
|
||||||
");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return luaCs.Lua.DoString(@$"
|
|
||||||
return Hook.Patch('{className}', '{testMethod}', function(instance, ptable)
|
|
||||||
{body}
|
|
||||||
end, Hook.HookMethodType.Before)
|
|
||||||
");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DynValue AddPostfix<T>(string body, string testMethod = "Run", string? patchId = null)
|
|
||||||
{
|
|
||||||
var className = typeof(T).FullName;
|
|
||||||
if (patchId != null)
|
|
||||||
{
|
|
||||||
return luaCs.Lua.DoString(@$"
|
|
||||||
return Hook.Patch('{patchId}', '{className}', '{testMethod}', function(instance, ptable)
|
|
||||||
{body}
|
|
||||||
end, Hook.HookMethodType.After)
|
|
||||||
");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return luaCs.Lua.DoString(@$"
|
|
||||||
return Hook.Patch('{className}', '{testMethod}', function(instance, ptable)
|
|
||||||
{body}
|
|
||||||
end, Hook.HookMethodType.After)
|
|
||||||
");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DynValue RemovePrefix<T>(string patchName, string testMethod = "Run")
|
|
||||||
{
|
|
||||||
var className = typeof(T).FullName;
|
|
||||||
return luaCs.Lua.DoString($@"
|
|
||||||
return Hook.RemovePatch('{patchName}', '{className}', '{testMethod}', Hook.HookMethodType.Before)
|
|
||||||
");
|
|
||||||
}
|
|
||||||
|
|
||||||
private DynValue RemovePostfix<T>(string patchName, string testMethod = "Run")
|
|
||||||
{
|
|
||||||
var className = typeof(T).FullName;
|
|
||||||
return luaCs.Lua.DoString($@"
|
|
||||||
return Hook.RemovePatch('{patchName}', '{className}', '{testMethod}', Hook.HookMethodType.After)
|
|
||||||
");
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PatchTarget1
|
|
||||||
{
|
{
|
||||||
public bool ran;
|
public bool ran;
|
||||||
|
|
||||||
@@ -111,8 +52,11 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestFullMethodReplacement()
|
public void TestFullMethodReplacement()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget1();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetSimple>();
|
||||||
AddPrefix<PatchTarget1>("ptable.PreventExecution = true");
|
var target = new PatchTargetSimple();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetSimple>(@"
|
||||||
|
ptable.PreventExecution = true
|
||||||
|
", nameof(PatchTargetSimple.Run));
|
||||||
target.Run();
|
target.Run();
|
||||||
Assert.False(target.ran);
|
Assert.False(target.ran);
|
||||||
}
|
}
|
||||||
@@ -120,11 +64,12 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestOverrideExistingPatch()
|
public void TestOverrideExistingPatch()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget1();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetSimple>();
|
||||||
AddPrefix<PatchTarget1>(@"
|
var target = new PatchTargetSimple();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetSimple>(@"
|
||||||
ptable.PreventExecution = true
|
ptable.PreventExecution = true
|
||||||
originalPatchRan = true
|
originalPatchRan = true
|
||||||
", patchId: "test");
|
", nameof(PatchTargetSimple.Run), patchId: "test");
|
||||||
target.Run();
|
target.Run();
|
||||||
Assert.False(target.ran);
|
Assert.False(target.ran);
|
||||||
Assert.True(luaCs.Lua.Globals["originalPatchRan"] as bool?);
|
Assert.True(luaCs.Lua.Globals["originalPatchRan"] as bool?);
|
||||||
@@ -134,7 +79,9 @@ namespace TestProject.LuaCs
|
|||||||
luaCs.Lua.Globals["originalPatchRan"] = false;
|
luaCs.Lua.Globals["originalPatchRan"] = false;
|
||||||
|
|
||||||
// Replace the existing prefix, but don't prevent execution this time
|
// Replace the existing prefix, but don't prevent execution this time
|
||||||
AddPrefix<PatchTarget1>("replacementPatchRan = true", patchId: "test");
|
luaCs.AddPrefix<PatchTargetSimple>(@"
|
||||||
|
replacementPatchRan = true
|
||||||
|
", nameof(PatchTargetSimple.Run), patchId: "test");
|
||||||
target.Run();
|
target.Run();
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
|
|
||||||
@@ -148,19 +95,20 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestRemovePrefix()
|
public void TestRemovePrefix()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget1();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetSimple>();
|
||||||
var patchId = AddPrefix<PatchTarget1>(@"
|
var target = new PatchTargetSimple();
|
||||||
|
using (var patchHandle = luaCs.AddPrefix<PatchTargetSimple>(@"
|
||||||
ptable.PreventExecution = true
|
ptable.PreventExecution = true
|
||||||
patchRan = true
|
patchRan = true
|
||||||
");
|
", nameof(PatchTargetSimple.Run)))
|
||||||
target.Run();
|
{
|
||||||
Assert.False(target.ran);
|
target.Run();
|
||||||
Assert.True(luaCs.Lua.Globals["patchRan"] as bool?);
|
Assert.False(target.ran);
|
||||||
|
Assert.True(luaCs.Lua.Globals["patchRan"] as bool?);
|
||||||
|
|
||||||
luaCs.Lua.Globals["patchRan"] = false;
|
luaCs.Lua.Globals["patchRan"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
Assert.Equal(DataType.String, patchId.Type);
|
|
||||||
RemovePrefix<PatchTarget1>(patchId.String);
|
|
||||||
target.Run();
|
target.Run();
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.False(luaCs.Lua.Globals["patchRan"] as bool?);
|
Assert.False(luaCs.Lua.Globals["patchRan"] as bool?);
|
||||||
@@ -169,19 +117,20 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestRemovePostfix()
|
public void TestRemovePostfix()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget1();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetSimple>();
|
||||||
var patchId = AddPostfix<PatchTarget1>(@"
|
var target = new PatchTargetSimple();
|
||||||
|
using (var patchHandle = luaCs.AddPostfix<PatchTargetSimple>(@"
|
||||||
patchRan = true
|
patchRan = true
|
||||||
");
|
", nameof(PatchTargetSimple.Run)))
|
||||||
target.Run();
|
{
|
||||||
Assert.True(target.ran);
|
target.Run();
|
||||||
Assert.True(luaCs.Lua.Globals["patchRan"] as bool?);
|
Assert.True(target.ran);
|
||||||
|
Assert.True(luaCs.Lua.Globals["patchRan"] as bool?);
|
||||||
|
|
||||||
target.ran = false;
|
target.ran = false;
|
||||||
luaCs.Lua.Globals["patchRan"] = false;
|
luaCs.Lua.Globals["patchRan"] = false;
|
||||||
|
}
|
||||||
|
|
||||||
Assert.Equal(DataType.String, patchId.Type);
|
|
||||||
RemovePostfix<PatchTarget1>(patchId.String);
|
|
||||||
target.Run();
|
target.Run();
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.False(luaCs.Lua.Globals["patchRan"] as bool?);
|
Assert.False(luaCs.Lua.Globals["patchRan"] as bool?);
|
||||||
@@ -197,7 +146,7 @@ namespace TestProject.LuaCs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PatchTarget2
|
private class PatchTargetReturnsObject
|
||||||
{
|
{
|
||||||
public bool ran;
|
public bool ran;
|
||||||
|
|
||||||
@@ -213,7 +162,7 @@ namespace TestProject.LuaCs
|
|||||||
int GetFoo();
|
int GetFoo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InterfaceImplementingType : IBogusInterface
|
private class InterfaceImplementingType : IBogusInterface
|
||||||
{
|
{
|
||||||
private readonly int foo;
|
private readonly int foo;
|
||||||
|
|
||||||
@@ -228,11 +177,12 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestReturnBoxed()
|
public void TestReturnBoxed()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget2();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetReturnsObject>();
|
||||||
AddPrefix<PatchTarget2>(@"
|
var target = new PatchTargetReturnsObject();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetReturnsObject>(@"
|
||||||
ptable.PreventExecution = true
|
ptable.PreventExecution = true
|
||||||
return 123
|
return 123
|
||||||
");
|
", nameof(PatchTargetReturnsObject.Run));
|
||||||
var returnValue = target.Run();
|
var returnValue = target.Run();
|
||||||
Assert.False(target.ran);
|
Assert.False(target.ran);
|
||||||
Assert.Equal(123, (int)(double)returnValue);
|
Assert.Equal(123, (int)(double)returnValue);
|
||||||
@@ -241,9 +191,12 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestReturnVoid()
|
public void TestReturnVoid()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget2();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetReturnsObject>();
|
||||||
|
var target = new PatchTargetReturnsObject();
|
||||||
// This should have no effect
|
// This should have no effect
|
||||||
AddPrefix<PatchTarget2>("return");
|
using var patchHandle = luaCs.AddPrefix<PatchTargetReturnsObject>(@"
|
||||||
|
return
|
||||||
|
", nameof(PatchTargetReturnsObject.Run));
|
||||||
var returnValue = target.Run();
|
var returnValue = target.Run();
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(5, returnValue);
|
Assert.Equal(5, returnValue);
|
||||||
@@ -252,9 +205,12 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestReturnNil()
|
public void TestReturnNil()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget2();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetReturnsObject>();
|
||||||
|
var target = new PatchTargetReturnsObject();
|
||||||
// This should modify the return value to "null"
|
// This should modify the return value to "null"
|
||||||
AddPostfix<PatchTarget2>("return nil");
|
using var patchHandle = luaCs.AddPostfix<PatchTargetReturnsObject>(@"
|
||||||
|
return nil
|
||||||
|
", nameof(PatchTargetReturnsObject.Run));
|
||||||
var returnValue = target.Run();
|
var returnValue = target.Run();
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Null(returnValue);
|
Assert.Null(returnValue);
|
||||||
@@ -263,17 +219,18 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestReturnValueType()
|
public void TestReturnValueType()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget2();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetReturnsObject>();
|
||||||
AddPostfix<PatchTarget2>(@"
|
var target = new PatchTargetReturnsObject();
|
||||||
|
using var patchHandle = luaCs.AddPostfix<PatchTargetReturnsObject>(@"
|
||||||
return TestValueType.__new(100)
|
return TestValueType.__new(100)
|
||||||
");
|
", nameof(PatchTargetSimple.Run));
|
||||||
var returnValue = target.Run();
|
var returnValue = target.Run();
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.IsType<TestValueType>(returnValue);
|
Assert.IsType<TestValueType>(returnValue);
|
||||||
Assert.Equal(100, ((TestValueType)returnValue).foo);
|
Assert.Equal(100, ((TestValueType)returnValue).foo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PatchTarget3
|
private class PatchTargetReturnsInterface
|
||||||
{
|
{
|
||||||
public bool ran;
|
public bool ran;
|
||||||
|
|
||||||
@@ -287,16 +244,17 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestReturnInterfaceImplementingType()
|
public void TestReturnInterfaceImplementingType()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget3();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetReturnsInterface>();
|
||||||
AddPostfix<PatchTarget3>(@"
|
var target = new PatchTargetReturnsInterface();
|
||||||
return InterfaceImplementingType.__new(100);
|
using var patchHandle = luaCs.AddPostfix<PatchTargetReturnsInterface>(@"
|
||||||
");
|
return InterfaceImplementingType.__new(100)
|
||||||
|
", nameof(PatchTargetReturnsInterface.Run));
|
||||||
var returnValue = target.Run()!;
|
var returnValue = target.Run()!;
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(100, returnValue.GetFoo());
|
Assert.Equal(100, returnValue.GetFoo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PatchTarget4
|
private class PatchTargetModifyParams
|
||||||
{
|
{
|
||||||
public bool ran;
|
public bool ran;
|
||||||
|
|
||||||
@@ -310,19 +268,20 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestModifyParameters()
|
public void TestModifyParameters()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget4();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetModifyParams>();
|
||||||
AddPrefix<PatchTarget4>(@"
|
var target = new PatchTargetModifyParams();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetModifyParams>(@"
|
||||||
ptable['a'] = Int32(100)
|
ptable['a'] = Int32(100)
|
||||||
ptable['b'] = 'abc'
|
ptable['b'] = 'abc'
|
||||||
ptable['refByte'] = Byte(4)
|
ptable['refByte'] = Byte(4)
|
||||||
");
|
", nameof(PatchTargetModifyParams.Run));
|
||||||
byte refByte = 123;
|
byte refByte = 123;
|
||||||
target.Run(5, out var outString, ref refByte, "foo");
|
target.Run(5, out var outString, ref refByte, "foo");
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal("100abc4", outString);
|
Assert.Equal("100abc4", outString);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PatchTarget5
|
private class PatchTargetVector2
|
||||||
{
|
{
|
||||||
public bool ran;
|
public bool ran;
|
||||||
|
|
||||||
@@ -336,15 +295,91 @@ namespace TestProject.LuaCs
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void TestParameterValueType()
|
public void TestParameterValueType()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget5();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetVector2>();
|
||||||
AddPrefix<PatchTarget5>("patchRan = true");
|
var target = new PatchTargetVector2();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetVector2>(@"
|
||||||
|
patchRan = true
|
||||||
|
", nameof(PatchTargetVector2.Run));
|
||||||
var returnValue = target.Run(new Vector2(1, 2));
|
var returnValue = target.Run(new Vector2(1, 2));
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.True(luaCs.Lua.Globals["patchRan"] as bool?);
|
Assert.True(luaCs.Lua.Globals["patchRan"] as bool?);
|
||||||
Assert.Equal("{X:1 Y:2}", returnValue);
|
Assert.Equal("{X:1 Y:2}", returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PatchTarget6
|
private class PatchTargetConstructor
|
||||||
|
{
|
||||||
|
public enum CtorType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Patched,
|
||||||
|
Default,
|
||||||
|
Int,
|
||||||
|
StringString,
|
||||||
|
}
|
||||||
|
|
||||||
|
public CtorType Ctor { get; set; }
|
||||||
|
|
||||||
|
public bool PrefixRan { get; set; }
|
||||||
|
|
||||||
|
public PatchTargetConstructor()
|
||||||
|
{
|
||||||
|
Ctor = CtorType.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PatchTargetConstructor(int a = default)
|
||||||
|
{
|
||||||
|
Ctor = CtorType.Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PatchTargetConstructor(string a, string b)
|
||||||
|
{
|
||||||
|
Ctor = CtorType.StringString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestPatchConstructor()
|
||||||
|
{
|
||||||
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetConstructor>();
|
||||||
|
|
||||||
|
{
|
||||||
|
using var postfixHandle = luaCs.AddPostfix<PatchTargetConstructor>(@$"
|
||||||
|
instance.Ctor = {(int)PatchTargetConstructor.CtorType.Patched}
|
||||||
|
", ".ctor");
|
||||||
|
using var prefixHandle = luaCs.AddPrefix<PatchTargetConstructor>(@$"
|
||||||
|
instance.PrefixRan = true
|
||||||
|
", ".ctor");
|
||||||
|
var target = new PatchTargetConstructor();
|
||||||
|
Assert.Equal(PatchTargetConstructor.CtorType.Patched, target.Ctor);
|
||||||
|
Assert.True(target.PrefixRan);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
using var postfixHandle = luaCs.AddPostfix<PatchTargetConstructor>(@$"
|
||||||
|
instance.Ctor = {(int)PatchTargetConstructor.CtorType.Patched}
|
||||||
|
", ".ctor", new[] { typeof(int).FullName! });
|
||||||
|
using var prefixHandle = luaCs.AddPrefix<PatchTargetConstructor>(@$"
|
||||||
|
instance.PrefixRan = true
|
||||||
|
", ".ctor", new[] { typeof(int).FullName! });
|
||||||
|
var target = new PatchTargetConstructor(1);
|
||||||
|
Assert.Equal(PatchTargetConstructor.CtorType.Patched, target.Ctor);
|
||||||
|
Assert.True(target.PrefixRan);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
using var postfixHandle = luaCs.AddPostfix<PatchTargetConstructor>(@$"
|
||||||
|
instance.Ctor = {(int)PatchTargetConstructor.CtorType.Patched}
|
||||||
|
", ".ctor", new[] { typeof(string).FullName!, typeof(string).FullName! });
|
||||||
|
using var prefixHandle = luaCs.AddPrefix<PatchTargetConstructor>(@$"
|
||||||
|
instance.PrefixRan = true
|
||||||
|
", ".ctor", new[] { typeof(string).FullName!, typeof(string).FullName! });
|
||||||
|
var target = new PatchTargetConstructor("", "");
|
||||||
|
Assert.Equal(PatchTargetConstructor.CtorType.Patched, target.Ctor);
|
||||||
|
Assert.True(target.PrefixRan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PatchTargetNumbers
|
||||||
{
|
{
|
||||||
public bool ran;
|
public bool ran;
|
||||||
|
|
||||||
@@ -410,120 +445,130 @@ namespace TestProject.LuaCs
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperSByte()
|
public void TestCastSByte()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = SByte(-6)
|
ptable['v'] = SByte(-6)
|
||||||
", testMethod: nameof(PatchTarget6.RunSByte));
|
", nameof(PatchTargetNumbers.RunSByte));
|
||||||
var returnValue = target.RunSByte(-5);
|
var returnValue = target.RunSByte(-5);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(-6, returnValue);
|
Assert.Equal(-6, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperByte()
|
public void TestCastByte()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = Byte(6)
|
ptable['v'] = Byte(6)
|
||||||
", testMethod: nameof(PatchTarget6.RunByte));
|
", nameof(PatchTargetNumbers.RunByte));
|
||||||
var returnValue = target.RunByte(5);
|
var returnValue = target.RunByte(5);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(6, returnValue);
|
Assert.Equal(6, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperInt16()
|
public void TestCastInt16()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = Int16(-25000)
|
ptable['v'] = Int16(-25000)
|
||||||
", testMethod: nameof(PatchTarget6.RunInt16));
|
", nameof(PatchTargetNumbers.RunInt16));
|
||||||
var returnValue = target.RunInt16(30000);
|
var returnValue = target.RunInt16(30000);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(-25000, returnValue);
|
Assert.Equal(-25000, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperUInt16()
|
public void TestCastUInt16()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = UInt16(60000)
|
ptable['v'] = UInt16(60000)
|
||||||
", testMethod: nameof(PatchTarget6.RunUInt16));
|
", nameof(PatchTargetNumbers.RunUInt16));
|
||||||
var returnValue = target.RunUInt16(50000);
|
var returnValue = target.RunUInt16(50000);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(60000, returnValue);
|
Assert.Equal(60000, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperInt32()
|
public void TestCastInt32()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = Int32('7FFFFF00', 16)
|
ptable['v'] = Int32('7FFFFF00', 16)
|
||||||
", testMethod: nameof(PatchTarget6.RunInt32));
|
", nameof(PatchTargetNumbers.RunInt32));
|
||||||
var returnValue = target.RunInt32(900000);
|
var returnValue = target.RunInt32(900000);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(0x7FFFFF00, returnValue);
|
Assert.Equal(0x7FFFFF00, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperUInt32()
|
public void TestCastUInt32()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = UInt32('AFFFFFFF', 16)
|
ptable['v'] = UInt32('AFFFFFFF', 16)
|
||||||
", testMethod: nameof(PatchTarget6.RunUInt32));
|
", nameof(PatchTargetNumbers.RunUInt32));
|
||||||
var returnValue = target.RunUInt32(300500);
|
var returnValue = target.RunUInt32(300500);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(0xAFFFFFFF, returnValue);
|
Assert.Equal(0xAFFFFFFF, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperInt64()
|
public void TestCastInt64()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = Int64('7555555555555555', 16)
|
ptable['v'] = Int64('7555555555555555', 16)
|
||||||
", testMethod: nameof(PatchTarget6.RunInt64));
|
", nameof(PatchTargetNumbers.RunInt64));
|
||||||
var returnValue = target.RunInt64(0x7FFFFFFF00000000);
|
var returnValue = target.RunInt64(0x7FFFFFFF00000000);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(0x7555555555555555, returnValue);
|
Assert.Equal(0x7555555555555555, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperUInt64()
|
public void TestCastUInt64()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = UInt64('F555555555555555', 16)
|
ptable['v'] = UInt64('F555555555555555', 16)
|
||||||
", testMethod: nameof(PatchTarget6.RunUInt64));
|
", nameof(PatchTargetNumbers.RunUInt64));
|
||||||
var returnValue = target.RunUInt64(0xFFFFFFFF00000000);
|
var returnValue = target.RunUInt64(0xFFFFFFFF00000000);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(0xF555555555555555, returnValue);
|
Assert.Equal(0xF555555555555555, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperSingle()
|
public void TestCastSingle()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = Single(123.456)
|
ptable['v'] = Single(123.456)
|
||||||
", testMethod: nameof(PatchTarget6.RunSingle));
|
", nameof(PatchTargetNumbers.RunSingle));
|
||||||
var returnValue = target.RunSingle(111.111f);
|
var returnValue = target.RunSingle(111.111f);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(123.456f, returnValue);
|
Assert.Equal(123.456f, returnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestCastPrimitiveWrapperDouble()
|
public void TestCastDouble()
|
||||||
{
|
{
|
||||||
var target = new PatchTarget6();
|
using var patchTargetHandle = HookPatchHelpers.LockPatchTarget<PatchTargetNumbers>();
|
||||||
AddPrefix<PatchTarget6>(@"
|
var target = new PatchTargetNumbers();
|
||||||
|
using var patchHandle = luaCs.AddPrefix<PatchTargetNumbers>(@"
|
||||||
ptable['v'] = Double(123.456)
|
ptable['v'] = Double(123.456)
|
||||||
", testMethod: nameof(PatchTarget6.RunDouble));
|
", nameof(PatchTargetNumbers.RunDouble));
|
||||||
var returnValue = target.RunDouble(111.111d);
|
var returnValue = target.RunDouble(111.111d);
|
||||||
Assert.True(target.ran);
|
Assert.True(target.ran);
|
||||||
Assert.Equal(123.456d, returnValue);
|
Assert.Equal(123.456d, returnValue);
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Barotrauma;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
|
|
||||||
|
namespace TestProject.LuaCs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shared LuaCsSetup instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Don't use this unless you need to test logic that makes use of
|
||||||
|
/// a shared state (static variables).
|
||||||
|
/// </remarks>
|
||||||
|
public class LuaCsFixture : IDisposable
|
||||||
|
{
|
||||||
|
public LuaCsFixture()
|
||||||
|
{
|
||||||
|
LuaCs.ExceptionHandler = (ex, _) =>
|
||||||
|
{
|
||||||
|
// Pretend we never caught the exception in the first place
|
||||||
|
// (this allows us to preserve the stack trace)
|
||||||
|
var di = ExceptionDispatchInfo.Capture(ex);
|
||||||
|
di.Throw();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal LuaCsSetup LuaCs { get; } = new();
|
||||||
|
|
||||||
|
void IDisposable.Dispose() => LuaCs.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
Submodule Libraries/moonsharp updated: b9fc22da9e...9366bba2f2
+1
-1
@@ -42,7 +42,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoGame.Framework.Linux.Ne
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinuxTest", "Barotrauma\BarotraumaTest\LinuxTest.csproj", "{F1B80D94-8BD6-48CE-8D17-BB2A5C98BCA3}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinuxTest", "Barotrauma\BarotraumaTest\LinuxTest.csproj", "{F1B80D94-8BD6-48CE-8D17-BB2A5C98BCA3}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoonSharp.Interpreter.netcore", "Libraries\moonsharp\src\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.netcore\MoonSharp.Interpreter.netcore.csproj", "{382DFA63-78FC-41AC-BA85-630960A56E5C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoonSharp.Interpreter", "Libraries\moonsharp\MoonSharp.Interpreter\MoonSharp.Interpreter.csproj", "{382DFA63-78FC-41AC-BA85-630960A56E5C}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facepunch.Steamworks.Posix"
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MacTest", "Barotrauma\BarotraumaTest\MacTest.csproj", "{20BC9336-B439-4BF1-8B65-D587DBF421D1}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MacTest", "Barotrauma\BarotraumaTest\MacTest.csproj", "{20BC9336-B439-4BF1-8B65-D587DBF421D1}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoonSharp.Interpreter.netcore", "Libraries\moonsharp\src\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.netcore\MoonSharp.Interpreter.netcore.csproj", "{40BDE83D-61D5-481C-A53E-E0F5B23881E2}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoonSharp.Interpreter", "Libraries\moonsharp\MoonSharp.Interpreter\MoonSharp.Interpreter.csproj", "{40BDE83D-61D5-481C-A53E-E0F5B23881E2}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpFont.NetStandard", "Li
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsTest", "Barotrauma\BarotraumaTest\WindowsTest.csproj", "{C7212AE2-A925-4225-A639-AE0653EF65B0}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsTest", "Barotrauma\BarotraumaTest\WindowsTest.csproj", "{C7212AE2-A925-4225-A639-AE0653EF65B0}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoonSharp.Interpreter.netcore", "Libraries\moonsharp\src\MoonSharp.Interpreter\_Projects\MoonSharp.Interpreter.netcore\MoonSharp.Interpreter.netcore.csproj", "{2EEF2610-64A3-4E5D-95ED-0E181C1A34ED}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MoonSharp.Interpreter", "Libraries\moonsharp\MoonSharp.Interpreter\MoonSharp.Interpreter.csproj", "{2EEF2610-64A3-4E5D-95ED-0E181C1A34ED}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||||
|
|||||||
Reference in New Issue
Block a user