Files
Torch/Piston/PluginManager.cs
2016-09-24 13:08:36 -07:00

169 lines
5.0 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Piston.API;
using PistonAPI;
using Sandbox;
using VRage.Plugins;
using VRage.Collections;
using VRage.Library.Collections;
namespace Piston
{
public class PluginManager
{
//TODO: Disable reloading if the plugin has static elements because they prevent a full reload.
public ListReader<IPlugin> Plugins => MyPlugins.Plugins;
private List<IPlugin> _plugins;
public const string PluginDir = "Plugins";
public PluginManager()
{
if (!Directory.Exists(PluginDir))
Directory.CreateDirectory(PluginDir);
GetPluginList();
}
/// <summary>
/// Get a reference to the internal VRage plugin list.
/// </summary>
private void GetPluginList()
{
_plugins = typeof(MyPlugins).GetField("m_plugins", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as List<IPlugin>;
}
/// <summary>
/// Get a plugin's name from its <see cref="PluginAttribute"/> or its type name.
/// </summary>
public string GetPluginName(Type pluginType)
{
var attr = pluginType.GetCustomAttribute<PluginAttribute>();
return attr?.Name ?? pluginType.Name;
}
/// <summary>
/// Load all plugins in the <see cref="PluginDir"/> folder.
/// </summary>
public void LoadAllPlugins()
{
var pluginFolders = GetPluginFolders();
foreach (var folder in pluginFolders)
{
LoadPluginFolder(folder);
}
}
/// <summary>
/// Load a plugin into the game.
/// </summary>
/// <param name="plugin"></param>
public void LoadPlugin(IPlugin plugin)
{
Logger.Write($"Loading plugin: {GetPluginName(plugin.GetType())}");
plugin.Init(MySandboxGame.Static);
_plugins.Add(plugin);
}
/// <summary>
/// Get the names of all the subfolders in the Plugins directory.
/// </summary>
/// <returns></returns>
public string[] GetPluginFolders()
{
var dirs = Directory.GetDirectories(PluginDir);
for (var i = 0; i < dirs.Length; i++)
{
dirs[i] = dirs[i].Substring(PluginDir.Length + 1);
}
return dirs;
}
/// <summary>
/// Load all plugins in the specified folder.
/// </summary>
/// <param name="folderName">Folder in the <see cref="PluginDir"/> directory</param>
public void LoadPluginFolder(string folderName)
{
var relativeDir = Path.Combine(PluginDir, folderName);
if (!Directory.Exists(relativeDir))
{
Logger.Write($"Plugin {folderName} does not exist in the Plugins folder.");
return;
}
var fileNames = Directory.GetFiles(relativeDir, "*.dll");
foreach (var fileName in fileNames)
{
var fullPath = Path.Combine(Directory.GetCurrentDirectory(), fileName);
UnblockDll(fullPath);
var asm = Assembly.LoadFrom(fullPath);
foreach (var type in asm.GetTypes())
{
if (type.GetInterfaces().Contains(typeof(IPlugin)))
{
var inst = (IPlugin)Activator.CreateInstance(type);
MySandboxGame.Static.Invoke(() => LoadPlugin(inst));
}
}
}
}
/// <summary>
/// Unload a plugin from the game.
/// </summary>
public void UnloadPlugin(IPlugin plugin)
{
_plugins.Remove(plugin);
plugin.Dispose();
}
/// <summary>
/// Reload a plugin.
/// </summary>
/// <param name="plugin"></param>
/// <param name="forceNonPiston">Reload a non-Piston plugin</param>
public void ReloadPlugin(IPlugin plugin, bool forceNonPiston = false)
{
var p = plugin as IPistonPlugin;
if (p == null && forceNonPiston)
{
plugin.Dispose();
plugin.Init(MySandboxGame.Static);
}
else
{
p?.Reload();
}
}
public void ReloadAll()
{
foreach (var plugin in _plugins)
{
var p = plugin as IPistonPlugin;
p?.Reload();
}
}
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteFile(string name);
public bool UnblockDll(string fileName)
{
return DeleteFile(fileName + ":Zone.Identifier");
}
}
}