Mercurial > repos > IBBoard.WarFoundry.API
view api/Factories/Xml/WarFoundryXmlRaceFactory.cs @ 150:b36cc4af435b
Re #176: Bug when saving recently edited army
* Try to make sure that we clear up more of our open streams
Bug seems to be state related in some way since I can only trigger it when loading the file as the first action, but doesn't seem to be related to file loading of other data files since a diagnostic hard-coded "LoadFiles()" call in the FrmMain constructor doesn't change the behaviour
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sat, 26 Sep 2009 10:43:28 +0000 |
parents | c11c0da01bbc |
children | 0c0e14f03785 |
line wrap: on
line source
// 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 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. using System; using System.Collections.Generic; using System.IO; using System.Xml; using IBBoard.Xml; using IBBoard.IO; using IBBoard.Lang; 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) { //Do nothing special } 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, WarFoundryLoader.GetDefault().GetGameSystem(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:categories/cat:cat")) { CreateCategoryFromElement(node, race); } foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:equipment/race:equipmentItem")) { CreateEquipmentItemFromElement(node, race); } foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:abilities/race:ability")) { CreateAbilityFromElement(node, race); } foreach (XmlElement node in WarFoundryXmlFactoryUtils.SelectNodes(extraData, "/race:race/race:units/race:unit")) { GetUnitTypeForElement(node, race); } race.SetAsFullyLoaded(); } private Category CreateCategoryFromElement(XmlElement elem, Race parentRace) { Category cat = CreateCategoryFromElement(elem); parentRace.AddCategory(cat); return cat; } private UnitType GetUnitTypeFromDocument(XmlDocument doc, string id, Race parentRace) { return GetUnitTypeForElement(WarFoundryXmlFactoryUtils.SelectSingleElement(doc, "/race:race/race:units/race:unit[@id='"+id+"']"), parentRace); } private UnitType GetUnitTypeForElement(XmlElement elem, Race parentRace) { string id = elem.GetAttribute("id"); UnitType type = parentRace.GetUnitType(id); if (type==null) { type = CreateUnitTypeFromElement(elem, id, parentRace); } return type; } private UnitType CreateUnitTypeFromElement(XmlElement elem, string id, Race parentRace) { string name = elem.GetAttribute("typeName"); UnitType type = new UnitType(id, name, parentRace); LoadCoreValuesForUnitType(elem, type); LoadEquipmentForUnitType(elem, type); LoadAbilitiesForUnitType(elem, type); LoadContainedUnitsForUnitType(elem, type); LoadRequirementsForUnitType(elem, type); LoadExtraDataForUnitType(elem, type); LoadNotesForUnitType(elem, type); parentRace.AddUnitType(type); return type; } private void LoadCoreValuesForUnitType(XmlElement elem, UnitType type) { 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 = type.Race.GetCategory(mainCatID); if (cat == null) { throw new InvalidDataException(String.Format("Attribute 'cat' of UnitType {0} (value: {1}) did not reference a valid category", type.ID, mainCatID)); } type.MainCategory = cat; XmlElement statsElement = WarFoundryXmlFactoryUtils.SelectSingleElement(elem, "race:stats"); Stats unitStats = ParseUnitStats(statsElement, type.GameSystem); type.SetUnitStats(unitStats); } private void LoadEquipmentForUnitType(XmlElement elem, UnitType type) { foreach (XmlElement equip in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:unitEquipment/race:unitEquipmentItem")) { string id = equip.GetAttribute("id"); EquipmentItem equipItem = type.Race.GetEquipmentItem(id); if (equipItem!=null) { string mutexGroup = equip.GetAttribute("exclusivityGroup"); UnitEquipmentItem unitEquipItem = new UnitEquipmentItem(equipItem, type, mutexGroup); unitEquipItem.RoundNumberUp = equip.GetAttribute("roundDirection").Equals("up"); try { unitEquipItem.IsRequired = bool.Parse(equip.GetAttribute("required")); } catch(FormatException e) { throw new InvalidFileException("Attribute 'required' of unit equipment item " + id + " for " + type.Name + " was not a valid boolean", e); } try { unitEquipItem.MinNumber = int.Parse(equip.GetAttribute("minNum")); } catch (FormatException e) { throw new InvalidFileException("Attribute 'minNum' of unit equipment item " + id + " for " + type.Name + " was not a valid integer", e); } try { unitEquipItem.MaxNumber = int.Parse(equip.GetAttribute("maxNum")); } catch (FormatException e) { throw new InvalidFileException("Attribute 'maxNum' of unit equipment item " + id + " for " + type.Name + " was not a valid integer", e); } try { unitEquipItem.MinPercentage = double.Parse(equip.GetAttribute("minPercentage")); } catch (FormatException e) { throw new InvalidFileException("Attribute 'minPercentage' of unit equipment item " + id + " for " + type.Name + " was not a valid decimal number", e); } try { unitEquipItem.MaxPercentage = double.Parse(equip.GetAttribute("maxPercentage")); } catch (FormatException e) { throw new InvalidFileException("Attribute 'maxPercentage' of unit equipment item " + id + " for " + type.Name + " was not a valid decimal number", e); } try { unitEquipItem.CostMultiplier = double.Parse(equip.GetAttribute("costMultiplier")); } catch (FormatException e) { throw new InvalidFileException("Attribute 'costMultiplier' of unit equipment item " + id + " for " + type.Name + " was not a valid decimal number", e); } try { unitEquipItem.CostRoundType = (RoundType) Enum.Parse(typeof(RoundType), equip.GetAttribute("costRounding")); } catch (ArgumentException e) { throw new InvalidFileException("Attribute 'costRounding' of unit equipment item " + id + " for " + type.Name + " was not a valid rounding type", e); } } else { throw new InvalidFileException("Equipment item with ID '" + id + "' was required by " + type.Name + " but was not found"); } } } private void LoadAbilitiesForUnitType(XmlElement elem, UnitType type) { foreach (XmlElement ability in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:unitAbilities/race:unitAbility")) { string id = ability.GetAttribute("abilityID"); bool required = XmlTools.GetBoolValueFromAttribute(ability, "required"); type.AddAbility(type.Race.GetAbility(id), required); } } private void LoadContainedUnitsForUnitType(XmlElement elem, UnitType type) { foreach (XmlElement containedUnitType in WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:contains/race:containedUnit")) { string id = containedUnitType.GetAttribute("containedID"); UnitType containedType = GetUnitTypeFromDocument(elem.OwnerDocument, id, type.Race); if (containedType!=null) { type.AddContainedUnitType(containedType); } else { throw new InvalidFileException("Unit type " + type.Name + " tried to contain undefined unit with ID "+id); } } } private void LoadRequirementsForUnitType(XmlElement elem, UnitType type) { //TODO: Load requirements } private void LoadExtraDataForUnitType(XmlElement elem, UnitType type) { } private void LoadNotesForUnitType(XmlElement elem, UnitType type) { XmlNode node = WarFoundryXmlFactoryUtils.SelectSingleNode(elem, "race:notes"); if (node!=null) { type.Notes = node.InnerText; } } private Stats ParseUnitStats(XmlElement elem, GameSystem system) { 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 WarFoundryXmlFactoryUtils.SelectNodes(elem, "race:stat")) { String statName = stat.GetAttribute("name"); stats.SetStatValue(statName, stat.InnerText); } return stats; } private EquipmentItem CreateEquipmentItemFromElement(XmlElement elem, Race race) { string id = elem.GetAttribute("id"); EquipmentItem item = race.GetEquipmentItem(id); if (item == null) { item = CreateEquipmentItemFromElement(elem, id, race); } return item; } private EquipmentItem CreateEquipmentItemFromElement(XmlElement elem, string id, Race race) { string name = elem.GetAttribute("name"); EquipmentItem item = new EquipmentItem(id, name, race); double cost = 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 item.Cost = cost; item.ItemArmourType = armourType; race.AddEquipmentItem(item); return item; } 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; race.AddAbility(ability); return ability; } } }