Files
se-launcher/PluginLoader/Main.cs
2022-11-20 23:02:20 +07:00

234 lines
6.3 KiB
C#

using System.Diagnostics;
using System.Net;
using System.Reflection;
using HarmonyLib;
using PluginLoader.Compiler;
using PluginLoader.Data;
using PluginLoader.GUI;
using PluginLoader.Stats;
using Sandbox.Game.World;
using VRage.Plugins;
using SEPMPlugin = PluginLoader.SEPM.SEPMPlugin;
namespace PluginLoader;
public class Main : IHandleInputPlugin
{
public static Main Instance;
private readonly List<PluginInstance> plugins = new();
private bool init;
public Main()
{
var sw = Stopwatch.StartNew();
Splash = new();
Instance = this;
var temp = Cursor.Current;
Cursor.Current = Cursors.AppStarting;
var pluginsDir = LoaderTools.PluginsDir;
Directory.CreateDirectory(pluginsDir);
LogFile.Init(pluginsDir);
LogFile.WriteLine("Starting - v" + Assembly.GetExecutingAssembly().GetName().Version.ToString(3));
// Fix tls 1.2 not supported on Windows 7 - github.com is tls 1.2 only
try
{
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
}
catch (NotSupportedException e)
{
LogFile.WriteLine("An error occurred while setting up networking, web requests will probably fail: " + e);
}
Splash.SetText("Finding references...");
RoslynReferences.GenerateAssemblyList();
AppDomain.CurrentDomain.AssemblyResolve += ResolveDependencies;
Config = PluginConfig.Load(pluginsDir);
List = new(pluginsDir, Config);
Config.Init(List);
StatsClient.OverrideBaseUrl(Config.StatsServerBaseUrl);
Splash.SetText("Patching...");
LogFile.WriteLine("Patching");
new Harmony("avaness.PluginLoader").PatchAll(Assembly.GetExecutingAssembly());
Splash.SetText("Instantiating plugins...");
LogFile.WriteLine("Instantiating plugins");
foreach (var id in Config)
{
var data = List[id];
if (data is GitHubPlugin github)
github.Init(pluginsDir);
if (PluginInstance.TryGet(data, out var p))
{
plugins.Add(p);
if (data.IsLocal)
HasLocal = true;
}
}
sw.Stop();
// FIXME: It can potentially run in the background speeding up the game's startup
ReportEnabledPlugins();
LogFile.WriteLine($"Finished startup. Took {sw.ElapsedMilliseconds}ms");
Cursor.Current = temp;
Splash.Delete();
Splash = null;
}
public PluginList List { get; }
public PluginConfig Config { get; }
public SplashScreen Splash { get; }
/// <summary>
/// True if a local plugin was loaded
/// </summary>
public bool HasLocal { get; }
// Skip local plugins, keep only enabled ones
public string[] TrackablePluginIds => Config.EnabledPlugins.Where(id => !List[id].IsLocal).ToArray();
public void Init(object gameInstance)
{
LogFile.WriteLine($"Initializing {plugins.Count} plugins");
for (var i = plugins.Count - 1; i >= 0; i--)
{
var p = plugins[i];
if (!p.Init(gameInstance))
plugins.RemoveAtFast(i);
}
init = true;
}
public void Update()
{
if (init)
for (var i = plugins.Count - 1; i >= 0; i--)
{
var p = plugins[i];
if (!p.Update())
plugins.RemoveAtFast(i);
}
}
public void HandleInput()
{
if (init)
for (var i = plugins.Count - 1; i >= 0; i--)
{
var p = plugins[i];
if (!p.HandleInput())
plugins.RemoveAtFast(i);
}
}
public void Dispose()
{
foreach (var p in plugins)
p.Dispose();
plugins.Clear();
AppDomain.CurrentDomain.AssemblyResolve -= ResolveDependencies;
LogFile.Dispose();
Instance = null;
}
public bool TryGetPluginInstance(string id, out PluginInstance instance)
{
instance = null;
if (!init)
return false;
foreach (var p in plugins)
if (p.Id == id)
{
instance = p;
return true;
}
return false;
}
private void ReportEnabledPlugins()
{
if (!PlayerConsent.ConsentGiven)
return;
Splash.SetText("Reporting plugin usage...");
LogFile.WriteLine("Reporting plugin usage");
// Config has already been validated at this point so all enabled plugins will have list items
// FIXME: Move into a background thread
if (StatsClient.Track(TrackablePluginIds))
LogFile.WriteLine("List of enabled plugins has been sent to the statistics server");
else
LogFile.WriteLine("Failed to send the list of enabled plugins to the statistics server");
}
public void RegisterComponents()
{
LogFile.WriteLine($"Registering {plugins.Count} components");
foreach (var plugin in plugins)
plugin.RegisterSession(MySession.Static);
}
public void DisablePlugins()
{
Config.Disable();
plugins.Clear();
LogFile.WriteLine("Disabled all plugins");
}
public void InstantiatePlugins()
{
LogFile.WriteLine($"Loading {plugins.Count} plugins");
for (var i = plugins.Count - 1; i >= 0; i--)
{
var p = plugins[i];
if (!p.Instantiate())
plugins.RemoveAtFast(i);
}
}
private Assembly ResolveDependencies(object sender, ResolveEventArgs args)
{
var assembly = args.RequestingAssembly?.GetName().ToString();
if (args.Name.Contains("0Harmony"))
{
if (assembly != null)
LogFile.WriteLine("Resolving 0Harmony for " + assembly);
else
LogFile.WriteLine("Resolving 0Harmony");
return typeof(Harmony).Assembly;
}
if (args.Name.Contains("SEPluginManager"))
{
if (assembly != null)
LogFile.WriteLine("Resolving SEPluginManager for " + assembly);
else
LogFile.WriteLine("Resolving SEPluginManager");
return typeof(SEPMPlugin).Assembly;
}
return null;
}
}