@@ -8,7 +8,10 @@ namespace StarMap.Core.ModRepository
88 internal class LoadedModRepository : IDisposable
99 {
1010 private readonly AssemblyLoadContext _coreAssemblyLoadContext ;
11+
1112 private readonly Dictionary < string , StarMapMethodAttribute > _registeredMethodAttributes = [ ] ;
13+ private readonly Dictionary < string , bool > _attemptedMods = [ ] ;
14+ private readonly Dictionary < string , ModAssemblyLoadContext > _modLoadContexts = [ ] ;
1215
1316 private readonly ModRegistry _mods = new ( ) ;
1417 public ModRegistry Mods => _mods ;
@@ -38,23 +41,72 @@ public LoadedModRepository(AssemblyLoadContext coreAssemblyLoadContext)
3841 . ToDictionary ( ) ;
3942 }
4043
41- public void LoadMod ( Mod mod )
44+ public void Init ( )
45+ {
46+ PrepareMods ( ) ;
47+ }
48+
49+ private void PrepareMods ( )
50+ {
51+ ModLibrary . PrepareManifest ( ) ;
52+
53+ var mods = ModLibrary . Manifest . Mods ;
54+ if ( mods is null ) return ;
55+
56+ string rootPath = "Content" ;
57+ string path = Path . Combine ( new ReadOnlySpan < string > ( in rootPath ) ) ;
58+
59+ foreach ( var mod in mods )
60+ {
61+ var modPath = Path . Combine ( path , mod . Id ) ;
62+
63+ if ( ! LoadMod ( mod . Id , modPath ) )
64+ {
65+ _attemptedMods [ mod . Id ] = false ;
66+ continue ;
67+ }
68+
69+ if ( _mods . GetBeforeMainAction ( mod . Id ) is ( object @object , MethodInfo method ) )
70+ {
71+ method . Invoke ( @object , [ ] ) ;
72+ }
73+ _attemptedMods [ mod . Id ] = true ;
74+ }
75+ }
76+
77+ public void ModPrepareSystems ( Mod mod )
4278 {
43- var fullPath = Path . GetFullPath ( mod . DirectoryPath ) ;
44- var filePath = Path . Combine ( fullPath , $ " { mod . Name } .dll" ) ;
45- var folderExists = Directory . Exists ( fullPath ) ;
46- var fileExists = File . Exists ( filePath ) ;
79+ if ( ! _attemptedMods . TryGetValue ( mod . Id , out var succeeded ) )
80+ {
81+ succeeded = LoadMod ( mod . Id , mod . DirectoryPath ) ;
82+ }
4783
48- if ( ! folderExists || ! fileExists ) return ;
84+ if ( ! succeeded ) return ;
85+
86+ if ( _mods . GetPrepareSystemsAction ( mod . Id ) is ( object @object , MethodInfo method ) )
87+ {
88+ method . Invoke ( @object , [ mod ] ) ;
89+ }
90+ }
91+
92+ private bool LoadMod ( string modId , string modDirectory )
93+ {
94+ var fullPath = Path . GetFullPath ( modDirectory ) ;
95+ var modAssemblyFile = Path . Combine ( fullPath , $ "{ modId } .dll") ;
96+ var assemblyExists = File . Exists ( modAssemblyFile ) ;
4997
50- var modLoadContext = new ModAssemblyLoadContext ( mod , _coreAssemblyLoadContext ) ;
51- var modAssembly = modLoadContext . LoadFromAssemblyName ( new AssemblyName ( ) { Name = mod . Name } ) ;
98+ if ( ! assemblyExists ) return false ;
5299
53- var modClass = modAssembly . GetTypes ( ) . FirstOrDefault ( type => type . IsDefined ( typeof ( StarMapModAttribute ) , inherit : false ) ) ;
54- if ( modClass is null ) return ;
100+ var modLoadContext = new ModAssemblyLoadContext ( modId , modDirectory , _coreAssemblyLoadContext ) ;
101+ var modAssembly = modLoadContext . LoadFromAssemblyName ( new AssemblyName ( ) { Name = modId } ) ;
102+
103+ var modClass = modAssembly . GetTypes ( ) . FirstOrDefault ( type => type . GetCustomAttributes ( ) . Any ( attr => attr . GetType ( ) . Name == typeof ( StarMapModAttribute ) . Name ) ) ;
104+ if ( modClass is null ) return false ;
55105
56106 var modObject = Activator . CreateInstance ( modClass ) ;
57- if ( modObject is null ) return ;
107+ if ( modObject is null ) return false ;
108+
109+ _modLoadContexts . Add ( modId , modLoadContext ) ;
58110
59111 var classMethods = modClass . GetMethods ( ) ;
60112 var immediateLoadMethods = new List < MethodInfo > ( ) ;
@@ -73,16 +125,12 @@ public void LoadMod(Mod mod)
73125 immediateLoadMethods . Add ( classMethod ) ;
74126 }
75127
76- _mods . Add ( attr , modObject , classMethod ) ;
128+ _mods . Add ( modId , attr , modObject , classMethod ) ;
77129 }
78130 }
79131
80- foreach ( var method in immediateLoadMethods )
81- {
82- method . Invoke ( modObject , [ mod ] ) ;
83- }
84-
85- Console . WriteLine ( $ "StarMap - Loaded mod: { mod . Name } ") ;
132+ Console . WriteLine ( $ "StarMap - Loaded mod: { modId } from { modAssemblyFile } ") ;
133+ return true ;
86134 }
87135
88136 public void OnAllModsLoaded ( )
@@ -100,6 +148,11 @@ public void Dispose()
100148 method . Invoke ( @object , [ ] ) ;
101149 }
102150
151+ foreach ( var modLoadContext in _modLoadContexts . Values )
152+ {
153+ modLoadContext . Unload ( ) ;
154+ }
155+
103156 _mods . Dispose ( ) ;
104157 }
105158 }
0 commit comments