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>
<rules>
<logger name="Keen" minlevel="Warn" writeTo="main"/>
<logger name="Keen" minlevel="Info" writeTo="console"/>
<logger name="Keen" minlevel="Debug" writeTo="keen" 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 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()
{
@@ -124,10 +116,7 @@ namespace Torch.Managers.PatchManager
try
{
// Force it to compile
RuntimeMethodHandle handle = _getMethodHandle.Invoke(method);
object runtimeMethodInfo = _getMethodInfo.Invoke(handle);
_compileDynamicMethod.Invoke(runtimeMethodInfo);
PatchUtilities.Compile(method);
}
catch
{

View File

@@ -426,16 +426,16 @@ namespace Torch.Managers.PatchManager.MSIL
{
case OperandType.InlineTok:
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;
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;
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;
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;
default:
throw new InvalidBranchException(

View File

@@ -3,10 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using NLog;
using Torch.Managers.PatchManager.MSIL;
using Torch.Managers.PatchManager.Transpile;
using Torch.Utils;
namespace Torch.Managers.PatchManager
{
@@ -36,5 +39,35 @@ namespace Torch.Managers.PatchManager
{
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 directory: {AppDomain.CurrentDomain.BaseDirectory}");
Managers.GetManager<PluginManager>().LoadPlugins();
Game = new VRageGame(this, TweakGameSettings, SteamAppName, SteamAppId, Config.InstancePath, RunArgs);
if (!Game.WaitFor(VRageGame.GameState.Stopped, TimeSpan.FromMinutes(5)))
Log.Warn("Failed to wait for game to be initialized");
Managers.GetManager<PluginManager>().LoadPlugins();
Managers.Attach();
_init = true;

View File

@@ -5,12 +5,15 @@ using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using NLog;
using Sandbox.Engine.Multiplayer;
using Torch.API;
using Torch.Managers.PatchManager;
using Torch.Utils.Reflected;
using PropertyAttributes = System.Reflection.PropertyAttributes;
namespace Torch.Utils
{
@@ -53,14 +56,16 @@ namespace Torch.Utils
{
#if DEBUG
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
Process(field);
#endif
}
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)));
return true;
}
return false;
}
@@ -142,8 +148,8 @@ namespace Torch.Utils
break;
case ReflectedPropertyInfoAttribute rpia:
info = GetFieldPropRecursive(rpia.Type, rpia.Name,
BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
(type, name, bindingFlags) => type.GetProperty(name, bindingFlags));
BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
(type, name, bindingFlags) => type.GetProperty(name, bindingFlags));
if (info == null)
throw new ArgumentException($"Unable to find property {rpia.Type.FullName}#{rpia.Name}");
break;
@@ -151,8 +157,8 @@ namespace Torch.Utils
if (rmia.Parameters != null)
{
info = rmia.Type.GetMethod(rmia.Name,
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, CallingConventions.Any, rmia.Parameters, null);
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, CallingConventions.Any, rmia.Parameters, null);
if (info == null)
throw new ArgumentException(
$"Unable to find method {rmia.Type.FullName}#{rmia.Name}({string.Join(", ", rmia.Parameters.Select(x => x.FullName))})");
@@ -160,17 +166,21 @@ namespace Torch.Utils
else
{
info = rmia.Type.GetMethod(rmia.Name,
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (info == null)
throw new ArgumentException(
$"Unable to find method {rmia.Type.FullName}#{rmia.Name}");
}
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}");
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}");
break;
}
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);
}
@@ -222,7 +232,7 @@ namespace Torch.Utils
argExp[i] = paramExp[i];
field.SetValue(null,
Expression.Lambda(Expression.Call(methodInstance, argExp), paramExp)
.Compile());
.Compile());
}
else
field.SetValue(null, Delegate.CreateDelegate(field.FieldType, methodInstance));
@@ -243,12 +253,14 @@ namespace Torch.Utils
: (Expression) paramExp[0];
field.SetValue(null,
Expression.Lambda(Expression.Call(instanceExp, methodInstance, argExp), paramExp)
.Compile());
_log.Trace($"Reflecting field {field.DeclaringType?.FullName}#{field.Name} with {methodInstance.DeclaringType?.FullName}#{methodInstance.Name}");
.Compile());
_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)
{
@@ -296,7 +308,8 @@ namespace Torch.Utils
trueType = parameters[0].ParameterType;
}
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.NonPublic |
@@ -307,35 +320,77 @@ namespace Torch.Utils
GetFieldPropRecursive(trueType, trueName, bindingFlags, (a, b, c) => a.GetProperty(b, c));
if (sourceField == null && sourceProperty == null)
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)
{
instanceExpr = trueType == paramExp[0].Type ? (Expression)paramExp[0] : Expression.Convert(paramExp[0], trueType);
}
EmitThis(il, parameters[0].ParameterType, trueType);
MemberExpression fieldExp = sourceField != null
? Expression.Field(instanceExpr, sourceField)
: Expression.Property(instanceExpr, sourceProperty);
Expression impl;
if (attr is ReflectedSetterAttribute)
if (isSetter)
{
var valParam = paramExp[isStatic ? 0 : 1];
var valExpr = (Expression)valParam;
var setType = sourceField?.FieldType ?? sourceProperty.PropertyType;
if (valParam.Type != setType)
valExpr = Expression.Convert(valExpr, setType);
impl = Expression.Block(Expression.Assign(fieldExp, valExpr), Expression.Default(typeof(void)));
int val = isStatic ? 0 : 1;
il.Emit(OpCodes.Ldarg, val);
EmitCast(il, parameters[val].ParameterType, sourceType);
if (sourceProperty != null)
il.Emit(sourceProperty.SetMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt,
sourceProperty.SetMethod);
else
il.Emit(isStatic ? OpCodes.Stsfld : OpCodes.Stfld, sourceField);
}
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());
_log.Trace($"Reflecting field {field.DeclaringType?.FullName}#{field.Name} with {field.DeclaringType?.FullName}#{field.Name}");
il.Emit(OpCodes.Ret);
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.SessionComponents;
using VRage.GameServices;
using VRage.Network;
using VRage.Plugins;
using VRage.Steam;
using VRage.Utils;
@@ -53,6 +54,10 @@ namespace Torch
[ReflectedMethod(Name = "Unload", TypeName = "Sandbox.Game.Audio.MyMusicController, Sandbox.Game")]
private static readonly Action<object> _musicControllerUnload;
// [ReflectedGetter(Name = "UpdateLayerDescriptors", Type = typeof(MyReplicationServer))]
// private static readonly Func<MyReplicationServer.UpdateLayerDesc[]> _layerSettings;
#pragma warning restore 649
private readonly TorchBase _torch;
@@ -195,6 +200,9 @@ namespace Torch
MyRenderProxy.GetRenderProfiler().InitMemoryHack("MainEntryPoint");
}
// var layers = _layerSettings();
// layers[layers.Length - 1].Radius *= 4;
_game = new SpaceEngineersGame(_runArgs);
}