Patch manager supports communicating method cancel state
Game state patch split out into a patch shim Special NS for events Core and auxillary assembly concepts Reflected manager stops working for mods/scripts
This commit is contained in:
@@ -163,14 +163,14 @@
|
||||
<Compile Include="ITorchConfig.cs" />
|
||||
<Compile Include="Managers\DependencyManagerExtensions.cs" />
|
||||
<Compile Include="Managers\DependencyProviderExtensions.cs" />
|
||||
<Compile Include="Managers\Event\EventHandlerAttribute.cs" />
|
||||
<Compile Include="Managers\Event\IEvent.cs" />
|
||||
<Compile Include="Managers\Event\IEventHandler.cs" />
|
||||
<Compile Include="Event\EventHandlerAttribute.cs" />
|
||||
<Compile Include="Event\IEvent.cs" />
|
||||
<Compile Include="Event\IEventHandler.cs" />
|
||||
<Compile Include="Managers\IChatManagerClient.cs" />
|
||||
<Compile Include="Managers\IChatManagerServer.cs" />
|
||||
<Compile Include="Managers\IDependencyManager.cs" />
|
||||
<Compile Include="Managers\IDependencyProvider.cs" />
|
||||
<Compile Include="Managers\Event\IEventManager.cs" />
|
||||
<Compile Include="Event\IEventManager.cs" />
|
||||
<Compile Include="Managers\IManager.cs" />
|
||||
<Compile Include="Managers\IMultiplayerManagerClient.cs" />
|
||||
<Compile Include="Managers\IMultiplayerManagerBase.cs" />
|
||||
|
@@ -26,8 +26,12 @@ namespace Torch.Event
|
||||
AddDispatchShim(type);
|
||||
}
|
||||
|
||||
private static readonly HashSet<Type> _dispatchShims = new HashSet<Type>();
|
||||
private static void AddDispatchShim(Type type)
|
||||
{
|
||||
lock (_dispatchShims)
|
||||
if (!_dispatchShims.Add(type))
|
||||
return;
|
||||
if (!type.IsSealed || !type.IsAbstract)
|
||||
_log.Warn($"Registering type {type.FullName} as an event dispatch type, even though it isn't declared singleton");
|
||||
var listsFound = 0;
|
||||
@@ -40,7 +44,7 @@ namespace Torch.Event
|
||||
_log.Error($"Ignore event dispatch list {type.FullName}#{field.Name}; we already have one.");
|
||||
else
|
||||
{
|
||||
_eventLists.Add(eventType, (IEventList) field.GetValue(null));
|
||||
_eventLists.Add(eventType, (IEventList)field.GetValue(null));
|
||||
listsFound++;
|
||||
}
|
||||
|
||||
@@ -49,7 +53,7 @@ namespace Torch.Event
|
||||
_log.Warn($"Registering type {type.FullName} as an event dispatch type, even though it has no event lists.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all event handler methods declared by the given type and its base types.
|
||||
/// </summary>
|
||||
|
@@ -79,8 +79,9 @@ namespace Torch.Managers.PatchManager
|
||||
}
|
||||
|
||||
|
||||
private const string INSTANCE_PARAMETER = "__instance";
|
||||
private const string RESULT_PARAMETER = "__result";
|
||||
public const string INSTANCE_PARAMETER = "__instance";
|
||||
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" })]
|
||||
@@ -118,7 +119,7 @@ namespace Torch.Managers.PatchManager
|
||||
var specialVariables = new Dictionary<string, LocalBuilder>();
|
||||
|
||||
Label labelAfterOriginalContent = target.DefineLabel();
|
||||
Label labelAfterOriginalReturn = target.DefineLabel();
|
||||
Label labelSkipMethodContent = target.DefineLabel();
|
||||
|
||||
|
||||
Type returnType = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
|
||||
@@ -131,6 +132,13 @@ namespace Torch.Managers.PatchManager
|
||||
resultVariable = target.DeclareLocal(returnType);
|
||||
}
|
||||
resultVariable?.SetToDefault(target);
|
||||
LocalBuilder prefixSkippedVariable = null;
|
||||
if (Prefixes.Count > 0 && Suffixes.Any(x => x.GetParameters()
|
||||
.Any(y => y.Name.Equals(PREFIX_SKIPPED_PARAMETER))))
|
||||
{
|
||||
prefixSkippedVariable = target.DeclareLocal(typeof(bool));
|
||||
specialVariables.Add(PREFIX_SKIPPED_PARAMETER, prefixSkippedVariable);
|
||||
}
|
||||
|
||||
if (resultVariable != null)
|
||||
specialVariables.Add(RESULT_PARAMETER, resultVariable);
|
||||
@@ -140,7 +148,7 @@ namespace Torch.Managers.PatchManager
|
||||
{
|
||||
EmitMonkeyCall(target, prefix, specialVariables);
|
||||
if (prefix.ReturnType == typeof(bool))
|
||||
target.Emit(OpCodes.Brfalse, labelAfterOriginalReturn);
|
||||
target.Emit(OpCodes.Brfalse, labelSkipMethodContent);
|
||||
else if (prefix.ReturnType != typeof(void))
|
||||
throw new Exception(
|
||||
$"Prefixes must return void or bool. {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}");
|
||||
@@ -154,7 +162,15 @@ namespace Torch.Managers.PatchManager
|
||||
target.MarkLabel(labelAfterOriginalContent);
|
||||
if (resultVariable != null)
|
||||
target.Emit(OpCodes.Stloc, resultVariable);
|
||||
target.MarkLabel(labelAfterOriginalReturn);
|
||||
Label notSkip = target.DefineLabel();
|
||||
target.Emit(OpCodes.Br, notSkip);
|
||||
target.MarkLabel(labelSkipMethodContent);
|
||||
if (prefixSkippedVariable != null)
|
||||
{
|
||||
target.Emit(OpCodes.Ldc_I4_1);
|
||||
target.Emit(OpCodes.Stloc, prefixSkippedVariable);
|
||||
}
|
||||
target.MarkLabel(notSkip);
|
||||
|
||||
target.EmitComment("Suffixes Begin");
|
||||
foreach (MethodInfo suffix in Suffixes)
|
||||
@@ -182,8 +198,18 @@ namespace Torch.Managers.PatchManager
|
||||
throw new Exception("Can't use an instance parameter for a static method");
|
||||
target.Emit(OpCodes.Ldarg_0);
|
||||
break;
|
||||
case PREFIX_SKIPPED_PARAMETER:
|
||||
if (param.ParameterType != typeof(bool))
|
||||
throw new Exception($"Prefix skipped parameter {param.ParameterType} must be of type bool");
|
||||
if (param.ParameterType.IsByRef || param.IsOut)
|
||||
throw new Exception($"Prefix skipped parameter {param.ParameterType} can't be a reference type");
|
||||
if (specialVariables.TryGetValue(PREFIX_SKIPPED_PARAMETER, out LocalBuilder prefixSkip))
|
||||
target.Emit(OpCodes.Ldloc, prefixSkip);
|
||||
else
|
||||
target.Emit(OpCodes.Ldc_I4_0);
|
||||
break;
|
||||
case RESULT_PARAMETER:
|
||||
var retType = param.ParameterType.IsByRef
|
||||
Type retType = param.ParameterType.IsByRef
|
||||
? param.ParameterType.GetElementType()
|
||||
: param.ParameterType;
|
||||
if (retType == null || !retType.IsAssignableFrom(specialVariables[RESULT_PARAMETER].LocalType))
|
||||
@@ -191,13 +217,13 @@ namespace Torch.Managers.PatchManager
|
||||
target.Emit(param.ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc, specialVariables[RESULT_PARAMETER]);
|
||||
break;
|
||||
default:
|
||||
var declParam = _method.GetParameters().FirstOrDefault(x => x.Name == param.Name);
|
||||
ParameterInfo declParam = _method.GetParameters().FirstOrDefault(x => x.Name == param.Name);
|
||||
if (declParam == null)
|
||||
throw new Exception($"Parameter name {param.Name} not found");
|
||||
var paramIdx = (_method.IsStatic ? 0 : 1) + declParam.Position;
|
||||
int paramIdx = (_method.IsStatic ? 0 : 1) + declParam.Position;
|
||||
|
||||
var patchByRef = param.IsOut || param.ParameterType.IsByRef;
|
||||
var declByRef = declParam.IsOut || declParam.ParameterType.IsByRef;
|
||||
bool patchByRef = param.IsOut || param.ParameterType.IsByRef;
|
||||
bool declByRef = declParam.IsOut || declParam.ParameterType.IsByRef;
|
||||
if (patchByRef == declByRef)
|
||||
target.Emit(OpCodes.Ldarg, paramIdx);
|
||||
else if (patchByRef)
|
||||
|
@@ -22,8 +22,14 @@ namespace Torch.Managers.PatchManager
|
||||
AddPatchShim(t);
|
||||
}
|
||||
|
||||
private static void AddPatchShim(Type type)
|
||||
private static readonly HashSet<Type> _patchShims = new HashSet<Type>();
|
||||
// Internal, not static, so the static cctor of TorchBase can hookup the GameStatePatchShim which tells us when
|
||||
// its safe to patch the rest of the game.
|
||||
internal static void AddPatchShim(Type type)
|
||||
{
|
||||
lock (_patchShims)
|
||||
if (!_patchShims.Add(type))
|
||||
return;
|
||||
if (!type.IsSealed || !type.IsAbstract)
|
||||
_log.Warn($"Registering type {type.FullName} as a patch shim type, even though it isn't declared singleton");
|
||||
MethodInfo method = type.GetMethod("Patch", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
@@ -34,7 +40,7 @@ namespace Torch.Managers.PatchManager
|
||||
}
|
||||
ParameterInfo[] ps = method.GetParameters();
|
||||
if (ps.Length != 1 || ps[0].IsOut || ps[0].IsOptional || ps[0].ParameterType.IsByRef ||
|
||||
ps[0].ParameterType == typeof(PatchContext) || method.ReturnType == typeof(void))
|
||||
ps[0].ParameterType != typeof(PatchContext) || method.ReturnType != typeof(void))
|
||||
{
|
||||
_log.Error($"Patch shim type {type.FullName} doesn't have a method with signature `void Patch(PatchContext)`");
|
||||
return;
|
||||
@@ -55,13 +61,10 @@ namespace Torch.Managers.PatchManager
|
||||
|
||||
private static readonly Dictionary<MethodBase, DecoratedMethod> _rewritePatterns = new Dictionary<MethodBase, DecoratedMethod>();
|
||||
private static readonly Dictionary<Assembly, List<PatchContext>> _contexts = new Dictionary<Assembly, List<PatchContext>>();
|
||||
private static List<PatchContext> _coreContexts = new List<PatchContext>();
|
||||
// ReSharper disable once CollectionNeverQueried.Local because we may want this in the future.
|
||||
private static readonly List<PatchContext> _coreContexts = new List<PatchContext>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rewrite pattern for the given method, creating one if it doesn't exist.
|
||||
/// </summary>
|
||||
/// <param name="method">Method to get the pattern for</param>
|
||||
/// <returns></returns>
|
||||
/// <inheritdoc cref="GetPattern"/>
|
||||
internal static MethodRewritePattern GetPatternInternal(MethodBase method)
|
||||
{
|
||||
lock (_rewritePatterns)
|
||||
@@ -145,14 +148,20 @@ namespace Torch.Managers.PatchManager
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Commit"/>
|
||||
internal static void CommitInternal()
|
||||
{
|
||||
lock (_rewritePatterns)
|
||||
foreach (DecoratedMethod m in _rewritePatterns.Values)
|
||||
m.Commit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commits all method decorations into IL.
|
||||
/// </summary>
|
||||
public void Commit()
|
||||
{
|
||||
lock (_rewritePatterns)
|
||||
foreach (DecoratedMethod m in _rewritePatterns.Values)
|
||||
m.Commit();
|
||||
CommitInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
75
Torch/Patches/GameStatePatchShim.cs
Normal file
75
Torch/Patches/GameStatePatchShim.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Sandbox;
|
||||
using Torch.API;
|
||||
using Torch.Managers.PatchManager;
|
||||
using Torch.Utils;
|
||||
|
||||
namespace Torch.Patches
|
||||
{
|
||||
[PatchShim]
|
||||
internal static class GameStatePatchShim
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[ReflectedMethodInfo(typeof(MySandboxGame), nameof(MySandboxGame.Dispose))]
|
||||
private static MethodInfo _sandboxGameDispose;
|
||||
[ReflectedMethodInfo(typeof(MySandboxGame), "Initialize")]
|
||||
private static MethodInfo _sandboxGameInit;
|
||||
#pragma warning restore 649
|
||||
|
||||
internal static void Patch(PatchContext target)
|
||||
{
|
||||
ConstructorInfo ctor = typeof(MySandboxGame).GetConstructor(new[] { typeof(string[]) });
|
||||
if (ctor == null)
|
||||
throw new ArgumentException("Can't find constructor MySandboxGame(string[])");
|
||||
target.GetPattern(ctor).Prefixes.Add(MethodRef(PrefixConstructor));
|
||||
target.GetPattern(ctor).Suffixes.Add(MethodRef(SuffixConstructor));
|
||||
target.GetPattern(_sandboxGameInit).Prefixes.Add(MethodRef(PrefixInit));
|
||||
target.GetPattern(_sandboxGameInit).Suffixes.Add(MethodRef(SuffixInit));
|
||||
target.GetPattern(_sandboxGameDispose).Prefixes.Add(MethodRef(PrefixDispose));
|
||||
target.GetPattern(_sandboxGameDispose).Suffixes.Add(MethodRef(SuffixDispose));
|
||||
}
|
||||
|
||||
private static MethodInfo MethodRef(Action a )
|
||||
{
|
||||
return a.Method;
|
||||
}
|
||||
|
||||
private static void PrefixConstructor()
|
||||
{
|
||||
if (TorchBase.Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Creating;
|
||||
}
|
||||
|
||||
private static void SuffixConstructor()
|
||||
{
|
||||
PatchManager.CommitInternal();
|
||||
if (TorchBase.Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Created;
|
||||
}
|
||||
|
||||
private static void PrefixInit()
|
||||
{
|
||||
if (TorchBase.Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Loading;
|
||||
}
|
||||
|
||||
private static void SuffixInit()
|
||||
{
|
||||
if (TorchBase.Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Loaded;
|
||||
}
|
||||
|
||||
private static void PrefixDispose()
|
||||
{
|
||||
if (TorchBase.Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Unloading;
|
||||
}
|
||||
|
||||
private static void SuffixDispose()
|
||||
{
|
||||
if (TorchBase.Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Unloaded;
|
||||
}
|
||||
}
|
||||
}
|
@@ -268,7 +268,8 @@ namespace Torch.Managers
|
||||
{
|
||||
var data = new byte[entry.Length];
|
||||
stream.Read(data, 0, data.Length);
|
||||
assemblies.Add(Assembly.Load(data));
|
||||
Assembly asm = Assembly.Load(data);
|
||||
TorchBase.RegisterAuxAssembly(asm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -155,15 +155,16 @@
|
||||
<Link>Properties\AssemblyVersion.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Collections\ObservableList.cs" />
|
||||
<Compile Include="Event\EventShimAttribute.cs" />
|
||||
<Compile Include="Managers\ChatManager\ChatManagerClient.cs" />
|
||||
<Compile Include="Managers\ChatManager\ChatManagerServer.cs" />
|
||||
<Compile Include="Extensions\DispatcherExtensions.cs" />
|
||||
<Compile Include="Extensions\ICollectionExtensions.cs" />
|
||||
<Compile Include="Managers\DependencyManager.cs" />
|
||||
<Compile Include="Managers\Event\EventList.cs" />
|
||||
<Compile Include="Managers\Event\EventManager.cs" />
|
||||
<Compile Include="Managers\Event\EventShimProgrammableBlock.cs" />
|
||||
<Compile Include="Managers\Event\IEventList.cs" />
|
||||
<Compile Include="Event\EventList.cs" />
|
||||
<Compile Include="Event\EventManager.cs" />
|
||||
<Compile Include="Event\EventShimProgrammableBlock.cs" />
|
||||
<Compile Include="Event\IEventList.cs" />
|
||||
<Compile Include="Managers\KeenLogManager.cs" />
|
||||
<Compile Include="Managers\PatchManager\AssemblyMemory.cs" />
|
||||
<Compile Include="Managers\PatchManager\DecoratedMethod.cs" />
|
||||
@@ -179,12 +180,14 @@
|
||||
<Compile Include="Managers\PatchManager\MSIL\MsilOperandInline.cs" />
|
||||
<Compile Include="Managers\PatchManager\MSIL\MsilOperandSwitch.cs" />
|
||||
<Compile Include="Managers\PatchManager\MethodRewritePattern.cs" />
|
||||
<Compile Include="Managers\PatchManager\PatchShimAttribute.cs" />
|
||||
<Compile Include="Managers\PatchManager\PatchContext.cs" />
|
||||
<Compile Include="Managers\PatchManager\PatchManager.cs" />
|
||||
<Compile Include="Managers\PatchManager\PatchPriorityAttribute.cs" />
|
||||
<Compile Include="Managers\PatchManager\Transpile\LoggingILGenerator.cs" />
|
||||
<Compile Include="Managers\PatchManager\Transpile\MethodContext.cs" />
|
||||
<Compile Include="Managers\PatchManager\Transpile\MethodTranspiler.cs" />
|
||||
<Compile Include="Patches\GameStatePatchShim.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SaveGameStatus.cs" />
|
||||
<Compile Include="Collections\KeyTree.cs" />
|
||||
|
@@ -26,6 +26,7 @@ using Torch.Event;
|
||||
using Torch.Managers;
|
||||
using Torch.Managers.ChatManager;
|
||||
using Torch.Managers.PatchManager;
|
||||
using Torch.Patches;
|
||||
using Torch.Utils;
|
||||
using Torch.Session;
|
||||
using VRage.Collections;
|
||||
@@ -46,10 +47,12 @@ namespace Torch
|
||||
{
|
||||
static TorchBase()
|
||||
{
|
||||
RuntimeHelpers.RunClassConstructor(typeof(ReflectedManager).TypeHandle);
|
||||
PatchManager.AddPatchShim(typeof(GameStatePatchShim));
|
||||
PatchManager.CommitInternal();
|
||||
RegisterCoreAssembly(typeof(ITorchBase).Assembly);
|
||||
RegisterCoreAssembly(typeof(TorchBase).Assembly);
|
||||
// We can safely never detach this since we don't reload assemblies.
|
||||
new ReflectedManager().Attach();
|
||||
RegisterCoreAssembly(Assembly.GetEntryAssembly());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -124,21 +127,11 @@ namespace Torch
|
||||
sessionManager.AddFactory((x) => new EntityManager(this));
|
||||
|
||||
Managers.AddManager(sessionManager);
|
||||
var patcher = new PatchManager(this);
|
||||
GameStateInjector.Inject(patcher.AcquireContext());
|
||||
Managers.AddManager(patcher);
|
||||
// Managers.AddManager(new KeenLogManager(this));
|
||||
Managers.AddManager(new PatchManager(this));
|
||||
Managers.AddManager(new FilesystemManager(this));
|
||||
Managers.AddManager(new UpdateManager(this));
|
||||
Managers.AddManager(new EventManager(this));
|
||||
Managers.AddManager(Plugins);
|
||||
GameStateChanged += (game, state) =>
|
||||
{
|
||||
if (state != TorchGameState.Created)
|
||||
return;
|
||||
// At this point flush the patches; it's safe.
|
||||
patcher.Commit();
|
||||
};
|
||||
TorchAPI.Instance = this;
|
||||
}
|
||||
|
||||
@@ -395,7 +388,7 @@ namespace Torch
|
||||
/// <inheritdoc />
|
||||
public virtual void Update()
|
||||
{
|
||||
GetManager<IPluginManager>().UpdatePlugins();
|
||||
Managers.GetManager<IPluginManager>().UpdatePlugins();
|
||||
}
|
||||
|
||||
|
||||
@@ -405,7 +398,7 @@ namespace Torch
|
||||
public TorchGameState GameState
|
||||
{
|
||||
get => _gameState;
|
||||
private set
|
||||
internal set
|
||||
{
|
||||
_gameState = value;
|
||||
GameStateChanged?.Invoke(MySandboxGame.Static, _gameState);
|
||||
@@ -415,81 +408,36 @@ namespace Torch
|
||||
/// <inheritdoc/>
|
||||
public event TorchGameStateChangedDel GameStateChanged;
|
||||
|
||||
#region GameStateInjecting
|
||||
private static class GameStateInjector
|
||||
private static readonly HashSet<Assembly> _registeredCoreAssemblies = new HashSet<Assembly>();
|
||||
/// <summary>
|
||||
/// Registers a core (Torch) assembly with the system, including its
|
||||
/// <see cref="EventManager"/> shims, <see cref="PatchManager"/> shims, and <see cref="ReflectedManager"/> components.
|
||||
/// </summary>
|
||||
/// <param name="asm">Assembly to register</param>
|
||||
internal static void RegisterCoreAssembly(Assembly asm)
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[ReflectedMethodInfo(typeof(MySandboxGame), nameof(MySandboxGame.Dispose))]
|
||||
private static MethodInfo _sandboxGameDispose;
|
||||
[ReflectedMethodInfo(typeof(MySandboxGame), "Initialize")]
|
||||
private static MethodInfo _sandboxGameInit;
|
||||
#pragma warning restore 649
|
||||
|
||||
internal static void Inject(PatchContext target)
|
||||
{
|
||||
ConstructorInfo ctor = typeof(MySandboxGame).GetConstructor(new[] { typeof(string[]) });
|
||||
if (ctor == null)
|
||||
throw new ArgumentException("Can't find constructor MySandboxGame(string[])");
|
||||
target.GetPattern(ctor).Prefixes.Add(MethodRef(nameof(PrefixConstructor)));
|
||||
target.GetPattern(ctor).Suffixes.Add(MethodRef(nameof(SuffixConstructor)));
|
||||
target.GetPattern(_sandboxGameInit).Prefixes.Add(MethodRef(nameof(PrefixInit)));
|
||||
target.GetPattern(_sandboxGameInit).Suffixes.Add(MethodRef(nameof(SuffixInit)));
|
||||
target.GetPattern(_sandboxGameDispose).Prefixes.Add(MethodRef(nameof(PrefixDispose)));
|
||||
target.GetPattern(_sandboxGameDispose).Suffixes.Add(MethodRef(nameof(SuffixDispose)));
|
||||
}
|
||||
|
||||
private static MethodInfo MethodRef(string name)
|
||||
{
|
||||
return typeof(GameStateInjector).GetMethod(name,
|
||||
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
}
|
||||
|
||||
private static void PrefixConstructor()
|
||||
{
|
||||
if (Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Creating;
|
||||
}
|
||||
|
||||
private static void SuffixConstructor()
|
||||
{
|
||||
if (Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Created;
|
||||
}
|
||||
|
||||
private static void PrefixInit()
|
||||
{
|
||||
if (Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Loading;
|
||||
}
|
||||
|
||||
private static void SuffixInit()
|
||||
{
|
||||
if (Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Loaded;
|
||||
}
|
||||
|
||||
private static void PrefixDispose()
|
||||
{
|
||||
if (Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Unloading;
|
||||
}
|
||||
|
||||
private static void SuffixDispose()
|
||||
{
|
||||
if (Instance is TorchBase tb)
|
||||
tb.GameState = TorchGameState.Unloaded;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private static readonly HashSet<Assembly> _registeredAssemblies = new HashSet<Assembly>();
|
||||
private static void RegisterCoreAssembly(Assembly asm)
|
||||
{
|
||||
lock (_registeredAssemblies)
|
||||
if (_registeredAssemblies.Add(asm))
|
||||
lock (_registeredCoreAssemblies)
|
||||
if (_registeredCoreAssemblies.Add(asm))
|
||||
{
|
||||
EventManager.AddDispatchShims(asm);
|
||||
PatchManager.AddPatchShims(asm);
|
||||
ReflectedManager.Process(asm);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly HashSet<Assembly> _registeredAuxAssemblies = new HashSet<Assembly>();
|
||||
|
||||
/// <summary>
|
||||
/// Registers an auxillary (plugin) assembly with the system, including its
|
||||
/// <see cref="ReflectedManager"/> related components.
|
||||
/// </summary>
|
||||
/// <param name="asm">Assembly to register</param>
|
||||
internal static void RegisterAuxAssembly(Assembly asm)
|
||||
{
|
||||
lock (_registeredAuxAssemblies)
|
||||
if (_registeredAuxAssemblies.Add(asm))
|
||||
{
|
||||
ReflectedManager.Process(asm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -398,43 +398,20 @@ namespace Torch.Utils
|
||||
/// <summary>
|
||||
/// Automatically calls <see cref="ReflectedManager.Process(Assembly)"/> for every assembly already loaded, and every assembly that is loaded in the future.
|
||||
/// </summary>
|
||||
public class ReflectedManager
|
||||
public static class ReflectedManager
|
||||
{
|
||||
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||
private static readonly string[] _namespaceBlacklist = new[] {
|
||||
"System", "VRage", "Sandbox", "SpaceEngineers", "Microsoft"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Registers the assembly load event and loads every already existing assembly.
|
||||
/// </summary>
|
||||
public void Attach()
|
||||
{
|
||||
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
Process(asm);
|
||||
AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deregisters the assembly load event
|
||||
/// </summary>
|
||||
public void Detach()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomain_AssemblyLoad;
|
||||
}
|
||||
|
||||
private void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
|
||||
{
|
||||
Process(args.LoadedAssembly);
|
||||
}
|
||||
|
||||
private static readonly HashSet<Type> _processedTypes = new HashSet<Type>();
|
||||
|
||||
/// <summary>
|
||||
/// Ensures all reflected fields and methods contained in the given type are initialized
|
||||
/// </summary>
|
||||
/// <param name="t">Type to process</param>
|
||||
public static void Process(Type t)
|
||||
internal static void Process(Type t)
|
||||
{
|
||||
if (_processedTypes.Add(t))
|
||||
{
|
||||
@@ -467,7 +444,7 @@ namespace Torch.Utils
|
||||
/// Ensures all types in the given assembly are initialized using <see cref="Process(Type)"/>
|
||||
/// </summary>
|
||||
/// <param name="asm">Assembly to process</param>
|
||||
public static void Process(Assembly asm)
|
||||
internal static void Process(Assembly asm)
|
||||
{
|
||||
foreach (Type type in asm.GetTypes())
|
||||
Process(type);
|
||||
|
Reference in New Issue
Block a user