using System.Reflection; using HarmonyLib; using PluginLoader.Data; using Sandbox.Game.World; using VRage.Game.Components; using VRage.Plugins; using SEPMPlugin = PluginLoader.SEPM.SEPMPlugin; namespace PluginLoader; public class PluginInstance { private readonly PluginData data; private readonly Assembly mainAssembly; private readonly Type mainType; private IHandleInputPlugin inputPlugin; private MethodInfo openConfigDialog; private IPlugin plugin; private PluginInstance(PluginData data, Assembly mainAssembly, Type mainType) { this.data = data; this.mainAssembly = mainAssembly; this.mainType = mainType; } public string Id => data.Id; public bool HasConfigDialog => openConfigDialog != null; public bool Instantiate() { try { plugin = (IPlugin)Activator.CreateInstance(mainType); inputPlugin = plugin as IHandleInputPlugin; } catch (Exception e) { ThrowError($"Failed to instantiate {data} because of an error: {e}"); return false; } try { openConfigDialog = AccessTools.DeclaredMethod(mainType, "OpenConfigDialog", Array.Empty()); } catch (Exception e) { LogFile.WriteLine($"Unable to find OpenConfigDialog() in {data} due to an error: {e}"); openConfigDialog = null; } return true; } public void OpenConfig() { if (plugin == null || openConfigDialog == null) return; try { openConfigDialog.Invoke(plugin, Array.Empty()); } catch (Exception e) { ThrowError($"Failed to open plugin config for {data} because of an error: {e}"); } } public bool Init(object gameInstance) { if (plugin == null) return false; try { if (plugin is SEPMPlugin sepm) LoaderTools.ExecuteMain(sepm); plugin.Init(gameInstance); return true; } catch (Exception e) { ThrowError($"Failed to initialize {data} because of an error: {e}"); return false; } } public void RegisterSession(MySession session) { if (plugin != null) try { var descType = typeof(MySessionComponentDescriptor); var count = 0; foreach (var t in mainAssembly.GetTypes().Where(t => Attribute.IsDefined(t, descType))) { var comp = (MySessionComponentBase)Activator.CreateInstance(t); session.RegisterComponent(comp, comp.UpdateOrder, comp.Priority); count++; } if (count > 0) LogFile.WriteLine($"Registered {count} session components from: {mainAssembly.FullName}"); } catch (Exception e) { ThrowError($"Failed to register {data} because of an error: {e}"); } } public bool Update() { if (plugin == null) return false; plugin.Update(); return true; } public bool HandleInput() { if (plugin == null) return false; inputPlugin?.HandleInput(); return true; } public void Dispose() { if (plugin != null) try { plugin.Dispose(); plugin = null; inputPlugin = null; } catch (Exception e) { data.Status = PluginStatus.Error; LogFile.WriteLine($"Failed to dispose {data} because of an error: {e}"); } } private void ThrowError(string error) { LogFile.WriteLine(error); data.Error(); Dispose(); } public static bool TryGet(PluginData data, out PluginInstance instance) { instance = null; if (data.Status == PluginStatus.Error || !data.TryLoadAssembly(out var a)) return false; var pluginType = a.GetTypes().FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t)); if (pluginType == null) { LogFile.WriteLine($"Failed to load {data} because it does not contain an IPlugin"); data.Error(); return false; } instance = new(data, a, pluginType); return true; } public override string ToString() { return data.ToString(); } }