Mercurial > repos > IBBoard.WarFoundry.API
comparison api/WarFoundryLoader.cs @ 14:0770e5cbba7c
Closes #21 - File loading in order
* Reworked LoadFiles to smaller methods for readability (also re #10) and structure
* Now determine expected load return before loading then load all "expected GameSystem" before "expected Race"
* Make "can load as race/game system/army" methods public in interface
Re #22 - Get errored file loading
* Created FileLoadFailure class and made LoadFiles return a list of them
Also
* Some code cleanup
* Change to DictionaryUtils calls
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sun, 25 Jan 2009 14:03:20 +0000 |
parents | 613bc5eaac59 |
children | 306558904c2a |
comparison
equal
deleted
inserted
replaced
13:ad8eaed12e66 | 14:0770e5cbba7c |
---|---|
150 } | 150 } |
151 | 151 |
152 /// <summary> | 152 /// <summary> |
153 /// Loads all of the data files in the registered directories. | 153 /// Loads all of the data files in the registered directories. |
154 /// </summary> | 154 /// </summary> |
155 public void LoadFiles() | 155 /// <returns> |
156 /// A <see cref="Dictionary"/> of files that failed to load mapped against the message that their failure returned | |
157 /// </returns> | |
158 public List<FileLoadFailure> LoadFiles() | |
156 { | 159 { |
157 LogNotifier.Debug(GetType(), "Load files"); | 160 LogNotifier.Debug(GetType(), "Load files"); |
158 PrepareForFileLoad(); | 161 PrepareForFileLoad(); |
159 | 162 Dictionary<FileInfo, IWarFoundryFactory> loadableRaces = new Dictionary<FileInfo, IWarFoundryFactory>(); |
160 foreach (DirectoryInfo directory in directories) | 163 Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems = new Dictionary<FileInfo, IWarFoundryFactory>(); |
161 { | 164 List<FileLoadFailure> failedLoads = FillLoadableFiles(loadableRaces, loadableGameSystems); |
162 if (directory.Exists) | 165 failedLoads.AddRange(LoadGameSystems(loadableGameSystems)); |
163 { | 166 failedLoads.AddRange(LoadRaces(loadableRaces)); |
164 LogNotifier.Debug(GetType(), "Load from "+directory.FullName); | 167 |
165 | 168 LogNotifier.Debug(GetType(), failedLoads.Count + " failed file loads"); |
166 foreach (FileInfo file in directory.GetFiles()) | 169 |
167 { | 170 return failedLoads; |
168 LoadFile(file); | |
169 } | |
170 } | |
171 else | |
172 { | |
173 LogNotifier.WarnFormat(GetType(), "Load for {0} failed because directory didn't exist", directory.FullName); | |
174 } | |
175 } | |
176 | |
177 ICollection<Race> races = new List<Race>(); | |
178 | |
179 foreach (SimpleSet<IWarFoundryObject> objs in loadedObjects.Values) | |
180 { | |
181 foreach (IWarFoundryObject obj in objs) | |
182 { | |
183 if (obj is Race) | |
184 { | |
185 races.Add((Race)obj); | |
186 } | |
187 else if (obj is GameSystem) | |
188 { | |
189 StoreGameSystem((GameSystem)obj); | |
190 } | |
191 } | |
192 } | |
193 | |
194 foreach (Race race in races) | |
195 { | |
196 StoreRace(race); | |
197 } | |
198 } | 171 } |
199 | 172 |
200 protected void PrepareForFileLoad() | 173 protected void PrepareForFileLoad() |
201 { | 174 { |
202 //Just set up blank dictionaries for now - may try different and more complex handling in future | 175 //Just set up blank dictionaries for now - may try different and more complex handling in future |
203 systemsTable = new Dictionary<string,GameSystem>(); | 176 systemsTable = new Dictionary<string,GameSystem>(); |
204 racesTable = new Dictionary<string,Dictionary<string,Dictionary<string,Race>>>(); | 177 racesTable = new Dictionary<string,Dictionary<string,Dictionary<string,Race>>>(); |
205 } | 178 } |
179 | |
180 private List<FileLoadFailure> FillLoadableFiles(Dictionary<FileInfo, IWarFoundryFactory> loadableRaces, Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems) | |
181 { | |
182 List<FileLoadFailure> fails = new List<FileLoadFailure>(); | |
183 | |
184 foreach (DirectoryInfo directory in directories) | |
185 { | |
186 if (directory.Exists) | |
187 { | |
188 List<FileLoadFailure> directoryFails = FillLoadableFilesForDirectory(loadableRaces, loadableGameSystems, directory); | |
189 fails.AddRange(directoryFails); | |
190 } | |
191 else | |
192 { | |
193 LogNotifier.WarnFormat(GetType(), "Load for {0} failed because directory didn't exist", directory.FullName); | |
194 } | |
195 } | |
196 | |
197 return fails; | |
198 } | |
199 | |
200 private List<FileLoadFailure> FillLoadableFilesForDirectory(Dictionary<FileInfo, IWarFoundryFactory> loadableRaces, Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems, DirectoryInfo directory) | |
201 { | |
202 List<FileLoadFailure> fails = new List<FileLoadFailure>(); | |
203 LogNotifier.Debug(GetType(), "Load from "+directory.FullName); | |
204 | |
205 foreach (FileInfo file in directory.GetFiles()) | |
206 { | |
207 IWarFoundryFactory factory = GetGameSystemRaceLoadingFactoryForFile(file); | |
208 | |
209 if (factory != null) | |
210 { | |
211 loadableGameSystems.Add(file, factory); | |
212 } | |
213 else | |
214 { | |
215 factory = GetRaceLoadingFactoryForFile(file); | |
216 | |
217 if (factory!=null) | |
218 { | |
219 loadableRaces.Add(file, factory); | |
220 } | |
221 else | |
222 { | |
223 fails.Add(new FileLoadFailure(file, "FileNotHandled", "File not handled as a Race or Game System definition: {0}")); | |
224 } | |
225 } | |
226 } | |
227 | |
228 return fails; | |
229 } | |
230 | |
231 private IWarFoundryFactory GetGameSystemRaceLoadingFactoryForFile(FileInfo file) | |
232 { | |
233 IWarFoundryFactory loadingFactory = null; | |
234 | |
235 foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) | |
236 { | |
237 if (factory.CanHandleFileAsGameSystem(file)) | |
238 { | |
239 loadingFactory = factory; | |
240 break; | |
241 } | |
242 } | |
243 | |
244 if (loadingFactory == null) | |
245 { | |
246 foreach (INativeWarFoundryFactory factory in factories) | |
247 { | |
248 if (factory.CanHandleFileAsGameSystem(file)) | |
249 { | |
250 loadingFactory = factory; | |
251 break; | |
252 } | |
253 } | |
254 } | |
255 | |
256 return loadingFactory; | |
257 } | |
258 | |
259 private IWarFoundryFactory GetRaceLoadingFactoryForFile(FileInfo file) | |
260 { | |
261 IWarFoundryFactory loadingFactory = null; | |
262 | |
263 foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) | |
264 { | |
265 if (factory.CanHandleFileAsRace(file)) | |
266 { | |
267 loadingFactory = factory; | |
268 break; | |
269 } | |
270 } | |
271 | |
272 if (loadingFactory == null) | |
273 { | |
274 foreach (INativeWarFoundryFactory factory in factories) | |
275 { | |
276 if (factory.CanHandleFileAsRace(file)) | |
277 { | |
278 loadingFactory = factory; | |
279 break; | |
280 } | |
281 } | |
282 } | |
283 | |
284 return loadingFactory; | |
285 } | |
286 | |
287 private List<FileLoadFailure> LoadGameSystems(Dictionary<FileInfo, IWarFoundryFactory> gameSystemFiles) | |
288 { | |
289 List<FileLoadFailure> fails = new List<FileLoadFailure>(); | |
290 | |
291 | |
292 foreach (FileInfo file in gameSystemFiles.Keys) | |
293 { | |
294 try | |
295 { | |
296 bool loaded = LoadObject(file, gameSystemFiles[file]); | |
297 | |
298 if (!loaded) | |
299 { | |
300 fails.Add(new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}")); | |
301 } | |
302 } | |
303 catch (Exception ex) | |
304 { | |
305 fails.Add(new FileLoadFailure(file, ex.Message)); | |
306 } | |
307 } | |
308 | |
309 return fails; | |
310 } | |
311 | |
312 private List<FileLoadFailure> LoadRaces(Dictionary<FileInfo, IWarFoundryFactory> raceFiles) | |
313 { | |
314 List<FileLoadFailure> fails = new List<FileLoadFailure>(); | |
315 | |
316 foreach (FileInfo file in raceFiles.Keys) | |
317 { | |
318 try | |
319 { | |
320 bool loaded = LoadObject(file, raceFiles[file]); | |
321 | |
322 if (!loaded) | |
323 { | |
324 fails.Add(new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}")); | |
325 } | |
326 } | |
327 catch (Exception ex) | |
328 { | |
329 fails.Add(new FileLoadFailure(file, ex.Message)); | |
330 } | |
331 } | |
332 | |
333 return fails; | |
334 } | |
335 | |
336 private bool LoadObject(FileInfo file, IWarFoundryFactory factory) | |
337 { | |
338 bool loaded = false; | |
339 | |
340 LogNotifier.DebugFormat(GetType(), "Loading {0} using {1}", file.FullName, factory.GetType().Name); | |
341 ICollection<IWarFoundryObject> objects = factory.CreateObjectsFromFile(file); | |
342 | |
343 if (objects.Count > 0) | |
344 { | |
345 AddLoadedObjects(objects, factory); | |
346 loaded = true; | |
347 } | |
348 | |
349 return loaded; | |
350 } | |
351 | |
206 | 352 |
207 /// <summary> | 353 /// <summary> |
208 /// Loads a single file through the registered WarFoundryFactories, if a factory exists that supports the file format. | 354 /// Loads a single file through the registered WarFoundryFactories, if a factory exists that supports the file format. |
209 /// </summary> | 355 /// </summary> |
210 /// <param name="file"> | 356 /// <param name="file"> |
211 /// A <see cref="FileInfo"/> for the file to attempt to load | 357 /// A <see cref="FileInfo"/> for the file to attempt to load |
212 /// </param> | 358 /// </param> |
213 protected void LoadFile(FileInfo file) | 359 /// <returns> |
214 { | 360 /// An ICollection of IWarFoundryObjects loaded from <code>file</code> |
215 bool handled = false; | 361 /// </returns> |
216 | 362 public ICollection<IWarFoundryObject> LoadFile(FileInfo file) |
217 if (!handled) | 363 { |
218 { | 364 ICollection<IWarFoundryObject> objs = null; |
219 ICollection<IWarFoundryObject> objs = null; | 365 IWarFoundryFactory loadFactory = null; |
220 IWarFoundryFactory loadFactory = null; | 366 |
367 if (nonNativeFactories.Count > 0) | |
368 { | |
369 LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as a non-native file"); | |
221 | 370 |
222 if (nonNativeFactories.Count > 0) | 371 foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) |
223 { | 372 { |
224 LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as a non-native file"); | 373 bool canLoad = factory.CanHandleFileFormat(file); |
374 LogNotifier.Debug(GetType(), "Load using "+factory.GetType().FullName+"? " + (canLoad ? "yes" : "no")); | |
225 | 375 |
226 foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) | 376 if (canLoad) |
227 { | 377 { |
228 LogNotifier.Debug(GetType(), "Load using "+factory.GetType().AssemblyQualifiedName+"? " + (factory.CanHandleFileFormat(file) ? "yes" : "no")); | 378 objs = factory.CreateObjectsFromFile(file); |
229 | 379 |
230 if (factory.CanHandleFileFormat(file)) | 380 if (objs!=null) |
231 { | 381 { |
232 objs = factory.CreateObjectsFromFile(file); | 382 loadFactory = factory; |
233 | 383 break; |
234 if (objs!=null) | 384 } |
235 { | 385 } |
236 loadFactory = factory; | 386 } |
237 break; | 387 } |
238 } | 388 |
239 } | 389 if (objs == null) |
240 } | 390 { |
241 } | 391 LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as native file"); |
242 | 392 |
243 if (objs == null) | 393 foreach (INativeWarFoundryFactory factory in factories) |
244 { | 394 { |
245 LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as native file"); | 395 if (factory.CanHandleFileFormat(file)) |
246 | |
247 foreach (INativeWarFoundryFactory factory in factories) | |
248 { | 396 { |
249 if (factory.CanHandleFileFormat(file)) | 397 objs = factory.CreateObjectsFromFile(file); |
398 | |
399 if (objs!=null) | |
250 { | 400 { |
251 objs = factory.CreateObjectsFromFile(file); | 401 loadFactory = factory; |
252 | 402 break; |
253 if (objs!=null) | |
254 { | |
255 loadFactory = factory; | |
256 break; | |
257 } | |
258 } | 403 } |
259 } | 404 } |
260 } | 405 } |
261 | 406 } |
262 if (objs!=null) | 407 |
263 { | 408 if (objs!=null) |
264 AddLoadedObjects(objs, loadFactory); | 409 { |
265 } | 410 AddLoadedObjects(objs, loadFactory); |
266 } | 411 } |
412 else | |
413 { | |
414 LogNotifier.Debug(GetType(), "Loading of "+file.FullName+" failed"); | |
415 objs = new List<IWarFoundryObject>(); | |
416 } | |
417 | |
418 return objs; | |
267 } | 419 } |
268 | 420 |
269 private void AddLoadedObjects(ICollection<IWarFoundryObject> loadedObjs, IWarFoundryFactory factory) | 421 private void AddLoadedObjects(ICollection<IWarFoundryObject> loadedObjs, IWarFoundryFactory factory) |
270 { | 422 { |
271 SimpleSet<IWarFoundryObject> objs; | 423 SimpleSet<IWarFoundryObject> objs; |
276 objs = new SimpleSet<IWarFoundryObject>(); | 428 objs = new SimpleSet<IWarFoundryObject>(); |
277 loadedObjects.Add(factory, objs); | 429 loadedObjects.Add(factory, objs); |
278 } | 430 } |
279 | 431 |
280 objs.AddRange(loadedObjs); | 432 objs.AddRange(loadedObjs); |
281 } | 433 StoreObjects(loadedObjs); |
282 | 434 } |
283 private void AddLoadedObject(IWarFoundryObject obj, IWarFoundryFactory factory) | 435 |
284 { | 436 private void StoreObjects(ICollection<IWarFoundryObject> loadedObjects) |
285 SimpleSet<IWarFoundryObject> objs; | 437 { |
286 loadedObjects.TryGetValue(factory, out objs); | 438 foreach (IWarFoundryObject loadedObject in loadedObjects) |
287 | 439 { |
288 if (objs == null) | 440 if (loadedObject is GameSystem) |
289 { | 441 { |
290 objs = new SimpleSet<IWarFoundryObject>(); | 442 StoreGameSystem((GameSystem)loadedObject); |
291 loadedObjects.Add(factory, objs); | 443 } |
292 } | 444 else if (loadedObject is Race) |
293 | 445 { |
294 objs.Add(obj); | 446 StoreRace((Race)loadedObject); |
447 } | |
448 } | |
295 } | 449 } |
296 | 450 |
297 protected virtual ZipFile MakeZipFile(FileInfo file) | 451 protected virtual ZipFile MakeZipFile(FileInfo file) |
298 { | 452 { |
299 return new ZipFile(file.FullName); | 453 return new ZipFile(file.FullName); |
311 { | 465 { |
312 systemsTable.Add(sysid, (GameSystem)system); | 466 systemsTable.Add(sysid, (GameSystem)system); |
313 } | 467 } |
314 } | 468 } |
315 | 469 |
316 | |
317 /// <summary> | |
318 /// Stores a loaded <see cref="GameSystem"/> that has been generated outside the core loading structure. | |
319 /// | |
320 /// Note: Calls to this function should be made before calls to StoreRace(Race, IWarFoundryFactory). | |
321 /// </summary> | |
322 /// <param name="system"> | |
323 /// The <see cref="GameSystem"/> to register as loaded. | |
324 /// </param> | |
325 /// <param name="factory"> | |
326 /// The <see cref="IWarFoundryFactory"/> that created it. | |
327 /// </param> | |
328 public void StoreGameSystem(GameSystem system, IWarFoundryFactory factory) | |
329 { | |
330 AddLoadedObject(system, factory); | |
331 StoreGameSystem(system); | |
332 } | |
333 | |
334 protected void StoreRace(Race race) | 470 protected void StoreRace(Race race) |
335 { | 471 { |
336 Dictionary<string, Dictionary<string, Race>> systemRaces; | 472 Dictionary<string, Dictionary<string, Race>> systemRaces; |
337 | 473 |
338 if (race.GameSystem == null) | 474 if (race.GameSystem == null) |
368 subRaces.Add(race.SubID.ToLower(), race); | 504 subRaces.Add(race.SubID.ToLower(), race); |
369 } | 505 } |
370 } | 506 } |
371 | 507 |
372 /// <summary> | 508 /// <summary> |
373 /// Stores a loaded <see cref="Race"/> that has been generated outside the core loading structure. | |
374 /// | |
375 /// Note: Calls to this function should ensure that the relevant <see cref="GameSystem"> has been created first. | |
376 /// </summary> | |
377 /// <param name="race"> | |
378 /// The <see cref="Race"/> to register as loaded. | |
379 /// </param> | |
380 /// <param name="factory"> | |
381 /// The <see cref="IWarFoundryFactory"/> that created it | |
382 /// </param> | |
383 public void StoreRace(Race race, IWarFoundryFactory factory) | |
384 { | |
385 AddLoadedObject(race, factory); | |
386 StoreRace(race); | |
387 } | |
388 | |
389 /// <summary> | |
390 /// Gets all <see cref="GameSystem"/>s that are currently available, determined by those that can be loaded with the current <see cref="IWarFoundryFactory"/>s. | 509 /// Gets all <see cref="GameSystem"/>s that are currently available, determined by those that can be loaded with the current <see cref="IWarFoundryFactory"/>s. |
391 /// </summary> | 510 /// </summary> |
392 /// <returns> | 511 /// <returns> |
393 /// An array of <see cref="GameSystem"/>s that are currently available. | 512 /// An array of <see cref="GameSystem"/>s that are currently available. |
394 /// </returns> | 513 /// </returns> |
397 if (systemsTable==null) | 516 if (systemsTable==null) |
398 { | 517 { |
399 LoadFiles(); | 518 LoadFiles(); |
400 } | 519 } |
401 | 520 |
402 GameSystem[] systems = new GameSystem[systemsTable.Count]; | 521 return DictionaryUtils.ToArray<string, GameSystem>(systemsTable); |
403 int iSys = 0; | |
404 | |
405 foreach (GameSystem sys in systemsTable.Values) | |
406 { | |
407 systems[iSys++] = sys; | |
408 } | |
409 | |
410 return systems; | |
411 } | 522 } |
412 | 523 |
413 /// <summary> | 524 /// <summary> |
414 /// Gets a single <see cref="GameSystem"/> with a given ID. | 525 /// Gets a single <see cref="GameSystem"/> with a given ID. |
415 /// </summary> | 526 /// </summary> |