embed plugin loader directly into the launcher
This commit is contained in:
255
PluginLoader/LoaderTools.cs
Normal file
255
PluginLoader/LoaderTools.cs
Normal file
@@ -0,0 +1,255 @@
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Windows.UI.Popups;
|
||||
using HarmonyLib;
|
||||
using PluginLoader.SEPM;
|
||||
using Sandbox;
|
||||
using Sandbox.Game.World;
|
||||
using Sandbox.Graphics.GUI;
|
||||
using VRage.FileSystem;
|
||||
using VRage.Input;
|
||||
using VRage.Plugins;
|
||||
|
||||
namespace PluginLoader;
|
||||
|
||||
public static class LoaderTools
|
||||
{
|
||||
public static string PluginsDir => Path.GetFullPath(Path.Combine(MyFileSystem.ExePath, "Plugins"));
|
||||
|
||||
public static DialogResult ShowMessageBox(string message, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
{
|
||||
var dialog = new MessageDialog(message, title);
|
||||
|
||||
switch (buttons)
|
||||
{
|
||||
case MessageBoxButtons.OK:
|
||||
dialog.Commands.Add(new UICommand("Ok"));
|
||||
break;
|
||||
case MessageBoxButtons.OKCancel:
|
||||
dialog.Commands.Add(new UICommand("Ok"));
|
||||
dialog.Commands.Add(new UICommand("Cancel"));
|
||||
break;
|
||||
case MessageBoxButtons.AbortRetryIgnore:
|
||||
break;
|
||||
case MessageBoxButtons.YesNoCancel:
|
||||
dialog.Commands.Add(new UICommand("Yes"));
|
||||
dialog.Commands.Add(new UICommand("No"));
|
||||
dialog.Commands.Add(new UICommand("Cancel"));
|
||||
break;
|
||||
case MessageBoxButtons.YesNo:
|
||||
dialog.Commands.Add(new UICommand("Yes"));
|
||||
dialog.Commands.Add(new UICommand("No"));
|
||||
break;
|
||||
case MessageBoxButtons.RetryCancel:
|
||||
dialog.Commands.Add(new UICommand("Retry"));
|
||||
dialog.Commands.Add(new UICommand("Cancel"));
|
||||
break;
|
||||
case MessageBoxButtons.CancelTryContinue:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(buttons), buttons, null);
|
||||
}
|
||||
|
||||
WinRT.Interop.InitializeWithWindow.Initialize(dialog, Process.GetCurrentProcess().MainWindowHandle);
|
||||
|
||||
var result = dialog.ShowAsync().AsTask().Result;
|
||||
|
||||
return buttons switch
|
||||
{
|
||||
MessageBoxButtons.OK => DialogResult.OK,
|
||||
MessageBoxButtons.OKCancel => result.Label == "Ok" ? DialogResult.OK : DialogResult.Cancel,
|
||||
MessageBoxButtons.AbortRetryIgnore => DialogResult.Ignore,
|
||||
MessageBoxButtons.YesNoCancel => result.Label switch
|
||||
{
|
||||
"Yes" => DialogResult.Yes,
|
||||
"No" => DialogResult.No,
|
||||
_ => DialogResult.Cancel
|
||||
},
|
||||
MessageBoxButtons.YesNo => result.Label switch
|
||||
{
|
||||
"Yes" => DialogResult.Yes,
|
||||
_ => DialogResult.No
|
||||
},
|
||||
MessageBoxButtons.RetryCancel => result.Label switch
|
||||
{
|
||||
"Retry" => DialogResult.Retry,
|
||||
_ => DialogResult.Cancel
|
||||
},
|
||||
MessageBoxButtons.CancelTryContinue => DialogResult.Cancel,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(buttons), buttons, null)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static void UnloadAndRestart()
|
||||
{
|
||||
LogFile.Dispose();
|
||||
MySessionLoader.Unload();
|
||||
MySandboxGame.Config.ControllerDefaultOnStart = MyInput.Static.IsJoystickLastUsed;
|
||||
MySandboxGame.Config.Save();
|
||||
MyScreenManager.CloseAllScreensNowExcept(null);
|
||||
MyPlugins.Unload();
|
||||
Restart();
|
||||
}
|
||||
|
||||
public static void Restart()
|
||||
{
|
||||
Application.Restart();
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
|
||||
public static void ExecuteMain(SEPMPlugin plugin)
|
||||
{
|
||||
var name = plugin.GetType().ToString();
|
||||
plugin.Main(new(name), new());
|
||||
}
|
||||
|
||||
public static string GetHash1(string file)
|
||||
{
|
||||
using (var sha = new SHA1Managed())
|
||||
{
|
||||
return GetHash(file, sha);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetHash256(string file)
|
||||
{
|
||||
using (var sha = new SHA256CryptoServiceProvider())
|
||||
{
|
||||
return GetHash(file, sha);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetHash(string file, HashAlgorithm hash)
|
||||
{
|
||||
using (var fileStream = new FileStream(file, FileMode.Open))
|
||||
{
|
||||
using (var bufferedStream = new BufferedStream(fileStream))
|
||||
{
|
||||
var data = hash.ComputeHash(bufferedStream);
|
||||
var sb = new StringBuilder(2 * data.Length);
|
||||
foreach (var b in data)
|
||||
sb.AppendFormat("{0:x2}", b);
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method attempts to disable JIT compiling for the assembly.
|
||||
/// This method will force any member access exceptions by methods to be thrown now instead of later.
|
||||
/// </summary>
|
||||
public static void Precompile(Assembly a)
|
||||
{
|
||||
Type[] types;
|
||||
try
|
||||
{
|
||||
types = a.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException e)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("LoaderExceptions: ");
|
||||
foreach (var e2 in e.LoaderExceptions)
|
||||
sb.Append(e2).AppendLine();
|
||||
LogFile.WriteLine(sb.ToString());
|
||||
throw;
|
||||
}
|
||||
|
||||
foreach (var t in types)
|
||||
{
|
||||
// Static constructors allow for early code execution which can cause issues later in the game
|
||||
if (HasStaticConstructor(t))
|
||||
continue;
|
||||
|
||||
foreach (var m in t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public |
|
||||
BindingFlags.Instance | BindingFlags.Static))
|
||||
{
|
||||
if (m.HasAttribute<HarmonyReversePatch>())
|
||||
throw new("Harmony attribute 'HarmonyReversePatch' found on the method '" + m.Name +
|
||||
"' is not compatible with Plugin Loader!");
|
||||
Precompile(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Precompile(MethodInfo m)
|
||||
{
|
||||
if (!m.IsAbstract && !m.ContainsGenericParameters)
|
||||
RuntimeHelpers.PrepareMethod(m.MethodHandle);
|
||||
}
|
||||
|
||||
private static bool HasStaticConstructor(Type t)
|
||||
{
|
||||
return t.GetConstructors(BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic |
|
||||
BindingFlags.Instance).Any(c => c.IsStatic);
|
||||
}
|
||||
|
||||
|
||||
public static void OpenFileDialog(string title, string directory, string filter, Action<string> onOk)
|
||||
{
|
||||
var t = new Thread(() => OpenFileDialogThread(title, directory, filter, onOk));
|
||||
t.SetApartmentState(ApartmentState.STA);
|
||||
t.Start();
|
||||
}
|
||||
|
||||
private static void OpenFileDialogThread(string title, string directory, string filter, Action<string> onOk)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the file path via prompt
|
||||
using (var openFileDialog = new OpenFileDialog())
|
||||
{
|
||||
if (Directory.Exists(directory))
|
||||
openFileDialog.InitialDirectory = directory;
|
||||
openFileDialog.Title = title;
|
||||
openFileDialog.Filter = filter;
|
||||
openFileDialog.RestoreDirectory = true;
|
||||
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
// Move back to the main thread so that we can interact with keen code again
|
||||
MySandboxGame.Static.Invoke(
|
||||
() => onOk(openFileDialog.FileName),
|
||||
"PluginLoader");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogFile.WriteGameLog("Error while opening file dialog: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenFolderDialog(string title, string directory, Action<string> onOk)
|
||||
{
|
||||
var t = new Thread(() => OpenFolderDialogThread(title, directory, onOk));
|
||||
t.SetApartmentState(ApartmentState.STA);
|
||||
t.Start();
|
||||
}
|
||||
|
||||
private static void OpenFolderDialogThread(string title, string directory, Action<string> onOk)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the file path via prompt
|
||||
using (var openFileDialog = new FolderBrowserDialog())
|
||||
{
|
||||
if (Directory.Exists(directory))
|
||||
openFileDialog.SelectedPath = directory;
|
||||
openFileDialog.Description = title;
|
||||
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
// Move back to the main thread so that we can interact with keen code again
|
||||
MySandboxGame.Static.Invoke(
|
||||
() => onOk(openFileDialog.SelectedPath),
|
||||
"PluginLoader");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogFile.WriteGameLog("Error while opening file dialog: " + e);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user