Changed plugins so they get Init-d before the sandbox game is created.
Changed NLog to dump Keen errors to Torch log too Added some debug info
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
</targets>
|
</targets>
|
||||||
|
|
||||||
<rules>
|
<rules>
|
||||||
|
<logger name="Keen" minlevel="Warn" writeTo="main"/>
|
||||||
<logger name="Keen" minlevel="Info" writeTo="console"/>
|
<logger name="Keen" minlevel="Info" writeTo="console"/>
|
||||||
<logger name="Keen" minlevel="Debug" writeTo="keen" final="true" />
|
<logger name="Keen" minlevel="Debug" writeTo="keen" final="true" />
|
||||||
<logger name="Keen" writeTo="null" final="true" />
|
<logger name="Keen" writeTo="null" final="true" />
|
||||||
|
@@ -99,14 +99,6 @@ namespace Torch.Managers.PatchManager
|
|||||||
public const string RESULT_PARAMETER = "__result";
|
public const string RESULT_PARAMETER = "__result";
|
||||||
public const string PREFIX_SKIPPED_PARAMETER = "__prefixSkipped";
|
public const string PREFIX_SKIPPED_PARAMETER = "__prefixSkipped";
|
||||||
|
|
||||||
#pragma warning disable 649
|
|
||||||
[ReflectedStaticMethod(Type = typeof(RuntimeHelpers), Name = "_CompileMethod", OverrideTypeNames = new[] { "System.IRuntimeMethodInfo" })]
|
|
||||||
private static Action<object> _compileDynamicMethod;
|
|
||||||
[ReflectedMethod(Name = "GetMethodInfo")]
|
|
||||||
private static Func<RuntimeMethodHandle, object> _getMethodInfo;
|
|
||||||
[ReflectedMethod(Name = "GetMethodDescriptor")]
|
|
||||||
private static Func<DynamicMethod, RuntimeMethodHandle> _getMethodHandle;
|
|
||||||
#pragma warning restore 649
|
|
||||||
|
|
||||||
public DynamicMethod ComposePatchedMethod()
|
public DynamicMethod ComposePatchedMethod()
|
||||||
{
|
{
|
||||||
@@ -124,10 +116,7 @@ namespace Torch.Managers.PatchManager
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Force it to compile
|
PatchUtilities.Compile(method);
|
||||||
RuntimeMethodHandle handle = _getMethodHandle.Invoke(method);
|
|
||||||
object runtimeMethodInfo = _getMethodInfo.Invoke(handle);
|
|
||||||
_compileDynamicMethod.Invoke(runtimeMethodInfo);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@@ -426,16 +426,16 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
{
|
{
|
||||||
case OperandType.InlineTok:
|
case OperandType.InlineTok:
|
||||||
Debug.Assert(Value is MethodBase || Value is Type || Value is FieldInfo,
|
Debug.Assert(Value is MethodBase || Value is Type || Value is FieldInfo,
|
||||||
$"Value {Value?.GetType()} doesn't match operand type");
|
$"Value {Value?.GetType()} doesn't match operand type for {Instruction.OpCode}");
|
||||||
break;
|
break;
|
||||||
case OperandType.InlineType:
|
case OperandType.InlineType:
|
||||||
Debug.Assert(Value is Type, $"Value {Value?.GetType()} doesn't match operand type");
|
Debug.Assert(Value is Type, $"Value {Value?.GetType()} doesn't match operand type for {Instruction.OpCode}");
|
||||||
break;
|
break;
|
||||||
case OperandType.InlineMethod:
|
case OperandType.InlineMethod:
|
||||||
Debug.Assert(Value is MethodBase, $"Value {Value?.GetType()} doesn't match operand type");
|
Debug.Assert(Value is MethodBase, $"Value {Value?.GetType()} doesn't match operand type for {Instruction.OpCode}");
|
||||||
break;
|
break;
|
||||||
case OperandType.InlineField:
|
case OperandType.InlineField:
|
||||||
Debug.Assert(Value is FieldInfo, $"Value {Value?.GetType()} doesn't match operand type");
|
Debug.Assert(Value is FieldInfo, $"Value {Value?.GetType()} doesn't match operand type for {Instruction.OpCode}");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidBranchException(
|
throw new InvalidBranchException(
|
||||||
|
@@ -3,10 +3,13 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NLog;
|
||||||
using Torch.Managers.PatchManager.MSIL;
|
using Torch.Managers.PatchManager.MSIL;
|
||||||
using Torch.Managers.PatchManager.Transpile;
|
using Torch.Managers.PatchManager.Transpile;
|
||||||
|
using Torch.Utils;
|
||||||
|
|
||||||
namespace Torch.Managers.PatchManager
|
namespace Torch.Managers.PatchManager
|
||||||
{
|
{
|
||||||
@@ -36,5 +39,35 @@ namespace Torch.Managers.PatchManager
|
|||||||
{
|
{
|
||||||
MethodTranspiler.EmitMethod(insn.ToList(), generator);
|
MethodTranspiler.EmitMethod(insn.ToList(), generator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Analyzes the integrity of a set of instructions.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level">default logging level</param>
|
||||||
|
/// <param name="instructions">instructions</param>
|
||||||
|
public static void IntegrityAnalysis(LogLevel level, IReadOnlyList<MsilInstruction> instructions)
|
||||||
|
{
|
||||||
|
MethodTranspiler.IntegrityAnalysis(level, instructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable 649
|
||||||
|
[ReflectedStaticMethod(Type = typeof(RuntimeHelpers), Name = "_CompileMethod", OverrideTypeNames = new[] { "System.IRuntimeMethodInfo" })]
|
||||||
|
private static Action<object> _compileDynamicMethod;
|
||||||
|
[ReflectedMethod(Name = "GetMethodInfo")]
|
||||||
|
private static Func<RuntimeMethodHandle, object> _getMethodInfo;
|
||||||
|
[ReflectedMethod(Name = "GetMethodDescriptor")]
|
||||||
|
private static Func<DynamicMethod, RuntimeMethodHandle> _getMethodHandle;
|
||||||
|
#pragma warning restore 649
|
||||||
|
/// <summary>
|
||||||
|
/// Forces the given dynamic method to be compiled
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="method"></param>
|
||||||
|
public static void Compile(DynamicMethod method)
|
||||||
|
{
|
||||||
|
// Force it to compile
|
||||||
|
RuntimeMethodHandle handle = _getMethodHandle.Invoke(method);
|
||||||
|
object runtimeMethodInfo = _getMethodInfo.Invoke(handle);
|
||||||
|
_compileDynamicMethod.Invoke(runtimeMethodInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -353,10 +353,10 @@ namespace Torch
|
|||||||
Log.Info($"Executing assembly: {Assembly.GetEntryAssembly().FullName}");
|
Log.Info($"Executing assembly: {Assembly.GetEntryAssembly().FullName}");
|
||||||
Log.Info($"Executing directory: {AppDomain.CurrentDomain.BaseDirectory}");
|
Log.Info($"Executing directory: {AppDomain.CurrentDomain.BaseDirectory}");
|
||||||
|
|
||||||
|
Managers.GetManager<PluginManager>().LoadPlugins();
|
||||||
Game = new VRageGame(this, TweakGameSettings, SteamAppName, SteamAppId, Config.InstancePath, RunArgs);
|
Game = new VRageGame(this, TweakGameSettings, SteamAppName, SteamAppId, Config.InstancePath, RunArgs);
|
||||||
if (!Game.WaitFor(VRageGame.GameState.Stopped, TimeSpan.FromMinutes(5)))
|
if (!Game.WaitFor(VRageGame.GameState.Stopped, TimeSpan.FromMinutes(5)))
|
||||||
Log.Warn("Failed to wait for game to be initialized");
|
Log.Warn("Failed to wait for game to be initialized");
|
||||||
Managers.GetManager<PluginManager>().LoadPlugins();
|
|
||||||
Managers.Attach();
|
Managers.Attach();
|
||||||
_init = true;
|
_init = true;
|
||||||
|
|
||||||
|
@@ -5,12 +5,15 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox.Engine.Multiplayer;
|
using Sandbox.Engine.Multiplayer;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
|
using Torch.Managers.PatchManager;
|
||||||
using Torch.Utils.Reflected;
|
using Torch.Utils.Reflected;
|
||||||
|
using PropertyAttributes = System.Reflection.PropertyAttributes;
|
||||||
|
|
||||||
namespace Torch.Utils
|
namespace Torch.Utils
|
||||||
{
|
{
|
||||||
@@ -53,14 +56,16 @@ namespace Torch.Utils
|
|||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (Process(field))
|
if (Process(field))
|
||||||
_log?.Trace($"Field {field.DeclaringType?.FullName}#{field.Name} = {field.GetValue(null) ?? "null"}");
|
_log?.Trace(
|
||||||
|
$"Field {field.DeclaringType?.FullName}#{field.Name} = {field.GetValue(null) ?? "null"}");
|
||||||
#else
|
#else
|
||||||
Process(field);
|
Process(field);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_log?.Error(e.InnerException ?? e, $"Unable to fill {field.DeclaringType?.FullName}#{field.Name}. {(e.InnerException ?? e).Message}");
|
_log?.Error(e.InnerException ?? e,
|
||||||
|
$"Unable to fill {field.DeclaringType?.FullName}#{field.Name}. {(e.InnerException ?? e).Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +126,7 @@ namespace Torch.Utils
|
|||||||
new Func<ReflectedEventReplacer>(() => new ReflectedEventReplacer(reflectedEventReplacer)));
|
new Func<ReflectedEventReplacer>(() => new ReflectedEventReplacer(reflectedEventReplacer)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,12 +171,16 @@ namespace Torch.Utils
|
|||||||
throw new ArgumentException(
|
throw new ArgumentException(
|
||||||
$"Unable to find method {rmia.Type.FullName}#{rmia.Name}");
|
$"Unable to find method {rmia.Type.FullName}#{rmia.Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rmia.ReturnType != null && !rmia.ReturnType.IsAssignableFrom(((MethodInfo) info).ReturnType))
|
if (rmia.ReturnType != null && !rmia.ReturnType.IsAssignableFrom(((MethodInfo) info).ReturnType))
|
||||||
throw new ArgumentException($"Method {rmia.Type.FullName}#{rmia.Name} has return type {((MethodInfo)info).ReturnType.FullName}, expected {rmia.ReturnType.FullName}");
|
throw new ArgumentException(
|
||||||
|
$"Method {rmia.Type.FullName}#{rmia.Name} has return type {((MethodInfo) info).ReturnType.FullName}, expected {rmia.ReturnType.FullName}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info == null)
|
if (info == null)
|
||||||
throw new ArgumentException($"Unable to find member info for {attr.GetType().Name}[{attr.Type.FullName}#{attr.Name}");
|
throw new ArgumentException(
|
||||||
|
$"Unable to find member info for {attr.GetType().Name}[{attr.Type.FullName}#{attr.Name}");
|
||||||
field.SetValue(null, info);
|
field.SetValue(null, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,11 +254,13 @@ namespace Torch.Utils
|
|||||||
field.SetValue(null,
|
field.SetValue(null,
|
||||||
Expression.Lambda(Expression.Call(instanceExp, methodInstance, argExp), paramExp)
|
Expression.Lambda(Expression.Call(instanceExp, methodInstance, argExp), paramExp)
|
||||||
.Compile());
|
.Compile());
|
||||||
_log.Trace($"Reflecting field {field.DeclaringType?.FullName}#{field.Name} with {methodInstance.DeclaringType?.FullName}#{methodInstance.Name}");
|
_log.Trace(
|
||||||
|
$"Reflecting field {field.DeclaringType?.FullName}#{field.Name} with {methodInstance.DeclaringType?.FullName}#{methodInstance.Name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static T GetFieldPropRecursive<T>(Type baseType, string name, BindingFlags flags, Func<Type, string, BindingFlags, T> getter) where T : class
|
internal static T GetFieldPropRecursive<T>(Type baseType, string name, BindingFlags flags,
|
||||||
|
Func<Type, string, BindingFlags, T> getter) where T : class
|
||||||
{
|
{
|
||||||
while (baseType != null)
|
while (baseType != null)
|
||||||
{
|
{
|
||||||
@@ -296,7 +308,8 @@ namespace Torch.Utils
|
|||||||
trueType = parameters[0].ParameterType;
|
trueType = parameters[0].ParameterType;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new ArgumentException($"Field attribute type {attr.GetType().FullName} is invalid", nameof(field));
|
throw new ArgumentException($"Field attribute type {attr.GetType().FullName} is invalid",
|
||||||
|
nameof(field));
|
||||||
|
|
||||||
BindingFlags bindingFlags = (isStatic ? BindingFlags.Static : BindingFlags.Instance) |
|
BindingFlags bindingFlags = (isStatic ? BindingFlags.Static : BindingFlags.Instance) |
|
||||||
BindingFlags.NonPublic |
|
BindingFlags.NonPublic |
|
||||||
@@ -307,35 +320,77 @@ namespace Torch.Utils
|
|||||||
GetFieldPropRecursive(trueType, trueName, bindingFlags, (a, b, c) => a.GetProperty(b, c));
|
GetFieldPropRecursive(trueType, trueName, bindingFlags, (a, b, c) => a.GetProperty(b, c));
|
||||||
if (sourceField == null && sourceProperty == null)
|
if (sourceField == null && sourceProperty == null)
|
||||||
throw new ArgumentException(
|
throw new ArgumentException(
|
||||||
$"Unable to find field or property for {trueName} in {trueType.FullName} or its base types", nameof(field));
|
$"Unable to find field or property for {trueName} in {trueType.FullName} or its base types",
|
||||||
|
nameof(field));
|
||||||
|
var sourceType = sourceField?.FieldType ?? sourceProperty.PropertyType;
|
||||||
|
bool isSetter = attr is ReflectedSetterAttribute;
|
||||||
|
if (sourceProperty != null && isSetter && !sourceProperty.CanWrite)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Can't create setter for readonly property {trueName} in {trueType.FullName}");
|
||||||
|
|
||||||
|
if (sourceProperty != null && !isSetter && !sourceProperty.CanRead)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Can't create getter for writeonly property {trueName} in {trueType.FullName}");
|
||||||
|
|
||||||
|
var dynMethod = new DynamicMethod((isSetter ? "set" : "get") + "_" + trueType.FullName + "." + trueName,
|
||||||
|
delegateMethod.ReturnType, parameters.Select(x => x.ParameterType).ToArray(),
|
||||||
|
typeof(ReflectedManager).Module, true);
|
||||||
|
ILGenerator il = dynMethod.GetILGenerator();
|
||||||
|
|
||||||
ParameterExpression[] paramExp = parameters.Select(x => Expression.Parameter(x.ParameterType)).ToArray();
|
|
||||||
Expression instanceExpr = null;
|
|
||||||
if (!isStatic)
|
if (!isStatic)
|
||||||
{
|
EmitThis(il, parameters[0].ParameterType, trueType);
|
||||||
instanceExpr = trueType == paramExp[0].Type ? (Expression)paramExp[0] : Expression.Convert(paramExp[0], trueType);
|
|
||||||
}
|
|
||||||
|
|
||||||
MemberExpression fieldExp = sourceField != null
|
if (isSetter)
|
||||||
? Expression.Field(instanceExpr, sourceField)
|
|
||||||
: Expression.Property(instanceExpr, sourceProperty);
|
|
||||||
Expression impl;
|
|
||||||
if (attr is ReflectedSetterAttribute)
|
|
||||||
{
|
{
|
||||||
var valParam = paramExp[isStatic ? 0 : 1];
|
int val = isStatic ? 0 : 1;
|
||||||
var valExpr = (Expression)valParam;
|
il.Emit(OpCodes.Ldarg, val);
|
||||||
var setType = sourceField?.FieldType ?? sourceProperty.PropertyType;
|
EmitCast(il, parameters[val].ParameterType, sourceType);
|
||||||
if (valParam.Type != setType)
|
if (sourceProperty != null)
|
||||||
valExpr = Expression.Convert(valExpr, setType);
|
il.Emit(sourceProperty.SetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt,
|
||||||
impl = Expression.Block(Expression.Assign(fieldExp, valExpr), Expression.Default(typeof(void)));
|
sourceProperty.SetMethod);
|
||||||
|
else
|
||||||
|
il.Emit(isStatic ? OpCodes.Stsfld : OpCodes.Stfld, sourceField);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
impl = fieldExp;
|
if (sourceProperty != null)
|
||||||
|
il.Emit(sourceProperty.GetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt,
|
||||||
|
sourceProperty.GetMethod);
|
||||||
|
else
|
||||||
|
il.Emit(isStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, sourceField);
|
||||||
|
EmitCast(il, sourceType, delegateMethod.ReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
field.SetValue(null, Expression.Lambda(impl, paramExp).Compile());
|
il.Emit(OpCodes.Ret);
|
||||||
_log.Trace($"Reflecting field {field.DeclaringType?.FullName}#{field.Name} with {field.DeclaringType?.FullName}#{field.Name}");
|
|
||||||
}
|
field.SetValue(null, dynMethod.CreateDelegate(field.FieldType));
|
||||||
|
_log.Trace(
|
||||||
|
$"Reflecting field {field.DeclaringType?.FullName}#{field.Name} with {field.DeclaringType?.FullName}#{field.Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IL Utils
|
||||||
|
|
||||||
|
private static void EmitThis(ILGenerator il, Type argType, Type privateType)
|
||||||
|
{
|
||||||
|
il.Emit(OpCodes.Ldarg_0);
|
||||||
|
// pointers?
|
||||||
|
EmitCast(il, argType, privateType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitCast(ILGenerator il, Type from, Type to)
|
||||||
|
{
|
||||||
|
if (from.IsValueType && !to.IsValueType)
|
||||||
|
il.Emit(OpCodes.Box, from);
|
||||||
|
else if (!from.IsValueType && to.IsValueType)
|
||||||
|
{
|
||||||
|
il.Emit(OpCodes.Unbox, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from != to && (from.IsAssignableFrom(to) || to.IsAssignableFrom(from)))
|
||||||
|
il.Emit(OpCodes.Castclass, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -28,6 +28,7 @@ using VRage.FileSystem;
|
|||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
using VRage.Game.SessionComponents;
|
using VRage.Game.SessionComponents;
|
||||||
using VRage.GameServices;
|
using VRage.GameServices;
|
||||||
|
using VRage.Network;
|
||||||
using VRage.Plugins;
|
using VRage.Plugins;
|
||||||
using VRage.Steam;
|
using VRage.Steam;
|
||||||
using VRage.Utils;
|
using VRage.Utils;
|
||||||
@@ -53,6 +54,10 @@ namespace Torch
|
|||||||
|
|
||||||
[ReflectedMethod(Name = "Unload", TypeName = "Sandbox.Game.Audio.MyMusicController, Sandbox.Game")]
|
[ReflectedMethod(Name = "Unload", TypeName = "Sandbox.Game.Audio.MyMusicController, Sandbox.Game")]
|
||||||
private static readonly Action<object> _musicControllerUnload;
|
private static readonly Action<object> _musicControllerUnload;
|
||||||
|
|
||||||
|
// [ReflectedGetter(Name = "UpdateLayerDescriptors", Type = typeof(MyReplicationServer))]
|
||||||
|
// private static readonly Func<MyReplicationServer.UpdateLayerDesc[]> _layerSettings;
|
||||||
|
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
private readonly TorchBase _torch;
|
private readonly TorchBase _torch;
|
||||||
@@ -195,6 +200,9 @@ namespace Torch
|
|||||||
MyRenderProxy.GetRenderProfiler().InitMemoryHack("MainEntryPoint");
|
MyRenderProxy.GetRenderProfiler().InitMemoryHack("MainEntryPoint");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// var layers = _layerSettings();
|
||||||
|
// layers[layers.Length - 1].Radius *= 4;
|
||||||
|
|
||||||
_game = new SpaceEngineersGame(_runArgs);
|
_game = new SpaceEngineersGame(_runArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user