Don't crash when modifying constructor

Tweak log level of assembly resolver.
Events relating to game initialization and shutdown.
Plugin manager loads plugins right before the dependency manager is attached.
This commit is contained in:
Westin Miller
2017-09-11 18:28:53 -07:00
parent e57f885d3b
commit 57acb274c6
8 changed files with 152 additions and 8 deletions

View File

@@ -103,6 +103,16 @@ namespace Torch.API
/// Initialize the Torch instance.
/// </summary>
void Init();
/// <summary>
/// The current state of the game this instance of torch is controlling.
/// </summary>
TorchGameState GameState { get; }
/// <summary>
/// Event raised when <see cref="GameState"/> changes.
/// </summary>
event TorchGameStateChangedDel GameStateChanged;
}
/// <summary>
@@ -121,6 +131,6 @@ namespace Torch.API
/// </summary>
public interface ITorchClient : ITorchBase
{
}
}

View File

@@ -186,6 +186,7 @@
<Compile Include="Session\ITorchSession.cs" />
<Compile Include="Session\ITorchSessionManager.cs" />
<Compile Include="Session\TorchSessionState.cs" />
<Compile Include="TorchGameState.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox;
namespace Torch.API
{
/// <summary>
/// Represents the state of a <see cref="MySandboxGame"/>
/// </summary>
public enum TorchGameState
{
/// <summary>
/// The game is currently being created.
/// </summary>
Creating,
/// <summary>
/// The game has been created and is ready to begin loading.
/// </summary>
Created,
/// <summary>
/// The game is currently loading.
/// </summary>
Loading,
/// <summary>
/// The game is fully loaded and ready to start sessions
/// </summary>
Loaded,
/// <summary>
/// The game is beginning the unload sequence
/// </summary>
Unloading,
/// <summary>
/// The game has been shutdown and is no longer active
/// </summary>
Unloaded
}
/// <summary>
/// Callback raised when a game's state changes
/// </summary>
/// <param name="game">The game who had a state change</param>
/// <param name="newState">The game's new state</param>
public delegate void TorchGameStateChangedDel(MySandboxGame game, TorchGameState newState);
}

View File

@@ -95,7 +95,6 @@ namespace Torch.Server
MyGlobalTypeMetadata.Static.Init();
GetManager<InstanceManager>().LoadInstance(Config.InstancePath);
Plugins.LoadPlugins();
}
private void InvokeBeforeRun()

View File

@@ -24,7 +24,7 @@ namespace Torch.Managers.PatchManager.MSIL
{
_module = method.Module;
_genericTypeArgs = method.DeclaringType?.GenericTypeArguments ?? new Type[0];
_genericMethArgs = method.GetGenericArguments();
_genericMethArgs = (method is MethodInfo ? method.GetGenericArguments() : new Type[0]);
}
public MemberInfo ResolveMember(int token)

View File

@@ -148,7 +148,7 @@ namespace Torch.Managers
var dlls = Directory.GetFiles(PluginDir, "*.dll", SearchOption.AllDirectories);
foreach (var dllPath in dlls)
{
_log.Debug($"Loading plugin {dllPath}");
_log.Info($"Loading plugin {dllPath}");
var asm = Assembly.UnsafeLoadFrom(dllPath);
foreach (var type in asm.GetExportedTypes())

View File

@@ -120,12 +120,13 @@ namespace Torch
sessionManager.AddFactory((x) => new EntityManager(this));
Managers.AddManager(sessionManager);
Managers.AddManager(new PatchManager(this));
Managers.AddManager(new KeenLogManager(this));
var patcher = new PatchManager(this);
GameStateInjector.Inject(patcher.AcquireContext());
Managers.AddManager(patcher);
// Managers.AddManager(new KeenLogManager(this));
Managers.AddManager(new FilesystemManager(this));
Managers.AddManager(new UpdateManager(this));
Managers.AddManager(Plugins);
TorchAPI.Instance = this;
}
@@ -269,6 +270,7 @@ namespace Torch
MySession.OnUnloading += OnSessionUnloading;
MySession.OnUnloaded += OnSessionUnloaded;
RegisterVRagePlugin();
Managers.GetManager<PluginManager>().LoadPlugins();
Managers.Attach();
_init = true;
}
@@ -383,5 +385,90 @@ namespace Torch
{
GetManager<IPluginManager>().UpdatePlugins();
}
private TorchGameState _gameState = TorchGameState.Unloaded;
/// <inheritdoc/>
public TorchGameState GameState
{
get => _gameState;
private set
{
_gameState = value;
GameStateChanged?.Invoke(MySandboxGame.Static, _gameState);
Log.Info($"Game state changed {_gameState}");
}
}
/// <inheritdoc/>
public event TorchGameStateChangedDel GameStateChanged;
#region GameStateInjecting
private static class GameStateInjector
{
#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
}
}

View File

@@ -67,7 +67,7 @@ namespace Torch.Utils
string assemblyPath = Path.Combine(path, assemblyName + ".dll");
if (!File.Exists(assemblyPath))
continue;
_log.Debug("Loading {0} from {1}", assemblyName, SimplifyPath(assemblyPath));
_log.Trace("Loading {0} from {1}", assemblyName, SimplifyPath(assemblyPath));
LogManager.Flush();
Assembly asm = Assembly.LoadFrom(assemblyPath);
_assemblies.Add(assemblyName, asm);