Mercurial > repos > IBBoard.WarFoundry.API
comparison api/AbstractWarFoundryLoader.cs @ 233:a36a0e9cc05d
Re #228: Crash with missing abilityID
* Separate out the actual loader implementation from the static "WarFoundryLoader" class
* Add a setter method for the current loader
* Create an abstract and default implementation of the Loader to reduce coupling and allow easier mocking/testing
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Thu, 24 Dec 2009 19:45:39 +0000 |
parents | |
children | c035afa4a42c |
comparison
equal
deleted
inserted
replaced
232:f5009a00a50d | 233:a36a0e9cc05d |
---|---|
1 // This file (AbstractWarFoundryLoader.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard | |
2 // | |
3 // The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license. | |
4 | |
5 using System; | |
6 using System.Collections.Generic; | |
7 using System.IO; | |
8 using IBBoard.Collections; | |
9 using IBBoard.IO; | |
10 using IBBoard.Logging; | |
11 using IBBoard.WarFoundry.API.Factories; | |
12 using IBBoard.WarFoundry.API.Objects; | |
13 | |
14 namespace IBBoard.WarFoundry.API | |
15 { | |
16 /// <summary> | |
17 /// The base abstract implementation of a WarFoundry file loader | |
18 /// </summary> | |
19 public abstract class AbstractWarFoundryLoader | |
20 { | |
21 private ICollection<DirectoryInfo> directories; | |
22 private ICollection<INativeWarFoundryFactory> factories; | |
23 private ICollection<INonNativeWarFoundryFactory> nonNativeFactories; | |
24 private Dictionary<IWarFoundryFactory, SimpleSet<IWarFoundryObject>> loadedObjects; | |
25 public delegate void FileLoadingCompleteDelegate(List<FileLoadFailure> failures); | |
26 public event MethodInvoker FileLoadingStarted; | |
27 public event FileLoadingCompleteDelegate FileLoadingFinished; | |
28 | |
29 protected AbstractWarFoundryLoader() | |
30 { | |
31 directories = new List<DirectoryInfo>(); | |
32 factories = new List<INativeWarFoundryFactory>(); | |
33 nonNativeFactories = new List<INonNativeWarFoundryFactory>(); | |
34 loadedObjects = new Dictionary<IWarFoundryFactory,SimpleSet<IWarFoundryObject>>(); | |
35 } | |
36 | |
37 /// <summary> | |
38 /// Adds a directory to the collection of directories that will be searched for WarFoundry data files. | |
39 /// </summary> | |
40 /// <param name="directory"> | |
41 /// The <see cref="DirectoryInfo"/> to add to the list for searching for data files | |
42 /// </param> | |
43 public void AddLoadDirectory(DirectoryInfo directory) | |
44 { | |
45 if (!directories.Contains(directory)) | |
46 { | |
47 directories.Add(directory); | |
48 } | |
49 } | |
50 | |
51 /// <summary> | |
52 /// Removes a directory from the collection of directories that will be searched for WarFoundry data files. | |
53 /// </summary> | |
54 /// <param name="directory"> | |
55 /// A <see cref="DirectoryInfo"/> | |
56 /// </param> | |
57 public void RemoveLoadDirectory(DirectoryInfo directory) | |
58 { | |
59 if (directories.Contains(directory)) | |
60 { | |
61 directories.Remove(directory); | |
62 } | |
63 } | |
64 | |
65 /// <summary> | |
66 /// Registers a <see cref="INativeWarFoundryFactory"/> as a factory that can parse native data files. | |
67 /// </summary> | |
68 /// <param name="factory"> | |
69 /// The <see cref="INativeWarFoundryFactory"/> to register to parse native data files. | |
70 /// </param> | |
71 public void RegisterFactory(INativeWarFoundryFactory factory) | |
72 { | |
73 if (!factories.Contains(factory)) | |
74 { | |
75 factories.Add(factory); | |
76 } | |
77 } | |
78 | |
79 /// <summary> | |
80 /// Unregisters a <see cref="INativeWarFoundryFactory"/> so that it will no longer be used to try to parse native data files. | |
81 /// </summary> | |
82 /// <param name="factory"> | |
83 /// The <see cref="INativeWarFoundryFactory"/> to remove from the collection of factories that are used to try to parse native data files. | |
84 /// </param> | |
85 public void UnregisterFactory(INativeWarFoundryFactory factory) | |
86 { | |
87 if (factories.Contains(factory)) | |
88 { | |
89 factories.Remove(factory); | |
90 } | |
91 } | |
92 | |
93 /// <summary> | |
94 /// Registers a <see cref="INonNativeWarFoundryFactory"/> so that it will be used to try to parse non-native data files from other applications. | |
95 /// </summary> | |
96 /// <param name="factory"> | |
97 /// The <see cref="INonNativeWarFoundryFactory"/> to register to parse non-native data files. | |
98 /// </param> | |
99 public void RegisterNonNativeFactory(INonNativeWarFoundryFactory factory) | |
100 { | |
101 if (!nonNativeFactories.Contains(factory)) | |
102 { | |
103 nonNativeFactories.Add(factory); | |
104 } | |
105 } | |
106 | |
107 /// <summary> | |
108 /// Unregisters a <see cref="INonNativeWarFoundryFactory"/> so that it will no longer be used to try to parse non-native data files from other applications. | |
109 /// </summary> | |
110 /// <param name="factory"> | |
111 /// The <see cref="INonNativeWarFoundryFactory"/> to remove from the collection of factories that are used to try to parse non-native data files. | |
112 /// </param> | |
113 public void UnregisterNonNativeFactory(INonNativeWarFoundryFactory factory) | |
114 { | |
115 if (nonNativeFactories.Contains(factory)) | |
116 { | |
117 nonNativeFactories.Remove(factory); | |
118 } | |
119 } | |
120 | |
121 /// <summary> | |
122 /// Loads all of the data files in the registered directories. | |
123 /// </summary> | |
124 /// <returns> | |
125 /// A <see cref="List"/> of <see cref="FileLoadFailure"/> for files that failed to load | |
126 /// </returns> | |
127 public List<FileLoadFailure> LoadFiles() | |
128 { | |
129 PrepareForFileLoad(); | |
130 Dictionary<FileInfo, IWarFoundryFactory> loadableRaces = new Dictionary<FileInfo, IWarFoundryFactory>(); | |
131 Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems = new Dictionary<FileInfo, IWarFoundryFactory>(); | |
132 List<FileLoadFailure> failedLoads = FillLoadableFiles(loadableRaces, loadableGameSystems); | |
133 failedLoads.AddRange(LoadGameSystems(loadableGameSystems)); | |
134 failedLoads.AddRange(LoadRaces(loadableRaces)); | |
135 OnFileLoadingFinished(failedLoads); | |
136 return failedLoads; | |
137 } | |
138 | |
139 private void OnFileLoadingFinished(List<FileLoadFailure> failures) | |
140 { | |
141 if (FileLoadingFinished!=null) | |
142 { | |
143 FileLoadingFinished(failures); | |
144 } | |
145 } | |
146 | |
147 protected abstract void PrepareForFileLoad(); | |
148 | |
149 private List<FileLoadFailure> FillLoadableFiles(Dictionary<FileInfo, IWarFoundryFactory> loadableRaces, Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems) | |
150 { | |
151 List<FileLoadFailure> fails = new List<FileLoadFailure>(); | |
152 | |
153 foreach (DirectoryInfo directory in directories) | |
154 { | |
155 if (directory.Exists) | |
156 { | |
157 List<FileLoadFailure> directoryFails = FillLoadableFilesForDirectory(loadableRaces, loadableGameSystems, directory); | |
158 fails.AddRange(directoryFails); | |
159 } | |
160 else | |
161 { | |
162 LogNotifier.WarnFormat(GetType(), "Load for {0} failed because directory didn't exist", directory.FullName); | |
163 } | |
164 } | |
165 | |
166 return fails; | |
167 } | |
168 | |
169 private List<FileLoadFailure> FillLoadableFilesForDirectory(Dictionary<FileInfo, IWarFoundryFactory> loadableRaces, Dictionary<FileInfo, IWarFoundryFactory> loadableGameSystems, DirectoryInfo directory) | |
170 { | |
171 List<FileLoadFailure> fails = new List<FileLoadFailure>(); | |
172 LogNotifier.Debug(GetType(), "Load from "+directory.FullName); | |
173 | |
174 foreach (FileInfo file in directory.GetFiles()) | |
175 { | |
176 IWarFoundryFactory factory = GetGameSystemLoadingFactoryForFile(file); | |
177 | |
178 if (factory != null) | |
179 { | |
180 loadableGameSystems.Add(file, factory); | |
181 } | |
182 else | |
183 { | |
184 factory = GetRaceLoadingFactoryForFile(file); | |
185 | |
186 if (factory!=null) | |
187 { | |
188 loadableRaces.Add(file, factory); | |
189 } | |
190 else | |
191 { | |
192 FileLoadFailure failure = new FileLoadFailure(file, "File not handled as a Race or Game System definition: {0}", "FileNotHandled"); | |
193 fails.Add(failure); | |
194 LogNotifier.Info(GetType(), failure.Message); | |
195 } | |
196 } | |
197 } | |
198 | |
199 return fails; | |
200 } | |
201 | |
202 private IWarFoundryFactory GetGameSystemLoadingFactoryForFile(FileInfo file) | |
203 { | |
204 IWarFoundryFactory loadingFactory = null; | |
205 | |
206 foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) | |
207 { | |
208 if (factory.CanHandleFileAsGameSystem(file)) | |
209 { | |
210 loadingFactory = factory; | |
211 break; | |
212 } | |
213 } | |
214 | |
215 if (loadingFactory == null) | |
216 { | |
217 foreach (INativeWarFoundryFactory factory in factories) | |
218 { | |
219 if (factory.CanHandleFileAsGameSystem(file)) | |
220 { | |
221 loadingFactory = factory; | |
222 break; | |
223 } | |
224 } | |
225 } | |
226 | |
227 return loadingFactory; | |
228 } | |
229 | |
230 private IWarFoundryFactory GetRaceLoadingFactoryForFile(FileInfo file) | |
231 { | |
232 IWarFoundryFactory loadingFactory = null; | |
233 | |
234 foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) | |
235 { | |
236 if (factory.CanHandleFileAsRace(file)) | |
237 { | |
238 loadingFactory = factory; | |
239 break; | |
240 } | |
241 } | |
242 | |
243 if (loadingFactory == null) | |
244 { | |
245 foreach (INativeWarFoundryFactory factory in factories) | |
246 { | |
247 if (factory.CanHandleFileAsRace(file)) | |
248 { | |
249 loadingFactory = factory; | |
250 break; | |
251 } | |
252 } | |
253 } | |
254 | |
255 return loadingFactory; | |
256 } | |
257 | |
258 private List<FileLoadFailure> LoadGameSystems(Dictionary<FileInfo, IWarFoundryFactory> gameSystemFiles) | |
259 { | |
260 List<FileLoadFailure> fails = new List<FileLoadFailure>(); | |
261 | |
262 | |
263 foreach (FileInfo file in gameSystemFiles.Keys) | |
264 { | |
265 FileLoadFailure failure = null; | |
266 | |
267 try | |
268 { | |
269 bool loaded = LoadObject(file, gameSystemFiles[file]); | |
270 | |
271 if (!loaded) | |
272 { | |
273 failure = new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as GameSystem using {1}"); | |
274 } | |
275 } | |
276 catch (Exception ex) | |
277 { | |
278 failure = new FileLoadFailure(file, null, ex.Message, null, ex); | |
279 } | |
280 | |
281 if (failure!=null) | |
282 { | |
283 fails.Add(failure); | |
284 LogNotifier.Warn(GetType(), failure.Message, failure.Exception); | |
285 } | |
286 } | |
287 | |
288 return fails; | |
289 } | |
290 | |
291 private List<FileLoadFailure> LoadRaces(Dictionary<FileInfo, IWarFoundryFactory> raceFiles) | |
292 { | |
293 List<FileLoadFailure> fails = new List<FileLoadFailure>(); | |
294 | |
295 foreach (FileInfo file in raceFiles.Keys) | |
296 { | |
297 FileLoadFailure failure = null; | |
298 | |
299 try | |
300 { | |
301 bool loaded = LoadObject(file, raceFiles[file]); | |
302 | |
303 if (!loaded) | |
304 { | |
305 failure = new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}"); | |
306 } | |
307 } | |
308 catch (Exception ex) | |
309 { | |
310 failure = new FileLoadFailure(file, null, ex.Message, null, ex); | |
311 } | |
312 | |
313 if (failure!=null) | |
314 { | |
315 fails.Add(failure); | |
316 LogNotifier.Warn(GetType(), failure.Message, failure.Exception); | |
317 } | |
318 } | |
319 | |
320 return fails; | |
321 } | |
322 | |
323 private bool LoadObject(FileInfo file, IWarFoundryFactory factory) | |
324 { | |
325 bool loaded = false; | |
326 | |
327 LogNotifier.DebugFormat(GetType(), "Loading {0} using {1}", file.FullName, factory.GetType().Name); | |
328 ICollection<IWarFoundryObject> objects = factory.CreateObjectsFromFile(file); | |
329 | |
330 if (objects.Count > 0) | |
331 { | |
332 AddLoadedObjects(objects, factory); | |
333 loaded = true; | |
334 } | |
335 | |
336 return loaded; | |
337 } | |
338 | |
339 | |
340 /// <summary> | |
341 /// Loads a single file through the registered WarFoundryFactories, if a factory exists that supports the file format. | |
342 /// </summary> | |
343 /// <param name="file"> | |
344 /// A <see cref="FileInfo"/> for the file to attempt to load | |
345 /// </param> | |
346 /// <returns> | |
347 /// An ICollection of IWarFoundryObjects loaded from <code>file</code> | |
348 /// </returns> | |
349 public ICollection<IWarFoundryObject> LoadFile(FileInfo file) | |
350 { | |
351 ICollection<IWarFoundryObject> objs = null; | |
352 IWarFoundryFactory loadFactory = null; | |
353 | |
354 try | |
355 { | |
356 objs = LoadFileWithNonNativeFactories(file, out loadFactory); | |
357 | |
358 if (objs == null) | |
359 { | |
360 objs = LoadFileWithNativeFactories(file, out loadFactory); | |
361 } | |
362 } | |
363 catch (InvalidFileException ex) | |
364 { | |
365 LogNotifier.Error(GetType(), file.FullName+" failed to load", ex); | |
366 } | |
367 | |
368 if (objs!=null) | |
369 { | |
370 AddLoadedObjects(objs, loadFactory); | |
371 } | |
372 else | |
373 { | |
374 objs = new List<IWarFoundryObject>(); | |
375 } | |
376 | |
377 return objs; | |
378 } | |
379 | |
380 private ICollection<IWarFoundryObject> LoadFileWithNonNativeFactories(FileInfo file, out IWarFoundryFactory loadFactory) | |
381 { | |
382 ICollection<IWarFoundryObject> objs = null; | |
383 loadFactory = null; | |
384 | |
385 if (nonNativeFactories.Count > 0) | |
386 { | |
387 LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as a non-native file"); | |
388 | |
389 foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) | |
390 { | |
391 bool canLoad = factory.CanHandleFileFormat(file); | |
392 LogNotifier.Debug(GetType(), "Load using "+factory.GetType().FullName+"? " + (canLoad ? "yes" : "no")); | |
393 | |
394 if (canLoad) | |
395 { | |
396 objs = factory.CreateObjectsFromFile(file); | |
397 | |
398 if (objs!=null) | |
399 { | |
400 loadFactory = factory; | |
401 break; | |
402 } | |
403 } | |
404 } | |
405 } | |
406 | |
407 return objs; | |
408 } | |
409 | |
410 private ICollection<IWarFoundryObject> LoadFileWithNativeFactories(FileInfo file, out IWarFoundryFactory loadFactory) | |
411 { | |
412 ICollection<IWarFoundryObject> objs = null; | |
413 loadFactory = null; | |
414 | |
415 if (factories.Count > 0) | |
416 { | |
417 LogNotifier.Debug(GetType(), "Attempting to load "+file.FullName+" as native file"); | |
418 | |
419 foreach (INativeWarFoundryFactory factory in factories) | |
420 { | |
421 if (factory.CanHandleFileFormat(file)) | |
422 { | |
423 objs = factory.CreateObjectsFromFile(file); | |
424 | |
425 if (objs!=null) | |
426 { | |
427 loadFactory = factory; | |
428 break; | |
429 } | |
430 } | |
431 } | |
432 } | |
433 | |
434 return objs; | |
435 } | |
436 | |
437 private void AddLoadedObjects(ICollection<IWarFoundryObject> loadedObjs, IWarFoundryFactory factory) | |
438 { | |
439 SimpleSet<IWarFoundryObject> objs; | |
440 loadedObjects.TryGetValue(factory, out objs); | |
441 | |
442 if (objs == null) | |
443 { | |
444 objs = new SimpleSet<IWarFoundryObject>(); | |
445 loadedObjects.Add(factory, objs); | |
446 } | |
447 | |
448 objs.AddRange(loadedObjs); | |
449 StoreObjects(loadedObjs); | |
450 } | |
451 | |
452 private void StoreObjects(ICollection<IWarFoundryObject> loadedObjects) | |
453 { | |
454 foreach (IWarFoundryObject loadedObject in loadedObjects) | |
455 { | |
456 if (loadedObject is GameSystem) | |
457 { | |
458 StoreGameSystem((GameSystem)loadedObject); | |
459 } | |
460 else if (loadedObject is Race) | |
461 { | |
462 StoreRace((Race)loadedObject); | |
463 } | |
464 } | |
465 } | |
466 | |
467 protected void StoreGameSystem(GameSystem system) | |
468 { | |
469 GameSystem existingSystem = GetExistingSystemForSystem(system); | |
470 | |
471 if (existingSystem!=null) | |
472 { | |
473 if (!system.Equals(existingSystem)) | |
474 { | |
475 //TODO: Raise an event to say we got a different duplicate | |
476 //We can't just fail, because failing is for completely unhandled files, not for objects in a file | |
477 } | |
478 } | |
479 else | |
480 { | |
481 DoStoreGameSystem(system); | |
482 } | |
483 } | |
484 | |
485 /// <summary> | |
486 /// Gets a game system that has already been loaded that duplicates the supplied game system's ID, if one exists. | |
487 /// </summary> | |
488 /// <param name="system"> | |
489 /// The <see cref="GameSystem"/> to find pre-existing duplicates of | |
490 /// </param> | |
491 /// <returns> | |
492 /// <code>null</code> if no existing duplicate exists, else the duplicate <see cref="GameSystem"/> | |
493 /// </returns> | |
494 protected abstract GameSystem GetExistingSystemForSystem(GameSystem system); | |
495 | |
496 /// <summary> | |
497 /// Stores a GameSystem in the loader's relevant storage structure | |
498 /// </summary> | |
499 /// <param name="system"> | |
500 /// The loaded <see cref="GameSystem"/> to store | |
501 /// </param> | |
502 protected abstract void DoStoreGameSystem(GameSystem system); | |
503 | |
504 protected void StoreRace(Race race) | |
505 { | |
506 if (race.GameSystem == null) | |
507 { | |
508 throw new InvalidOperationException("Race cannot have null game system. Game system should be loaded before race."); | |
509 } | |
510 | |
511 DoStoreRace(race); | |
512 } | |
513 | |
514 /// <summary> | |
515 /// Performs the implementation specific storage of a race | |
516 /// </summary> | |
517 /// <param name="race"> | |
518 /// The <see cref="Race"/> to store | |
519 /// </param> | |
520 protected abstract void DoStoreRace(Race race); | |
521 | |
522 /// <summary> | |
523 /// Gets all <see cref="GameSystem"/>s that are currently available, determined by those that can be loaded with the current <see cref="IWarFoundryFactory"/>s. | |
524 /// </summary> | |
525 /// <returns> | |
526 /// An array of <see cref="GameSystem"/>s that are currently available. | |
527 /// </returns> | |
528 public abstract GameSystem[] GetGameSystems(); | |
529 | |
530 /// <summary> | |
531 /// Gets a single <see cref="GameSystem"/> with a given ID. | |
532 /// </summary> | |
533 /// <param name="systemID"> | |
534 /// The ID of the <see cref="GameSystem"/> to get, as a <see cref="System.String"/>. | |
535 /// </param> | |
536 /// <returns> | |
537 /// The <see cref="GameSystem"/> with the given ID, or <code>null</code> if one doesn't exist. | |
538 /// </returns> | |
539 public abstract GameSystem GetGameSystem(string systemID); | |
540 | |
541 /// <summary> | |
542 /// Removes a loaded <see cref="GameSystem"/>. Used when a GameSystem fails to complete loading | |
543 /// </summary> | |
544 /// <param name="system">The GameSystem to remove</param> | |
545 protected internal abstract void RemoveGameSystem(GameSystem system); | |
546 | |
547 /// <summary> | |
548 /// Gets an array of the races for the specified <see cref="GameSystem"/>. | |
549 /// </summary> | |
550 /// <param name="system"> | |
551 /// The <see cref="GameSystem"/> to get the available races for. | |
552 /// </param> | |
553 /// <returns> | |
554 /// An array of <see cref="Race"/>s for the <see cref="GameSystem"/> | |
555 /// </returns> | |
556 public abstract Race[] GetRaces(GameSystem system); | |
557 | |
558 /// <summary> | |
559 /// Gets a single race for a given <see cref="GameSystem"/> by ID of the race. | |
560 /// </summary> | |
561 /// <param name="system"> | |
562 /// The <see cref="GameSystem"/> that the race is part of. | |
563 /// </param> | |
564 /// <param name="raceID"> | |
565 /// A <see cref="System.String"/> ID for the race to load. | |
566 /// </param> | |
567 /// <returns> | |
568 /// A <see cref="Race"/> with the specified ID from the <see cref="GameSystem"/>, or <code>null</code> if one doesn't exist. | |
569 /// </returns> | |
570 public abstract Race GetRace(GameSystem system, string raceID); | |
571 | |
572 /// <summary> | |
573 /// Gets a single race for a given <see cref="GameSystem"/> by the race's ID and sub-race ID. | |
574 /// </summary> | |
575 /// <param name="system"> | |
576 /// The <see cref="GameSystem"/> that the race is part of. | |
577 /// </param> | |
578 /// <param name="raceID"> | |
579 /// The <see cref="System.String"/> ID for the race to load. | |
580 /// </param> | |
581 /// <param name="raceSubID"> | |
582 /// A <see cref="System.String"/> | |
583 /// </param> | |
584 /// <returns> | |
585 /// A <see cref="Race"/> | |
586 /// </returns> | |
587 public abstract Race GetRace(GameSystem system, string raceID, string raceSubID); | |
588 | |
589 protected internal abstract void RemoveRace(Race race); | |
590 | |
591 /// <summary> | |
592 /// Gets the IDs of all of the game systems currently available. | |
593 /// </summary> | |
594 /// <returns> | |
595 /// An array of <see cref="System.String"/>s representing the IDs of the game systems. | |
596 /// </returns> | |
597 public virtual string[] GetGameSystemIDs() | |
598 { | |
599 GameSystem[] systems = GetGameSystems(); | |
600 return GetWarFoundryObjectIDs(systems); | |
601 } | |
602 | |
603 protected string[] GetWarFoundryObjectIDs(WarFoundryObject[] objs) | |
604 { | |
605 int objCount = objs.Length; | |
606 string[] keys = new string[objCount]; | |
607 | |
608 for (int i = 0; i < objCount; i++) | |
609 { | |
610 keys[i] = objs[i].ID; | |
611 } | |
612 | |
613 return keys; | |
614 } | |
615 | |
616 /// <summary> | |
617 /// Gets the IDs of all of the races of a specified game system. | |
618 /// </summary> | |
619 /// <param name="system"> | |
620 /// The <see cref="GameSystem"/> to get the available races for. | |
621 /// </param> | |
622 /// <returns> | |
623 /// An array of <see cref="System.String"/>s representing the IDs of the races of the specified game system. | |
624 /// </returns> | |
625 public virtual string[] GetSystemRaceIDs(GameSystem system) | |
626 { | |
627 Race[] races = GetRaces(system); | |
628 return GetWarFoundryObjectIDs(races); | |
629 } | |
630 | |
631 public Army LoadArmy(FileInfo file) | |
632 { | |
633 IWarFoundryFactory factory = GetArmyLoadingFactoryForFile(file); | |
634 Army loadedArmy = null; | |
635 | |
636 if (factory != null) | |
637 { | |
638 ICollection<IWarFoundryObject> objs = factory.CreateObjectsFromFile(file); | |
639 | |
640 if (objs.Count == 1) | |
641 { | |
642 foreach (IWarFoundryObject systemCount in objs) | |
643 { | |
644 if (systemCount is Army) | |
645 { | |
646 loadedArmy = (Army) systemCount; | |
647 } | |
648 } | |
649 } | |
650 } | |
651 | |
652 return loadedArmy; | |
653 } | |
654 | |
655 private IWarFoundryFactory GetArmyLoadingFactoryForFile(FileInfo file) | |
656 { | |
657 IWarFoundryFactory loadingFactory = null; | |
658 | |
659 foreach (INonNativeWarFoundryFactory factory in nonNativeFactories) | |
660 { | |
661 if (factory.CanHandleFileAsArmy(file)) | |
662 { | |
663 loadingFactory = factory; | |
664 break; | |
665 } | |
666 } | |
667 | |
668 if (loadingFactory == null) | |
669 { | |
670 foreach (INativeWarFoundryFactory factory in factories) | |
671 { | |
672 if (factory.CanHandleFileAsArmy(file)) | |
673 { | |
674 loadingFactory = factory; | |
675 break; | |
676 } | |
677 } | |
678 } | |
679 | |
680 return loadingFactory; | |
681 } | |
682 } | |
683 } |