Mercurial > repos > IBDev-IBBoard.WarFoundry.API
changeset 52:64ef178c18aa
Re #10 - Refactor for readability
* Break WarFoundryXMLFactory out in to GameSystem, Race and Army factories
* Create factory utils classes with methods from WarFoundryXMLFactory for getting node lists etc
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Mon, 30 Mar 2009 19:44:03 +0000 |
parents | b271a2252758 |
children | 1b35eed503ef |
files | IBBoard.WarFoundry.API.csproj api/Factories/Xml/AbstractStagedLoadedSubFactory.cs api/Factories/Xml/WarFoundryXmlArmyFactory.cs api/Factories/Xml/WarFoundryXmlFactory.cs api/Factories/Xml/WarFoundryXmlFactoryUtils.cs api/Factories/Xml/WarFoundryXmlGameSystemFactory.cs api/Factories/Xml/WarFoundryXmlRaceFactory.cs |
diffstat | 7 files changed, 521 insertions(+), 383 deletions(-) [+] |
line wrap: on
line diff
--- a/IBBoard.WarFoundry.API.csproj Sat Mar 28 21:00:35 2009 +0000 +++ b/IBBoard.WarFoundry.API.csproj Mon Mar 30 19:44:03 2009 +0000 @@ -120,6 +120,11 @@ <Compile Include="api\WarFoundryCore.cs" /> <Compile Include="api\WarFoundryLoader.cs" /> <Compile Include="AssemblyInfo.cs" /> + <Compile Include="api\Factories\Xml\WarFoundryXmlGameSystemFactory.cs" /> + <Compile Include="api\Factories\Xml\WarFoundryXmlRaceFactory.cs" /> + <Compile Include="api\Factories\Xml\WarFoundryXmlArmyFactory.cs" /> + <Compile Include="api\Factories\Xml\WarFoundryXmlFactoryUtils.cs" /> + <Compile Include="api\Factories\Xml\AbstractStagedLoadedSubFactory.cs" /> </ItemGroup> <ItemGroup> <Content Include="libs\ICSharpCode.SharpZipLib.dll" />
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/api/Factories/Xml/AbstractStagedLoadedSubFactory.cs Mon Mar 30 19:44:03 2009 +0000 @@ -0,0 +1,34 @@ +// This file (AbstractStagedLoadedSubFactory.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard +// +// The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license. +// + +using System; +using System.Xml; +using IBBoard.Xml; +using IBBoard.WarFoundry.API.Objects; + +namespace IBBoard.WarFoundry.API.Factories.Xml +{ + public class AbstractStagedLoadedSubFactory + { + protected WarFoundryXmlFactory mainFactory; + + protected AbstractStagedLoadedSubFactory(WarFoundryXmlFactory factory) + { + mainFactory = factory; + } + + protected Category CreateCategoryFromElement(XmlElement elem) + { + string id = elem.GetAttribute("id"); + string name = elem.GetAttribute("name"); + Category cat = new Category(id, name); + cat.MaximumPercentage = XmlTools.GetIntValueFromAttribute(elem, "maxPercentage"); + cat.MinimumPercentage = XmlTools.GetIntValueFromAttribute(elem, "minPercentage"); + cat.MaximumPoints = XmlTools.GetIntValueFromAttribute(elem, "maxPoints"); + cat.MinimumPoints = XmlTools.GetIntValueFromAttribute(elem, "minPoints"); + return cat; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/api/Factories/Xml/WarFoundryXmlArmyFactory.cs Mon Mar 30 19:44:03 2009 +0000 @@ -0,0 +1,32 @@ +// This file (WarFoundryXmlArmyFactory.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard +// +// The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license. +// + +using System; +using System.Xml; +using IBBoard.Xml; +using ICSharpCode.SharpZipLib.Zip; +using IBBoard.WarFoundry.API.Objects; + +namespace IBBoard.WarFoundry.API.Factories.Xml +{ + /// <summary> + /// A sub-factory for loading WarFoundry Army XML files + /// </summary> + public class WarFoundryXmlArmyFactory + { + public Army CreateArmyFromElement(ZipFile file, XmlElement elem) + { + string name = elem.GetAttribute("name"); + string systemID = elem.GetAttribute("gameSystem"); + GameSystem system = WarFoundryLoader.GetDefault().GetGameSystem(systemID); + string raceID = elem.GetAttribute("race"); + Race race = WarFoundryLoader.GetDefault().GetRace(system, raceID); + int points = XmlTools.GetIntValueFromAttribute(elem, "maxPoints"); + Army army = new Army(race, name, points, file); + //TODO: Complete loading of army + return army; + } + } +}
--- a/api/Factories/Xml/WarFoundryXmlFactory.cs Sat Mar 28 21:00:35 2009 +0000 +++ b/api/Factories/Xml/WarFoundryXmlFactory.cs Mon Mar 30 19:44:03 2009 +0000 @@ -26,9 +26,9 @@ public class WarFoundryXmlFactory : AbstractNativeWarFoundryFactory { private static WarFoundryXmlFactory factory; - private XmlReaderSettings settings; - private XmlNamespaceManager nsManager; - private Dictionary<IWarFoundryObject, XmlDocument> extraData = new Dictionary<IWarFoundryObject, XmlDocument>(); + private WarFoundryXmlGameSystemFactory gameSystemFactory; + private WarFoundryXmlRaceFactory raceFactory; + private WarFoundryXmlArmyFactory armyFactory; public static AbstractNativeWarFoundryFactory GetFactory() { @@ -42,7 +42,9 @@ private WarFoundryXmlFactory() : base() { - //Hide constructor + gameSystemFactory = new WarFoundryXmlGameSystemFactory(this); + raceFactory = new WarFoundryXmlRaceFactory(this); + armyFactory = new WarFoundryXmlArmyFactory(); } protected override bool CheckCanFindArmyFileContent(ZipFile file) @@ -68,12 +70,12 @@ protected override Army CreateArmyFromStream (ZipFile file, Stream dataStream) { XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.ARMY_ELEMENT); - return CreateArmyFromElement(file, elem); + return armyFactory.CreateArmyFromElement(file, elem); } private XmlElement GetRootElementFromStream(Stream stream, WarFoundryXmlElementName elementName) { - XmlDocument doc = CreateXmlDocumentFromStream(stream); + XmlDocument doc = WarFoundryXmlFactoryUtils.CreateXmlDocumentFromStream(stream); XmlElement elem = (XmlElement)doc.LastChild; if (!elem.LocalName.Equals(elementName.Value)) @@ -83,91 +85,6 @@ return elem; } - - private XmlDocument CreateXmlDocumentFromStream(Stream stream) - { - XmlDocument doc = new XmlDocument(); - XmlReader reader = XmlReader.Create(stream, GetReaderSettings()); - - try - { - doc.Load(reader); - } - //Don't catch XMLSchemaExceptions - let them get thrown out - finally - { - reader.Close(); - } - - return doc; - } - - /// <summary> - /// Lazy-getter for XML reader settings. May throw a <see cref="InvalidDataException"/> if there is a problem with the translation schema. - /// </summary> - /// <returns> - /// A <see cref="XmlReaderSettings"/> with the default values for validating the translation document against the translation schema - /// </returns> - private XmlReaderSettings GetReaderSettings() - { - if (settings == null) - { - settings = new XmlReaderSettings(); - settings.ValidationType = ValidationType.Schema; - settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; - settings.ProhibitDtd = true; - settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod); - XmlSchemaSet cache = new XmlSchemaSet(); - string path = IBBoard.Constants.ExecutablePath + "/dtds/"; - string nsBase = "http://ibboard.co.uk/warfoundry/"; - AddSchemaToCache(cache, nsBase + "core", path + "warfoundry-core.xsd"); - AddSchemaToCache(cache, nsBase + "cats", path + "warfoundry-cats.xsd"); - AddSchemaToCache(cache, nsBase + "race", path + "race.xsd"); - AddSchemaToCache(cache, nsBase + "system", path + "system.xsd"); - AddSchemaToCache(cache, nsBase + "army", path + "army.xsd"); - settings.Schemas.Add(cache); - } - - return settings; - } - - private void ValidationEventMethod(object sender, ValidationEventArgs e) - { - throw new InvalidDataException("Problem validating against schema for WarFoundry data: " + e.Exception.Message, e.Exception); - } - - private void AddSchemaToCache(XmlSchemaSet cache, string xmlNamespace, string schemaLocation) - { - try - { - cache.Add(xmlNamespace, schemaLocation); - } - catch (IOException ex) - { - LogNotifier.Warn(GetType(), "Problem reading schema: " + ex.Message, ex); - } - catch (XmlSchemaException ex) - { - LogNotifier.Warn(GetType(), "Problem validating schema for WarFoundry data: " + ex.Message, ex); - } - catch (XmlException ex) - { - LogNotifier.Warn(GetType(), "Problem reading data for schema: " + ex.Message, ex); - } - } - - private Army CreateArmyFromElement(ZipFile file, XmlElement elem) - { - string name = elem.GetAttribute("name"); - string systemID = elem.GetAttribute("gameSystem"); - GameSystem system = WarFoundryLoader.GetDefault().GetGameSystem(systemID); - string raceID = elem.GetAttribute("race"); - Race race = WarFoundryLoader.GetDefault().GetRace(system, raceID); - int points = XmlTools.GetIntValueFromAttribute(elem, "maxPoints"); - Army army = new Army(race, name, points, file); - //TODO: Complete loading of army - return army; - } protected override Stream GetGameSystemDataStream (ZipFile file) { @@ -178,21 +95,7 @@ { XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.SYSTEM_ELEMENT); LogNotifier.Debug(GetType(), "Create GameSystem"); - return CreateSystemFromElement(file, elem); - } - - private GameSystem CreateSystemFromElement(ZipFile file, XmlElement elem) - { - string id = elem.GetAttribute("id"); - string name = elem.GetAttribute("name"); - GameSystem system = new GameSystem(id, name, this); - StoreExtraData(system, elem); - return system; - } - - private void StoreExtraData(WarFoundryStagedLoadingObject wfObject, XmlElement elem) - { - extraData[wfObject] = elem.OwnerDocument; + return gameSystemFactory.CreateSystemFromElement(file, elem); } protected override Stream GetRaceDataStream (ZipFile file) @@ -204,56 +107,7 @@ { XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.RACE_ELEMENT); LogNotifier.Debug(GetType(), "Create Race"); - return CreateRaceFromElement(file, elem); - } - - private Race CreateRaceFromElement(ZipFile file, XmlElement elem) - { - string id = elem.GetAttribute("id"); - string subid = elem.GetAttribute("subid"); - string systemID = elem.GetAttribute("system"); - string name = elem.GetAttribute("name"); - Race race = new Race(id, subid, name, systemID, this); - StoreExtraData(race, elem); - return race; - } - - public XmlDocument GetExtraData(IWarFoundryObject obj) - { - XmlDocument extra = null; - extraData.TryGetValue(obj, out extra); - return extra; - } - - private XmlNamespaceManager GetNamespaceManager() - { - if (nsManager == null) - { - nsManager = new XmlNamespaceManager(new NameTable()); - nsManager.AddNamespace("core", "http://ibboard.co.uk/warfoundry/core"); - nsManager.AddNamespace("cat", "http://ibboard.co.uk/warfoundry/cats"); - nsManager.AddNamespace("race", "http://ibboard.co.uk/warfoundry/race"); - nsManager.AddNamespace("system", "http://ibboard.co.uk/warfoundry/system"); - nsManager.AddNamespace("army", "http://ibboard.co.uk/warfoundry/army"); - } - - return nsManager; - } - - private XmlNodeList SelectNodes(XmlNode element, string xpathQuery) - { - return element.SelectNodes(xpathQuery, GetNamespaceManager()); - } - - private XmlNode SelectSingleNode(XmlNode element, string xpathQuery) - { - return element.SelectSingleNode(xpathQuery, GetNamespaceManager()); - } - - private XmlElement SelectSingleElement(XmlNode element, string xpathQuery) - { - XmlNode node = SelectSingleNode(element, xpathQuery); - return (node is XmlElement) ? (XmlElement) node : null; + return raceFactory.CreateRaceFromElement(file, elem); } public override void CompleteLoading(IWarFoundryStagedLoadObject obj) @@ -262,237 +116,12 @@ if (obj is GameSystem) { - CompleteLoading((GameSystem)obj); + gameSystemFactory.CompleteLoading((GameSystem)obj); } else if (obj is Race) { - CompleteLoading((Race)obj); - } - } - - public void CompleteLoading(GameSystem system) - { - if (!CanCompleteLoading(system)) - { - return; - } - - system.SetAsLoading(); - XmlDocument extraData = GetExtraData(system); - LoadCategoriesForSystem(system, extraData); - XmlElement statsElem = SelectSingleElement(extraData, "/system:system/system:sysStatsList"); - string defaultStatsID = statsElem.GetAttribute("defaultStats"); - LoadSystemStatsForSystem(system, extraData); - system.StandardSystemStatsID = defaultStatsID; - XmlElement systemElement = SelectSingleElement(extraData, "/system:system"); - system.WarnOnError = XmlTools.GetBoolValueFromAttribute(systemElement, "warn"); - system.AllowAllies = XmlTools.GetBoolValueFromAttribute(systemElement, "allowAllies"); - LogNotifier.DebugFormat(GetType(), "Completed loading of GameSystem with ID {0}", system.ID); - LogNotifier.DebugFormat(GetType(), "GameSystem with ID {0} default stats: {1}", system.ID, system.StandardSystemStatsID); - system.SetAsFullyLoaded(); - } - - private bool CanCompleteLoading(IWarFoundryStagedLoadObject obj) - { - bool canLoad = true; - - if (obj.IsFullyLoaded) - { - LogNotifier.DebugFormat(GetType(), "Object of type {0} with ID {1} is already fully loaded", obj.GetType().Name, obj.ID); - canLoad = false; - } - else if (obj.IsLoading) - { - LogNotifier.WarnFormat(GetType(), "Object of type {0} with ID {1} is already being loaded", obj.GetType().Name, obj.ID); - canLoad = false; - } - - return canLoad; - } - - private void LoadCategoriesForSystem(GameSystem system, XmlNode elem) - { - foreach (XmlElement cat in SelectNodes(elem, "/system:system/system:categories/cat:cat")) - { - system.AddCategory(CreateCategoryFromElement(cat)); - } - } - - private Category CreateCategoryFromElement(XmlElement elem) - { - string id = elem.GetAttribute("id"); - string name = elem.GetAttribute("name"); - Category cat = new Category(id, name); - cat.MaximumPercentage = XmlTools.GetIntValueFromAttribute(elem, "maxPercentage"); - cat.MinimumPercentage = XmlTools.GetIntValueFromAttribute(elem, "minPercentage"); - cat.MaximumPoints = XmlTools.GetIntValueFromAttribute(elem, "maxPoints"); - cat.MinimumPoints = XmlTools.GetIntValueFromAttribute(elem, "minPoints"); - return cat; - } - - private void LoadSystemStatsForSystem(GameSystem system, XmlNode elem) - { - foreach (XmlElement stats in SelectNodes(elem, "/system:system/system:sysStatsList/system:sysStats")) - { - SystemStats sysStats = CreateSystemStatsFromElement(stats); - system.AddSystemStats(sysStats); - } - } - - private SystemStats CreateSystemStatsFromElement(XmlElement elem) - { - List<StatSlot> slots = new List<StatSlot>(); - string id = elem.GetAttribute("id"); - - foreach (XmlElement slot in elem.ChildNodes) - { - StatSlot statSlot = new StatSlot(slot.GetAttribute("name")); - slots.Add(statSlot); - } - - return new SystemStats(id, slots.ToArray()); - } - - public void CompleteLoading(Race race) - { - if (!CanCompleteLoading(race)) - { - return; - } - - race.SetAsLoading(); - XmlDocument extraData = GetExtraData(race); - - foreach (XmlElement node in SelectNodes(extraData, "/race:race/race:units/race:unit")) - { - UnitType type = CreateUnitTypeFromElement(node, race, race.GameSystem); - race.AddUnitType(type); - } - - foreach (XmlElement node in SelectNodes(extraData, "/race:race/race:categories/cat:cat")) - { - race.AddCategory(CreateCategoryFromElement(node)); - } - - foreach (XmlElement node in SelectNodes(extraData, "/race:race/race:equipment/cat:equipmentItem")) - { - EquipmentItem item = CreateEquipmentItemFromElement(node, race); - race.AddEquipmentItem(item); + raceFactory.CompleteLoading((Race)obj); } - - foreach (XmlElement node in SelectNodes(extraData, "/race:race/race:abilities/cat:ability")) - { - Ability ability = CreateAbilityFromElement(node, race); - race.AddAbility(ability); - } - - race.SetAsFullyLoaded(); - LogNotifier.DebugFormat(GetType(), "Completed loading of Race with ID {0}", race.ID); - } - - private UnitType CreateUnitTypeFromElement(XmlElement elem, Race parentRace, GameSystem system) - { - string id = elem.GetAttribute("id"); - string name = elem.GetAttribute("typeName"); - UnitType type = new UnitType(id, name, parentRace); - type.MaxNumber = XmlTools.GetIntValueFromAttribute(elem, "maxNum"); - type.MinNumber = XmlTools.GetIntValueFromAttribute(elem, "minNum"); - type.MaxSize = XmlTools.GetIntValueFromAttribute(elem, "maxSize"); - type.MinSize = XmlTools.GetIntValueFromAttribute(elem, "minSize"); - type.BaseSize = XmlTools.GetIntValueFromAttribute(elem, "baseSize"); - type.CostPerTrooper = XmlTools.GetIntValueFromAttribute(elem, "points"); - type.BaseUnitCost = XmlTools.GetIntValueFromAttribute(elem, "unitPoints"); - string mainCatID = elem.GetAttribute("cat"); - Category cat = parentRace.GetCategory(mainCatID); - - if (cat == null) - { - throw new InvalidDataException(String.Format("Attribute 'cat' of UnitType {0} (value: {1}) did not reference a valid category", id, mainCatID)); - } - - type.MainCategory = cat; - XmlElement statsElement = SelectSingleElement(elem, "/race:race/race:units/race:unit/race:stats"); - type.UnitStats = ParseUnitStats(statsElement, system); - //TODO: Add unit requirements - LogNotifier.Debug(GetType(), "Loaded "+type.Name); - return type; - } - - private Stats ParseUnitStats(XmlElement elem, GameSystem system) - { - List<Stat> statsList = new List<Stat>(); - String statsID = elem.GetAttribute("statSet"); - SystemStats statsSet; - - if (statsID == "") - { - statsSet = system.StandardSystemStats; - } - else - { - statsSet = system.GetSystemStatsForID(statsID); - } - - Stats stats = new Stats(statsSet); - - foreach (XmlElement stat in elem.ChildNodes) - { - String statID = stat.GetAttribute("name"); - StatSlot slot = statsSet[statID]; - - if (slot!=null) - { - statsList.Add(new Stat(slot, stat.InnerText)); - } - else - { - throw new InvalidFileException("The stat "+statID+" was not found in stats set "+statsID); - } - } - - stats.SetStats(statsList); - - return stats; - } - - private EquipmentItem CreateEquipmentItemFromElement(XmlElement elem, Race race) - { - string id = elem.GetAttribute("id"); - string name = elem.GetAttribute("name"); - double cost = 0, min = 0, max = 0; - ArmourType armourType; - - try - { - cost = XmlTools.GetDoubleValueFromAttribute(elem, "cost"); - } - catch(FormatException ex) - { - throw new InvalidFileException("Attribute 'cost' of equipment item "+id+" was not a valid number", ex); - } - - try - { - armourType = (ArmourType)Enum.Parse(typeof(ArmourType), elem.GetAttribute("armourType")); - } - catch(ArgumentException ex) - { - throw new InvalidFileException("Attribute 'armourType' of equipment "+id+" was not a valid value from the enumeration", ex); - } - - //TODO: Parse equipment stats if there are any - - return new EquipmentItem(id, name, cost, min, max, armourType, race); - } - - private Ability CreateAbilityFromElement(XmlElement elem, Race race) - { - string id = elem.GetAttribute("id"); - string name = elem.GetAttribute("name"); - Ability ability = new Ability(id, name); - XmlNode node = elem.SelectSingleNode("description", GetNamespaceManager()); - ability.Description = (node == null) ? "" : node.InnerText; - return ability; } } } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/api/Factories/Xml/WarFoundryXmlFactoryUtils.cs Mon Mar 30 19:44:03 2009 +0000 @@ -0,0 +1,144 @@ +// This file (WarFoundryXmlFactoryUtils.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard +// +// The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license. +// + +using System; +using System.IO; +using System.Xml; +using System.Xml.Schema; +using IBBoard.Logging; +using IBBoard.WarFoundry.API.Objects; + +namespace IBBoard.WarFoundry.API.Factories.Xml +{ + /// <summary> + /// A collection of useful utility methods for loading WarFoundry data from XML files + /// </summary> + public class WarFoundryXmlFactoryUtils + { + private static XmlReaderSettings settings; + private static XmlNamespaceManager nsManager; + + public static XmlNodeList SelectNodes(XmlNode element, string xpathQuery) + { + return element.SelectNodes(xpathQuery, GetNamespaceManager()); + } + + public static XmlNode SelectSingleNode(XmlNode element, string xpathQuery) + { + return element.SelectSingleNode(xpathQuery, GetNamespaceManager()); + } + + public static XmlElement SelectSingleElement(XmlNode element, string xpathQuery) + { + XmlNode node = SelectSingleNode(element, xpathQuery); + return (node is XmlElement) ? (XmlElement) node : null; + } + + public static XmlNamespaceManager GetNamespaceManager() + { + if (nsManager == null) + { + nsManager = new XmlNamespaceManager(new NameTable()); + nsManager.AddNamespace("core", "http://ibboard.co.uk/warfoundry/core"); + nsManager.AddNamespace("cat", "http://ibboard.co.uk/warfoundry/cats"); + nsManager.AddNamespace("race", "http://ibboard.co.uk/warfoundry/race"); + nsManager.AddNamespace("system", "http://ibboard.co.uk/warfoundry/system"); + nsManager.AddNamespace("army", "http://ibboard.co.uk/warfoundry/army"); + } + + return nsManager; + } + + /// <summary> + /// Lazy-getter for XML reader settings. May throw a <see cref="InvalidDataException"/> if there is a problem with the translation schema. + /// </summary> + /// <returns> + /// A <see cref="XmlReaderSettings"/> with the default values for validating the translation document against the translation schema + /// </returns> + public static XmlReaderSettings GetReaderSettings() + { + if (settings == null) + { + settings = new XmlReaderSettings(); + settings.ValidationType = ValidationType.Schema; + settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; + settings.ProhibitDtd = true; + settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod); + XmlSchemaSet cache = new XmlSchemaSet(); + string path = IBBoard.Constants.ExecutablePath + "/dtds/"; + string nsBase = "http://ibboard.co.uk/warfoundry/"; + AddSchemaToCache(cache, nsBase + "core", path + "warfoundry-core.xsd"); + AddSchemaToCache(cache, nsBase + "cats", path + "warfoundry-cats.xsd"); + AddSchemaToCache(cache, nsBase + "race", path + "race.xsd"); + AddSchemaToCache(cache, nsBase + "system", path + "system.xsd"); + AddSchemaToCache(cache, nsBase + "army", path + "army.xsd"); + settings.Schemas.Add(cache); + } + + return settings; + } + + private static void ValidationEventMethod(object sender, ValidationEventArgs e) + { + throw new InvalidDataException("Problem validating against schema for WarFoundry data: " + e.Exception.Message, e.Exception); + } + + private static void AddSchemaToCache(XmlSchemaSet cache, string xmlNamespace, string schemaLocation) + { + try + { + cache.Add(xmlNamespace, schemaLocation); + } + catch (IOException ex) + { + LogNotifier.Warn(typeof(WarFoundryXmlFactoryUtils), "Problem reading schema: " + ex.Message, ex); + } + catch (XmlSchemaException ex) + { + LogNotifier.Warn(typeof(WarFoundryXmlFactoryUtils), "Problem validating schema for WarFoundry data: " + ex.Message, ex); + } + catch (XmlException ex) + { + LogNotifier.Warn(typeof(WarFoundryXmlFactoryUtils), "Problem reading data for schema: " + ex.Message, ex); + } + } + + public static XmlDocument CreateXmlDocumentFromStream(Stream stream) + { + XmlDocument doc = new XmlDocument(); + XmlReader reader = XmlReader.Create(stream, GetReaderSettings()); + + try + { + doc.Load(reader); + } + //Don't catch XMLSchemaExceptions - let them get thrown out + finally + { + reader.Close(); + } + + return doc; + } + + public static bool CanCompleteLoading(IWarFoundryStagedLoadObject obj) + { + bool canLoad = true; + + if (obj.IsFullyLoaded) + { + LogNotifier.DebugFormat(typeof(WarFoundryXmlFactoryUtils), "Object of type {0} with ID {1} is already fully loaded", obj.GetType().Name, obj.ID); + canLoad = false; + } + else if (obj.IsLoading) + { + LogNotifier.WarnFormat(typeof(WarFoundryXmlFactoryUtils), "Object of type {0} with ID {1} is already being loaded", obj.GetType().Name, obj.ID); + canLoad = false; + } + + return canLoad; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/api/Factories/Xml/WarFoundryXmlGameSystemFactory.cs Mon Mar 30 19:44:03 2009 +0000 @@ -0,0 +1,100 @@ +// This file (WarFoundryXmlGameSystemFactory.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard +// +// The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license. +// + +using System; +using System.Collections.Generic; +using System.Xml; +using ICSharpCode.SharpZipLib.Zip; +using IBBoard.Logging; +using IBBoard.Xml; +using IBBoard.WarFoundry.API.Objects; + +namespace IBBoard.WarFoundry.API.Factories.Xml +{ + /// <summary> + /// A sub-factory specifically for loading GameSystems from WarFoundry XML files + /// </summary> + public class WarFoundryXmlGameSystemFactory : AbstractStagedLoadedSubFactory + { + private Dictionary<GameSystem, XmlDocument> extraData = new Dictionary<GameSystem, XmlDocument>(); + + public WarFoundryXmlGameSystemFactory(WarFoundryXmlFactory factory) : base(factory) + { + } + + private void StoreExtraData(GameSystem wfObject, XmlElement elem) + { + extraData[wfObject] = elem.OwnerDocument; + } + + private XmlDocument GetExtraData(GameSystem obj) + { + XmlDocument extra = null; + extraData.TryGetValue(obj, out extra); + return extra; + } + + public GameSystem CreateSystemFromElement(ZipFile file, XmlElement elem) + { + string id = elem.GetAttribute("id"); + string name = elem.GetAttribute("name"); + GameSystem system = new GameSystem(id, name, mainFactory); + StoreExtraData(system, elem); + return system; + } + + public void CompleteLoading(GameSystem system) + { + if (!WarFoundryXmlFactoryUtils.CanCompleteLoading(system)) + { + return; + } + + system.SetAsLoading(); + XmlDocument extraData = GetExtraData(system); + LoadCategoriesForSystem(system, extraData); + XmlElement statsElem = WarFoundryXmlFactoryUtils.SelectSingleElement(extraData, "/system:system/system:sysStatsList"); + string defaultStatsID = statsElem.GetAttribute("defaultStats"); + LoadSystemStatsForSystem(system, extraData); + system.StandardSystemStatsID = defaultStatsID; + XmlElement systemElement = WarFoundryXmlFactoryUtils.SelectSingleElement(extraData, "/system:system"); + system.WarnOnError = XmlTools.GetBoolValueFromAttribute(systemElement, "warn"); + system.AllowAllies = XmlTools.GetBoolValueFromAttribute(systemElement, "allowAllies"); + LogNotifier.DebugFormat(GetType(), "Completed loading of GameSystem with ID {0}", system.ID); + LogNotifier.DebugFormat(GetType(), "GameSystem with ID {0} default stats: {1}", system.ID, system.StandardSystemStatsID); + system.SetAsFullyLoaded(); + } + + private void LoadCategoriesForSystem(GameSystem system, XmlNode elem) + { + foreach (XmlElement cat in WarFoundryXmlFactoryUtils.SelectNodes(elem, "/system:system/system:categories/cat:cat")) + { + system.AddCategory(CreateCategoryFromElement(cat)); + } + } + + private void LoadSystemStatsForSystem(GameSystem system, XmlNode elem) + { + foreach (XmlElement stats in WarFoundryXmlFactoryUtils.SelectNodes(elem, "/system:system/system:sysStatsList/system:sysStats")) + { + SystemStats sysStats = CreateSystemStatsFromElement(stats); + system.AddSystemStats(sysStats); + } + } + + private SystemStats CreateSystemStatsFromElement(XmlElement elem) + { + List<StatSlot> slots = new List<StatSlot>(); + string id = elem.GetAttribute("id"); + + foreach (XmlElement slot in elem.ChildNodes) + { + StatSlot statSlot = new StatSlot(slot.GetAttribute("name")); + slots.Add(statSlot); + } + + return new SystemStats(id, slots.ToArray()); + } } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/api/Factories/Xml/WarFoundryXmlRaceFactory.cs Mon Mar 30 19:44:03 2009 +0000 @@ -0,0 +1,194 @@ +// This file (WarFoundryXmlRaceFactory.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard +// +// The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using IBBoard.Xml; +using IBBoard.IO; +using IBBoard.Logging; +using ICSharpCode.SharpZipLib.Zip; +using IBBoard.WarFoundry.API.Objects; + +namespace IBBoard.WarFoundry.API.Factories.Xml +{ + /// <summary> + /// A sub-factory for loading WarFoundry Race XML files + /// </summary> + public class WarFoundryXmlRaceFactory : AbstractStagedLoadedSubFactory + { + private Dictionary<Race, XmlDocument> extraData = new Dictionary<Race, XmlDocument>(); + + public WarFoundryXmlRaceFactory(WarFoundryXmlFactory factory) : base (factory) + { + } + + private void StoreExtraData(Race wfObject, XmlElement elem) + { + extraData[wfObject] = elem.OwnerDocument; + } + + private XmlDocument GetExtraData(Race obj) + { + XmlDocument extra = null; + extraData.TryGetValue(obj, out extra); + return extra; + } + + public Race CreateRaceFromElement(ZipFile file, XmlElement elem) + { + string id = elem.GetAttribute("id"); + string subid = elem.GetAttribute("subid"); + string systemID = elem.GetAttribute("system"); + string name = elem.GetAttribute("name"); + Race race = new Race(id, subid, name, systemID, mainFactory); + StoreExtraData(race, elem); + return race; + } + + public void CompleteLoading(Race race) + { + if (!WarFoundryXmlFactoryUtils.CanCompleteLoading(race)) + { + return; + } + + race.SetAsLoading(); + XmlDocument extraData = GetExtraData(race); + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:units/race:unit")) + { + UnitType type = CreateUnitTypeFromElement(node, race, race.GameSystem); + race.AddUnitType(type); + } + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:categories/cat:cat")) + { + race.AddCategory(CreateCategoryFromElement(node)); + } + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:equipment/cat:equipmentItem")) + { + EquipmentItem item = CreateEquipmentItemFromElement(node, race); + race.AddEquipmentItem(item); + } + + foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:abilities/cat:ability")) + { + Ability ability = CreateAbilityFromElement(node, race); + race.AddAbility(ability); + } + + race.SetAsFullyLoaded(); + LogNotifier.DebugFormat(GetType(), "Completed loading of Race with ID {0}", race.ID); + } + + private UnitType CreateUnitTypeFromElement(XmlElement elem, Race parentRace, GameSystem system) + { + string id = elem.GetAttribute("id"); + string name = elem.GetAttribute("typeName"); + UnitType type = new UnitType(id, name, parentRace); + type.MaxNumber = XmlTools.GetIntValueFromAttribute(elem, "maxNum"); + type.MinNumber = XmlTools.GetIntValueFromAttribute(elem, "minNum"); + type.MaxSize = XmlTools.GetIntValueFromAttribute(elem, "maxSize"); + type.MinSize = XmlTools.GetIntValueFromAttribute(elem, "minSize"); + type.BaseSize = XmlTools.GetIntValueFromAttribute(elem, "baseSize"); + type.CostPerTrooper = XmlTools.GetIntValueFromAttribute(elem, "points"); + type.BaseUnitCost = XmlTools.GetIntValueFromAttribute(elem, "unitPoints"); + string mainCatID = elem.GetAttribute("cat"); + Category cat = parentRace.GetCategory(mainCatID); + + if (cat == null) + { + throw new InvalidDataException(String.Format("Attribute 'cat' of UnitType {0} (value: {1}) did not reference a valid category", id, mainCatID)); + } + + type.MainCategory = cat; + XmlElement statsElement = WarFoundryXmlFactoryUtils.SelectSingleElement(elem, "/race:race/race:units/race:unit/race:stats"); + type.UnitStats = ParseUnitStats(statsElement, system); + //TODO: Add unit requirements + LogNotifier.Debug(GetType(), "Loaded "+type.Name); + return type; + } + + private Stats ParseUnitStats(XmlElement elem, GameSystem system) + { + List<Stat> statsList = new List<Stat>(); + String statsID = elem.GetAttribute("statSet"); + SystemStats statsSet; + + if (statsID == "") + { + statsSet = system.StandardSystemStats; + } + else + { + statsSet = system.GetSystemStatsForID(statsID); + } + + Stats stats = new Stats(statsSet); + + foreach (XmlElement stat in elem.ChildNodes) + { + String statID = stat.GetAttribute("name"); + StatSlot slot = statsSet[statID]; + + if (slot!=null) + { + statsList.Add(new Stat(slot, stat.InnerText)); + } + else + { + throw new InvalidFileException("The stat "+statID+" was not found in stats set "+statsID); + } + } + + stats.SetStats(statsList); + + return stats; + } + + private EquipmentItem CreateEquipmentItemFromElement(XmlElement elem, Race race) + { + string id = elem.GetAttribute("id"); + string name = elem.GetAttribute("name"); + double cost = 0, min = 0, max = 0; + ArmourType armourType; + + try + { + cost = XmlTools.GetDoubleValueFromAttribute(elem, "cost"); + } + catch(FormatException ex) + { + throw new InvalidFileException("Attribute 'cost' of equipment item "+id+" was not a valid number", ex); + } + + try + { + armourType = (ArmourType)Enum.Parse(typeof(ArmourType), elem.GetAttribute("armourType")); + } + catch(ArgumentException ex) + { + throw new InvalidFileException("Attribute 'armourType' of equipment "+id+" was not a valid value from the enumeration", ex); + } + + //TODO: Parse equipment stats if there are any + + return new EquipmentItem(id, name, cost, min, max, armourType, race); + } + + private Ability CreateAbilityFromElement(XmlElement elem, Race race) + { + string id = elem.GetAttribute("id"); + string name = elem.GetAttribute("name"); + Ability ability = new Ability(id, name); + XmlNode node = elem.SelectSingleNode("description", WarFoundryXmlFactoryUtils.GetNamespaceManager()); + ability.Description = (node == null) ? "" : node.InnerText; + return ability; + } + } +}