diff --git a/Torch.API/IPluginManager.cs b/Torch.API/IPluginManager.cs index 32e30e9..6d7bf2f 100644 --- a/Torch.API/IPluginManager.cs +++ b/Torch.API/IPluginManager.cs @@ -7,6 +7,7 @@ namespace Torch.API { public interface IPluginManager : IEnumerable { - + void UpdatePlugins(); + void LoadPlugins(); } } \ No newline at end of file diff --git a/Torch.API/ITorchPlugin.cs b/Torch.API/ITorchPlugin.cs index 21d7026..31adc91 100644 --- a/Torch.API/ITorchPlugin.cs +++ b/Torch.API/ITorchPlugin.cs @@ -12,7 +12,6 @@ namespace Torch.API Guid Id { get; } Version Version { get; } string Name { get; } - bool Enabled { get; set; } void Init(ITorchBase torchBase); void Update(); diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs index 027f6d5..13de69f 100644 --- a/Torch.Server/TorchServer.cs +++ b/Torch.Server/TorchServer.cs @@ -23,7 +23,7 @@ namespace Torch.Server { public class TorchServer : TorchBase, ITorchServer { - public Thread ServerThread { get; private set; } + public Thread GameThread { get; private set; } public bool IsRunning { get; private set; } public event Action SessionLoading; @@ -66,7 +66,7 @@ namespace Torch.Server private void OnSessionReady() { - Plugins.LoadAllPlugins(); + Plugins.LoadPlugins(); InvokeSessionLoaded(); } @@ -92,7 +92,7 @@ namespace Torch.Server /// public override void Stop() { - if (Thread.CurrentThread.ManagedThreadId != ServerThread?.ManagedThreadId) + if (Thread.CurrentThread.ManagedThreadId != GameThread?.ManagedThreadId) { Log.Write("Requesting server stop."); MySandboxGame.Static.Invoke(Stop); diff --git a/Torch/Managers/NetworkManager/NetworkManager.cs b/Torch/Managers/NetworkManager/NetworkManager.cs index ec3fb9f..a6e4d03 100644 --- a/Torch/Managers/NetworkManager/NetworkManager.cs +++ b/Torch/Managers/NetworkManager/NetworkManager.cs @@ -233,7 +233,7 @@ namespace Torch.Managers /// public void RaiseEvent(MethodInfo method, object obj, ulong steamId, params object[] args) { - RaiseEvent(method,obj,new EndpointId(steamId), args); + RaiseEvent(method, obj, new EndpointId(steamId), args); } /// @@ -252,7 +252,7 @@ namespace Torch.Managers throw new ArgumentOutOfRangeException(nameof(args), "Cannot pass more than 6 arguments!"); var owner = obj as IMyEventOwner; - if (obj != null && owner == null ) + if (obj != null && owner == null) throw new InvalidCastException("Provided event target is not of type IMyEventOwner!"); if(!method.HasAttribute()) @@ -261,7 +261,7 @@ namespace Torch.Managers //array to hold arguments to pass into DispatchEvent object[] arguments = new object[11]; - arguments[0] = (obj == null ? TryGetStaticCallSite(method) : TryGetCallSite(method, obj)); + arguments[0] = obj == null ? TryGetStaticCallSite(method) : TryGetCallSite(method, obj); arguments[1] = endpoint; arguments[2] = 1f; arguments[3] = owner; diff --git a/Torch/PluginManager.cs b/Torch/PluginManager.cs index a55decb..ac6fc2a 100644 --- a/Torch/PluginManager.cs +++ b/Torch/PluginManager.cs @@ -10,6 +10,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Sandbox; +using Sandbox.ModAPI; using Torch.API; using VRage.Plugins; using VRage.Collections; @@ -17,19 +18,63 @@ using VRage.Library.Collections; namespace Torch { + internal class TorchPluginUpdater : IPlugin + { + private readonly IPluginManager _manager; + public TorchPluginUpdater(IPluginManager manager) + { + _manager = manager; + } + + public void Init(object obj) { } + + public void Update() + { + _manager.UpdatePlugins(); + } + + public void Dispose() { } + } + public class PluginManager : IPluginManager { private readonly ITorchBase _torch; public const string PluginDir = "Plugins"; - private readonly List _plugins = new List(); + private readonly List _plugins = new List(); + private readonly TorchPluginUpdater _updater; public PluginManager(ITorchBase torch) { _torch = torch; + _updater = new TorchPluginUpdater(this); if (!Directory.Exists(PluginDir)) Directory.CreateDirectory(PluginDir); + + InitUpdater(); + } + + private void InitUpdater() + { + var pluginList = typeof(MyPlugins).GetField("m_plugins", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as List; + if (pluginList == null) + throw new TypeLoadException($"m_plugins field not found in {nameof(MyPlugins)}"); + + pluginList.Add(_updater); + } + + public void UpdatePlugins() + { + Parallel.ForEach(_plugins, p => p.Update()); + } + + public void UnloadPlugins() + { + foreach (var plugin in _plugins) + plugin.Unload(); + + _plugins.Clear(); } /// @@ -46,41 +91,12 @@ namespace Torch foreach (var type in asm.GetExportedTypes()) { - if (type.IsSubclassOf(typeof(TorchPluginBase))) - _plugins.Add((TorchPluginBase)Activator.CreateInstance(type)); + if (type.GetInterfaces().Contains(typeof(ITorchPlugin))) + _plugins.Add((ITorchPlugin)Activator.CreateInstance(type)); } } } - public async void ReloadPluginAsync(ITorchPlugin plugin) - { - var p = plugin as TorchPluginBase; - if (p == null) - return; - - var newPlugin = (TorchPluginBase)Activator.CreateInstance(p.GetType()); - _plugins.Add(newPlugin); - - await p.StopAsync(); - _plugins.Remove(p); - - newPlugin.Run(_torch, true); - } - - public void StartEnabledPlugins() - { - foreach (var plugin in _plugins) - { - if (plugin.Enabled) - plugin.Run(_torch); - } - } - - public bool UnblockDll(string fileName) - { - return DeleteFile(fileName + ":Zone.Identifier"); - } - public IEnumerator GetEnumerator() { return _plugins.GetEnumerator(); @@ -91,6 +107,15 @@ namespace Torch return GetEnumerator(); } + /// + /// Removes the lock on a DLL downloaded from the internet. + /// + /// + public bool UnblockDll(string fileName) + { + return DeleteFile(fileName + ":Zone.Identifier"); + } + [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DeleteFile(string name); diff --git a/Torch/Reflection.cs b/Torch/Reflection.cs index 670db93..e624b6a 100644 --- a/Torch/Reflection.cs +++ b/Torch/Reflection.cs @@ -10,13 +10,8 @@ namespace Torch public static class Reflection { //private static readonly Logger Log = LogManager.GetLogger( "BaseLog" ); - public static bool HasMethod(Type objectType, string methodName) - { - return HasMethod(objectType, methodName, null); - } - - public static bool HasMethod(Type objectType, string methodName, Type[] argTypes) + public static bool HasMethod(Type objectType, string methodName, Type[] argTypes = null) { try { diff --git a/Torch/TorchPluginBase.cs b/Torch/TorchPluginBase.cs index 97540fa..9fd0625 100644 --- a/Torch/TorchPluginBase.cs +++ b/Torch/TorchPluginBase.cs @@ -16,8 +16,6 @@ namespace Torch public Guid Id { get; } public Version Version { get; } public string Name { get; } - public bool Enabled { get; set; } = true; - public bool IsRunning => !Loop.IsCompleted; public ITorchBase Torch { get; private set; } protected TorchPluginBase() @@ -50,57 +48,5 @@ namespace Torch public abstract void Update(); public abstract void Unload(); - - #region Internal Loop Code - - internal CancellationTokenSource ctSource = new CancellationTokenSource(); - - internal Task Loop { get; private set; } = Task.CompletedTask; - private readonly TimeSpan _loopInterval = TimeSpan.FromSeconds(1d / 60d); - private bool _runLoop; - internal Task Run(ITorchBase torch, bool enable = false) - { - if (IsRunning) - throw new InvalidOperationException($"Plugin {Name} is already running."); - - if (!Enabled) - return Loop = Task.CompletedTask; - - _runLoop = true; - return Loop = Task.Run(() => - { - try - { - Init(torch); - - while (Enabled && !ctSource.Token.IsCancellationRequested) - { - ctSource.Token.ThrowIfCancellationRequested(); - var ts = Stopwatch.GetTimestamp(); - Update(); - var time = TimeSpan.FromTicks(Stopwatch.GetTimestamp() - ts); - - if (time < _loopInterval) - Task.Delay(_loopInterval - time); - } - - Unload(); - } - catch (Exception e) - { - torch.Log.Write($"Plugin {Name} threw an exception."); - torch.Log.WriteException(e); - throw; - } - }); - } - - internal async Task StopAsync() - { - ctSource.Cancel(); - await Loop; - } - - #endregion } }