using System; using System.Collections.Generic; using System.IO; using System.Reflection; using UnityEngine; namespace BWModLoader { public class ModLoader { public static ModLoader Instance { get; internal set; } private static readonly string dllpath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath; private static readonly string folderPath = Path.GetDirectoryName(dllpath); public static string ModsPath => folderPath + "\\Mods"; public static string AssetsPath => ModsPath + "\\Assets"; public static string LogPath => ModsPath + "\\Logs"; public ModLogger Logger; /// /// All known mods files /// private readonly Dictionary> allMods = new Dictionary>(); /// /// Gets all known mods files /// /// Prevent modification from outside by making copy public Dictionary> GetAllMods() => new Dictionary>(allMods); /// /// GameObject that holds our mods /// public GameObject ModObjects { get; } = new GameObject(); public ModLoader(ModLogger logger) { this.Logger = logger; } /// /// Checks if a mod is loaded /// /// /// public bool IsLoaded(Type mod) { return ModObjects.GetComponent(mod) != null; } /// /// Refresh all known mods /// public void RefreshModFiles() { DirectoryInfo dir = new DirectoryInfo(ModsPath); //Unloads & clears known mods foreach (var mod in allMods) { Unload(mod.Key); } allMods.Clear(); //Find all files to refresh foreach (FileInfo file in dir.GetFiles("*.dll")) { //Save mod types and file path allMods.Add(file, LoadModTypes(file)); Logger.Log("Found dll: " + file.Name); } } /// /// Finds and loads all mod classes in a file /// /// The file to load /// private List LoadModTypes(FileInfo file) { List mods = new List(); try { Assembly modDll = Assembly.LoadFrom(file.FullName); Type[] modType = modDll.GetTypes(); foreach (Type t in modType) { Logger.Log("Found type in " + file.Name + ": " + t.Name); if (t.IsClass && typeof(MonoBehaviour).IsAssignableFrom(t) && !t.IsAbstract && t.IsPublic) { mods.Add(t); } } } catch (Exception e) { Logger.Log("Exception raised while loading mod " + file.Name); Logger.Log(e.Message); Logger.Log("Skipped loading this mod"); } return mods; } /// /// will load a mod from memory /// /// public void Load(FileInfo file) { if (allMods.TryGetValue(file, out var types)) { foreach (Type mod in types) { //if mod is not loaded if (!IsLoaded(mod)) { ModObjects.AddComponent(mod); Logger.Log("Loaded: " + mod.Name + " From file: " + file.Name); } } } } //Unloads a mod from game public void Unload(FileInfo file) { if (allMods.TryGetValue(file, out var types)) { foreach (Type mod in types) { //if mod is loaded if (IsLoaded(mod)) { UnityEngine.Object.Destroy(ModObjects.GetComponent(mod)); Logger.Log("Unloaded: " + mod.Name + " From file: " + file.Name); } } } } } }