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:
Westin Miller
2018-01-24 17:24:08 -08:00
parent e6928b6ab1
commit 1e6b3faff8
7 changed files with 139 additions and 53 deletions

View File

@@ -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" />

View File

@@ -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
{ {

View File

@@ -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(

View File

@@ -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);
}
} }
} }

View File

@@ -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;

View File

@@ -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
} }
} }

View File

@@ -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);
} }