diff --git a/Torch.API/ITorchBase.cs b/Torch.API/ITorchBase.cs index 6c851ab..c319818 100644 --- a/Torch.API/ITorchBase.cs +++ b/Torch.API/ITorchBase.cs @@ -103,6 +103,16 @@ namespace Torch.API /// Initialize the Torch instance. /// void Init(); + + /// + /// The current state of the game this instance of torch is controlling. + /// + TorchGameState GameState { get; } + + /// + /// Event raised when changes. + /// + event TorchGameStateChangedDel GameStateChanged; } /// @@ -121,6 +131,6 @@ namespace Torch.API /// public interface ITorchClient : ITorchBase { - + } } diff --git a/Torch.API/Torch.API.csproj b/Torch.API/Torch.API.csproj index d771abd..bbf2e3b 100644 --- a/Torch.API/Torch.API.csproj +++ b/Torch.API/Torch.API.csproj @@ -186,6 +186,7 @@ + diff --git a/Torch.API/TorchGameState.cs b/Torch.API/TorchGameState.cs new file mode 100644 index 0000000..5c81393 --- /dev/null +++ b/Torch.API/TorchGameState.cs @@ -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 +{ + /// + /// Represents the state of a + /// + public enum TorchGameState + { + /// + /// The game is currently being created. + /// + Creating, + /// + /// The game has been created and is ready to begin loading. + /// + Created, + /// + /// The game is currently loading. + /// + Loading, + /// + /// The game is fully loaded and ready to start sessions + /// + Loaded, + /// + /// The game is beginning the unload sequence + /// + Unloading, + /// + /// The game has been shutdown and is no longer active + /// + Unloaded + } + + /// + /// Callback raised when a game's state changes + /// + /// The game who had a state change + /// The game's new state + public delegate void TorchGameStateChangedDel(MySandboxGame game, TorchGameState newState); +} diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs index b5dfef4..afd6bfe 100644 --- a/Torch.Server/TorchServer.cs +++ b/Torch.Server/TorchServer.cs @@ -95,7 +95,6 @@ namespace Torch.Server MyGlobalTypeMetadata.Static.Init(); GetManager().LoadInstance(Config.InstancePath); - Plugins.LoadPlugins(); } private void InvokeBeforeRun() diff --git a/Torch/Managers/PatchManager/MSIL/ITokenResolver.cs b/Torch/Managers/PatchManager/MSIL/ITokenResolver.cs index ffaac0a..5b85c93 100644 --- a/Torch/Managers/PatchManager/MSIL/ITokenResolver.cs +++ b/Torch/Managers/PatchManager/MSIL/ITokenResolver.cs @@ -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) diff --git a/Torch/Managers/PluginManager.cs b/Torch/Managers/PluginManager.cs index c6828e2..92112f2 100644 --- a/Torch/Managers/PluginManager.cs +++ b/Torch/Managers/PluginManager.cs @@ -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()) diff --git a/Torch/TorchBase.cs b/Torch/TorchBase.cs index 00cccaa..7bf0b18 100644 --- a/Torch/TorchBase.cs +++ b/Torch/TorchBase.cs @@ -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().LoadPlugins(); Managers.Attach(); _init = true; } @@ -383,5 +385,90 @@ namespace Torch { GetManager().UpdatePlugins(); } + + + private TorchGameState _gameState = TorchGameState.Unloaded; + + /// + public TorchGameState GameState + { + get => _gameState; + private set + { + _gameState = value; + GameStateChanged?.Invoke(MySandboxGame.Static, _gameState); + Log.Info($"Game state changed {_gameState}"); + } + } + + /// + 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 } } diff --git a/Torch/Utils/TorchAssemblyResolver.cs b/Torch/Utils/TorchAssemblyResolver.cs index ca1f6bb..7b558bd 100644 --- a/Torch/Utils/TorchAssemblyResolver.cs +++ b/Torch/Utils/TorchAssemblyResolver.cs @@ -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);