@@ -35,103 +35,203 @@ public static FolderPath ModsFolder
3535 }
3636 }
3737
38+ private List < string > _modsLoaded ;
39+
3840 // List of all mods loaded in the folder MODS
39- private SFSMod [ ] _modList ;
40- /*public SFSMod[] ModList
41- {
42- get
43- }*/
41+ private Dictionary < string , SFSMod > _modList ;
4442
43+ /// <summary>
44+ /// first method executed. Save loader instance in static var and suscribe to scene event.
45+ /// </summary>
4546 private void Awake ( )
4647 {
4748 Loader . main = this ;
48- this . _modList = new SFSMod [ ] { } ;
4949 this . suscribeOnChangeScene ( this . OnSceneLoaded ) ;
5050 _modsFolder = FileLocations . BaseFolder . Extend ( "MODS" ) . CreateFolder ( ) ;
5151 }
5252
53+ /// <summary>
54+ /// This method start to read mods and is executed automatically when this class is created after Awake method.
55+ /// </summary>
5356 private void Start ( )
5457 {
55- IEnumerable < FolderPath > modsFolders = _modsFolder . GetFoldersInFolder ( false ) ;
56- string basePath = Path . Combine ( FileLocations . BaseFolder , "MODS" ) ;
57- Debug . Log ( "Reading Mods" ) ;
58- Debug . LogError ( new Exception ( "Error custom" ) ) ;
59-
60- foreach ( FolderPath folder in modsFolders )
58+ Debug . Log ( "Reading mods" ) ;
59+ this . _modList = this . getModList ( ) ;
60+ this . _modsLoaded = new List < string > ( ) ;
61+
62+ foreach ( SFSMod mod in this . _modList . Values )
6163 {
62- string fileModPath = Path . Combine ( basePath , folder . FolderName , folder . FolderName + ".dll" ) ;
64+ if ( this . _modsLoaded . Contains ( mod . ModId ) )
65+ {
66+ continue ;
67+ }
68+
6369 try
6470 {
65- SFSMod mod = this . loadMod ( fileModPath ) ;
66- this . _modList . AddItem ( mod ) ;
67- Debug . Log ( mod . Name + " Loaded" ) ;
71+ this . loadMod ( mod ) ;
6872 }
69- catch ( Exception e )
73+ catch ( Exception e )
7074 {
71- Debug . LogError ( "Error Reading " + folder . FolderName + " folder" ) ;
72- Debug . LogError ( e ) ;
75+ Debug . LogException ( e ) ;
7376 }
74-
7577 }
76-
7778 }
7879
79- private void OnSceneLoaded ( Scene scene , LoadSceneMode mode )
80+ /// <summary>
81+ /// get mod instance.
82+ /// </summary>
83+ /// <param name="modId">Mod ID you need</param>
84+ /// <returns>instance mod</returns>
85+ public SFSMod getMod ( string modId )
8086 {
81- Debug . Log ( "Scene change to " + scene . name ) ;
87+ return this . _modList [ modId ] ;
8288 }
8389
84- public bool suscribeOnChangeScene ( UnityAction < Scene , LoadSceneMode > method )
90+ /// <summary>
91+ /// This method read MODS folder and identify what is the entry point for each folder.
92+ /// </summary>
93+ /// <returns> dictionary whit modid as key and SFSMod instance as value</returns>
94+ private Dictionary < string , SFSMod > getModList ( )
8595 {
86- SceneManager . sceneLoaded += method ;
87- return true ;
88- }
96+ Dictionary < string , SFSMod > modList = new Dictionary < string , SFSMod > ( ) ;
8997
90- private SFSMod loadMod ( string path )
91- {
92- Assembly assembly = Assembly . LoadFrom ( path ) ;
93- SFSMod mod = null ;
98+ // get list of mod Folders in MODS folder
99+ IEnumerable < FolderPath > modsFolders = _modsFolder . GetFoldersInFolder ( false ) ;
100+ string basePath = Path . Combine ( FileLocations . BaseFolder , "MODS" ) ;
94101
95- foreach ( Type typeClass in assembly . GetTypes ( ) )
102+ foreach ( FolderPath folder in modsFolders )
96103 {
97- if ( typeClass . IsSubclassOf ( typeof ( SFSMod ) ) )
104+ string fileModPath = Path . Combine ( basePath , folder . FolderName , folder . FolderName + ".dll" ) ;
105+ try
98106 {
99- mod = ( Activator . CreateInstance ( typeClass ) as SFSMod ) ;
100- break ;
107+ // get mod assembly
108+ Assembly assembly = Assembly . LoadFrom ( fileModPath ) ;
109+ SFSMod mod = null ;
110+
111+ // verfiy if hace SFSMod class
112+ foreach ( Type typeClass in assembly . GetTypes ( ) )
113+ {
114+ if ( typeClass . IsSubclassOf ( typeof ( SFSMod ) ) )
115+ {
116+ mod = ( Activator . CreateInstance ( typeClass ) as SFSMod ) ;
117+ break ;
118+ }
119+
120+ }
121+
122+ if ( mod == null )
123+ {
124+ throw new Exception ( folder . FolderName + " entry point not found" ) ;
125+
126+ }
127+
128+ if ( modList . ContainsKey ( mod . ModId ) )
129+ {
130+ throw new Exception ( "Already existe another mod whit id " + mod . ModId ) ;
131+ }
132+
133+ modList . Add ( mod . ModId , mod ) ;
101134 }
102-
135+ catch ( Exception e )
136+ {
137+ Debug . LogException ( e ) ;
138+ }
139+
103140 }
141+ return modList ;
142+ }
104143
105- if ( mod == null )
144+ /// <summary>
145+ /// Load mod dependecies and chec if is already loaded and check their version.
146+ /// </summary>
147+ /// <param name="dependencies"> list of dependecies that you need to load first</param>
148+ /// <returns> true if all dependecies have been loaded </returns>
149+ private bool loadDependencies ( SFSModDependencie [ ] dependencies )
150+ {
151+ // for each mod dependencie
152+ foreach ( SFSModDependencie dependencie in dependencies )
106153 {
107- throw new Exception ( "SFSmod class not found" ) ;
154+ // exist mod in the list?
155+ if ( this . _modList . ContainsKey ( dependencie . ModId ) )
156+ {
157+ // get mod dependecie
158+ SFSMod dependencieMod = this . _modList [ dependencie . ModId ] ;
159+
160+ // verify if the dependencie version is the same that mod need
161+ bool versionFlag = false ;
162+ foreach ( string version in dependencie . Versions )
163+ {
164+ if ( verifyVersion ( dependencieMod . Version , version ) )
165+ {
166+ versionFlag = true ;
167+ break ;
168+ }
169+ }
170+
171+ // the version is valid
172+ if ( versionFlag )
173+ {
174+ // start load dependencie first
175+ this . loadMod ( dependencieMod ) ;
176+ continue ;
177+ }
178+ }
179+ // dependencie not exist or is diferent version
180+ throw new Exception ( "Is necesary install " + dependencie . ModId + " " + string . Join ( ", " , dependencie . Versions ) ) ;
108181 }
182+ return true ;
183+ }
184+
185+ /// <summary>
186+ /// start to check version mod and run load method
187+ /// </summary>
188+ /// <param name="mod">mod to start load</param>
189+ private void loadMod ( SFSMod mod )
190+ {
191+ // this mod has been load?, if not start load
192+ if ( this . _modsLoaded . Contains ( mod . ModId ) )
193+ {
194+ return ;
195+ }
196+
197+ Debug . Log ( "Loading " + mod . Name ) ;
198+ this . _modsLoaded . Add ( mod . ModId ) ;
109199
110- if ( verifyModLoaderVersion ( mod . ModLoderVersion ) )
200+ // check if the version is valid for this modloader version
201+ if ( verifyVersion ( mod . ModLoderVersion , modLoderVersion ) )
111202 {
203+ // Have dependencies?
204+ if ( mod . Dependencies != null )
205+ {
206+ // load them
207+ this . loadDependencies ( mod . Dependencies ) ;
208+ }
209+
112210 mod . loadAssets ( ) ;
113211 mod . load ( ) ;
114-
115- return mod ;
212+ return ;
116213 }
117- throw new Exception ( mod . Name + " need ModLoader " + mod . Version ) ;
214+
215+ // the mod loader version is not valid
216+ throw new Exception ( mod . Name + " need ModLoader " + mod . Version ) ;
118217 }
119218
120219 /// <summary>
121- /// get if the mod have a valid version format and valid version for this modloader version
220+ /// check two versions string to identify if are the same
122221 /// </summary>
123- /// <param name="version"> mod version</param>
124- /// <returns>true if valid version</returns>
125- private bool verifyModLoaderVersion ( string version )
222+ /// <param name="version1"> version to check</param>
223+ /// <param name="version2"> verison to check</param>
224+ /// <returns>true if are valid versions</returns>
225+ private bool verifyVersion ( string version1 , string version2 )
126226 {
127227 Regex rx = new Regex ( @"\bv([0-9]|[1-9][0-9]).([0-9]|[1-9][0-9]|x).([0-9]|[1-9][0-9]|x)\b" , RegexOptions . Compiled | RegexOptions . IgnoreCase ) ;
128228 // have the formal v1.x.x
129- if ( rx . IsMatch ( version ) )
229+ if ( rx . IsMatch ( version1 ) && rx . IsMatch ( version2 ) )
130230 {
131- string [ ] modVersion = version . Split ( '.' ) ;
132- string [ ] target = modLoderVersion . Split ( '.' ) ;
133-
134- if ( modVersion . Length == target . Length )
231+ string [ ] modVersion = version1 . Split ( '.' ) ;
232+ string [ ] target = version2 . Split ( '.' ) ;
233+
234+ if ( modVersion . Length == target . Length )
135235 {
136236 for ( short index = 0 ; index < target . Length ; index ++ )
137237 {
@@ -145,13 +245,30 @@ private bool verifyModLoaderVersion(string version)
145245 }
146246 }
147247 // have the format and is valid version for this modloader version
148- return true ;
248+ return true ;
149249
150250 }
151-
251+
152252 }
153253 return false ;
154- }
254+ }
255+
256+ private void OnSceneLoaded ( Scene scene , LoadSceneMode mode )
257+ {
258+ Debug . Log ( "Scene change to " + scene . name ) ;
259+ }
260+
261+ /// <summary>
262+ /// suscribe to scene change event
263+ /// </summary>
264+ /// <param name="method">method what do you want to suscribe</param>
265+ /// <returns>true if subscribed</returns>
266+ public bool suscribeOnChangeScene ( UnityAction < Scene , LoadSceneMode > method )
267+ {
268+ SceneManager . sceneLoaded += method ;
269+ return true ;
270+ }
271+
155272
156273 /// <summary>
157274 /// This is the mod loader entry point, this is the method execute after be injected in the game
0 commit comments