Updated KD and ModulLoader

This commit is contained in:
Mueller Wayan
2025-05-18 18:05:23 +02:00
parent 47ddfed9bc
commit 1862530728
38 changed files with 602 additions and 360 deletions
+95 -38
View File
@@ -1,4 +1,5 @@
using Firebird2D.Datatypes;
using Firebird2D.DataypesAndInterfaces.Interfaces;
using Firebird2D.Interfaces;
using Firebird2D.Logger;
using Firebird2D.Requirement;
@@ -25,66 +26,122 @@ namespace Firebird2D.ModulLoading
public class ModulLoader
{
private readonly IGame gameInstance;
private static readonly Dictionary<ExtensionDependencyInjection, (Type type, Func<IGame, object> resolver)> providers = new()
{
[ExtensionDependencyInjection.game] = (typeof(IGame), game => game),
[ExtensionDependencyInjection.eventsystem] = (typeof(IEventBus), game => game.EventBus),
[ExtensionDependencyInjection.keymapper] = (typeof(IKeyMapper), game => game.KeyMapper),
};
private ModulList? modulList = null;
public ModulLoader(IGame gameInstance)
{
this.gameInstance = gameInstance;
DeserialiseModulList();
}
public void LoadModules()
public T? LoadSystemComponent<T>(ModuleType moduleType, IGame gameInstance) where T : class
{
DeserialiseModulList();
if (modulList == null) return;
List<Modul> eventModul = modulList.mods.Where(m => m.ModuleType == ModuleType.EventSystem).ToList();
if(modulList?.mods == null || modulList.mods.Count == 0) return null;
if (eventModul.Count > 1) GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Warning, $"More then one EventModul defined first modul ist loaded");
List<Modul> systemModules = modulList.mods.Where(m => m.ModuleType == moduleType).ToList();
if (systemModules.Count > 1) GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Warning, $"More then one {moduleType.ToString()} defined, first loadable modul ist loaded");
if (systemModules.Count < 1) { GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Info, $"No {moduleType.ToString()} is Defined Basic Modul is Loaded"); return null; };
if (eventModul.Count != 0)
for(int i = 0; i < systemModules.Count; i++)
{
try
{
Assembly eventAssembly = Assembly.Load(eventModul[0].RelativePath);
if (string.IsNullOrWhiteSpace(systemModules[i].RelativePath)) continue;
T? modul = LoadModule<T>(moduleType, gameInstance, systemModules[i].RelativePath);
if (modul == null) continue;
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Info, $"{systemModules[i].RelativePath} is loeaded for {moduleType}.");
return modul;
}
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Info, $"F{eventModul[0].Name} loaded.");
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Error, $"None of the defined {moduleType} modules could be loaded.");
LinkEventAssembly(eventAssembly);
}
catch(Exception ex)
return null;
}
public void LoadExtensions(IGame gameInstance)
{
if (modulList?.mods == null || modulList.mods.Count == 0) return;
List<Modul> eventModul = modulList.mods.Where(m => m.ModuleType == ModuleType.Extension).ToList();
foreach (Modul modul in eventModul) {
if (string.IsNullOrWhiteSpace(modul.RelativePath)) continue;
IExtensionBase? extensionBase = LoadModule<IExtensionBase>(ModuleType.Extension, gameInstance, modul.RelativePath);
if (extensionBase != null)
{
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Warning, $"Failed to load {eventModul[0].Name}, with exception {ex.Message}");
extensionBase.Startup();
}
}
else
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Warning, $"More then one EventModul defined first modul ist loaded");
if (modulList.mods.Count == 0) return;
}
private void LinkEventAssembly(Assembly assembly)
{
Type? type = assembly.GetTypes().FirstOrDefault(t => typeof(IEventBus).IsAssignableFrom(t) && !t.IsInterface);
Require.NotNull(type,"type",0);
IEventBus? eventBus = Activator.CreateInstance(type) as IEventBus;
Require.NotNull(eventBus,"eventBus",0);
gameInstance.EventBus = eventBus;
}
private void DeserialiseModulList()
private T? LoadModule<T>(ModuleType moduleType, IGame gameInstance, string modulePath) where T : class
{
try
{
using (FileStream file = new FileStream("Modules/Moduls.xml", FileMode.Open))
string basePath = AppContext.BaseDirectory;
string dllPath = Path.Combine(basePath, modulePath);
Assembly assembly = Assembly.LoadFrom(dllPath);
Type moduleClassType = assembly.GetTypes().First(t => typeof(T).IsAssignableFrom(t));
List<Type> dependencyInjectionTypes = [];
List<Object> dependencyInjections = [];
foreach (var neededParam in moduleType.getNeededDependencyInjection())
{
if (providers.TryGetValue(neededParam, out var entry))
{
dependencyInjectionTypes.Add(entry.type);
dependencyInjections.Add(entry.resolver(gameInstance));
}
else
{
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Warning, $"No provider found for dependency: {neededParam}");
}
}
ConstructorInfo? ctor = moduleClassType.GetConstructor(dependencyInjectionTypes.ToArray());
if (ctor == null)
{
string signature = string.Join(", ", dependencyInjectionTypes.Select(t => t.Name));
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Error, $"No constructor found matching: ({signature})");
return null;
};
T instance = (T)ctor.Invoke(dependencyInjections.ToArray());
Type expectedType = moduleType.getBasicModuleInterfaceType();
if (!expectedType.IsInstanceOfType(instance))
{
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Error, $"Instance does not implement {expectedType.Name}");
return null;
}
return instance;
}
catch (Exception ex)
{
GameLogger.GetInstance(0).Log("ModuleLoader", LogType.Error, $"Error while loading event module {ex.ToString()}");
return null;
}
}
public void DeserialiseModulList()
{
try
{
string path = Path.Combine(AppContext.BaseDirectory, "Modules", "Moduls.xml");
using (FileStream file = new FileStream(path, FileMode.Open))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ModulList));
modulList = (ModulList?)xmlSerializer.Deserialize(file);
@@ -92,7 +149,7 @@ namespace Firebird2D.ModulLoading
}
catch(Exception ex) {
modulList = null;
GameLogger.GetInstance(0).Log("ModulLoader",LogType.Warning, $"Modul file not existing or invalid: {ex.Message}");
GameLogger.GetInstance(0).Log("ModulLoader",LogType.Warning, $"Modul file not existing or invalid: {ex.ToString()}");
}
}
}
+47
View File
@@ -0,0 +1,47 @@
using Firebird2D.DataypesAndInterfaces.Interfaces;
using Firebird2D.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Firebird2D.ModulLoading
{
public enum ModuleType
{
Extension = 0,
EventSystem = 1,
KeyMapper = 2
}
public enum ExtensionDependencyInjection
{
game,
eventsystem,
keymapper
}
public static class ModuleTypeExtensions
{
public static Type getBasicModuleInterfaceType(this ModuleType moduleType)
{
return moduleType switch
{
ModuleType.Extension => typeof(IExtensionBase),
ModuleType.EventSystem => typeof(IEventBus),
ModuleType.KeyMapper => typeof(IKeyMapper)
};
}
public static ExtensionDependencyInjection[] getNeededDependencyInjection(this ModuleType moduleType)
{
return moduleType switch
{
ModuleType.Extension => [ExtensionDependencyInjection.game],
ModuleType.EventSystem => [ ],
ModuleType.KeyMapper => [ExtensionDependencyInjection.eventsystem]
};
}
}
}
+3 -1
View File
@@ -2,7 +2,9 @@
<Moduls>
<!--
<Modul>
<ModuleType>Plugin</ModuleType>
<ModuleType>Extension |
EventSystem |
KeyMapper</ModuleType>
<Name>Logger</Name>
<RelativePath>Modules/Logger</RelativePath>
</Modul>