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);
}
}
}
}
}
}