/// <summary> /// Parses and XML Node or File recursively and constructs entity definitions. /// </summary> /// <param name="data">node to analyze</param> /// <remarks> /// Files should be structured as such: /// /// <Project> /// <Set name="testSet"> /// <Entity name="new" base="Test"/> /// <Entity name="new2" base="Test"> /// <Property name="Position" remove="true"/> /// <Component type="Physics" add="true"/> /// </Entity> /// </Set> /// <Entity name="Test"> /// <Property type="Vector2" name="Position"> /// <Vector2> //XML serialized stuff /// </Vector2> /// </Property> /// <Component type="StaticRenderable"> /// <StaticRenderable> // FirstChild gets passed to the Component.Initialize() or whatever /// </StaticRenderable> /// </Component> /// </Entity> /// <Entity base="Test" name="TestRawr"> /// /// </Entity> /// </Project> /// /// </remarks> public static void Parse(XmlNode data) { // This is a generic parse method, it determines what it's parsing, and switch (data.Name.ToLower().Trim()) { case "project": // if it's a project, just parse each child node. foreach (XmlNode node in data.ChildNodes) { Parse(node); } break; case "set": // If it's a set, just parse the set and add it to our set collection. SetDefinition set = ParseSet(data); m_Sets.Add(set.Name, set); break; case "entity": // Same deal with entity. EntityDefinition ent = ParseEntity(data); m_Entities.Add(ent.Name, ent); break; default: return; } }
/// <summary> /// Parse XML and use it to produce a SetDefinition. /// </summary> /// <param name="data">Data for the set definition.</param> /// <returns>The Constructed Set.</returns> public static SetDefinition ParseSet(XmlNode data) { // If this set says it's based on another set, and that set exists SetDefinition set; if (data.Attributes["base"] != null && m_Sets.ContainsKey(data.Attributes["base"].Value)) { // Zip that set together with the passed in data. set = SetDefinition.ZipTogether(m_Sets[data.Attributes["base"].Value], data); } else { // Otherwise, we can just make it from scratch set = new SetDefinition(data.Attributes["name"].Value); // and add each entity node to the set. The entities will get resolved/zipped when you // actually produce the set. foreach (XmlNode node in data.ChildNodes) { set.Entities.Add(node); } } // And return the newly created/modified set definition. return(set); }
/// <summary> /// Clone this set. /// </summary> /// <returns>A cloned set.</returns> public object Clone() { SetDefinition newSet = new SetDefinition(this.Name); foreach (XmlNode node in this.Entities) { newSet.Entities.Add(node.Clone()); } return(newSet); }
/// <summary> /// Zips together the current set along with some additional customization data. /// </summary> /// <param name="customization">Data to customize the set definition with.</param> /// <returns>A completely new SetDefinition object, customized based on the customization parameters</returns> /// <remarks> /// Structure of a Set: /// <Set name="testSet"> /// <Entity base="Test" type="add"/> /// <Entity base="Test" type="modify"> /// <Property name="Position" type="remove"/> /// <Component type="Physics" type="add"/> /// </Entity> /// </Set> /// <Set name="Test2" base="testSet"> /// <Entity base="Test" type="remove"/> /// <Entity base="Rawr" type="add"/> /// </Set> /// </remarks> public static SetDefinition ZipTogether(SetDefinition set, XmlNode customization) { //Clone the set so we don't end up modifying the original. SetDefinition newSet = (SetDefinition)set.Clone(); // If we aren't to do any customization, just return. if (customization != null) { // For each of the customization points, foreach (XmlNode child in customization.ChildNodes) { // Make sure it's an Entity (sets don't really understand anything else yet) if (child.Name.ToLower() == "entity" && child.Attributes["mod"] != null) { // Check what modification type we are, add remove or modify. switch (child.Attributes["mod"].Value.ToLower()) { case "add": newSet.Entities.Add(child); break; case "remove": if (child.Attributes["name"] != null) { String name = child.Attributes["name"].Value; newSet.Entities.RemoveAll((node) => node.Attributes["name"] != null && node.Attributes["name"].Value == name); } break; case "modify": if (child.Attributes["name"] != null) { // Zipping together the inner XML with what we have stored creates a new customization point, which will later be applied to entities. String name = child.Attributes["name"].Value; foreach (XmlNode node in newSet.Entities) { if (node.Attributes["name"] != null && node.Attributes["name"].Value == name) { node.InnerXml = node.ZipTogether(child).InnerXml; } } } break; } } } } return(newSet); }
/// <summary> /// Produce a set from a definition. This produces each of the entities as well. /// </summary> /// <param name="setName">Name of the set to produce.</param> /// <param name="customizationData">Data to customize the set with.</param> /// <returns>List of produced entities.</returns> public static List <Entity> ProduceSet(String setName, XmlNode customizationData = null) { if (m_Sets.ContainsKey(setName)) { // Customize the existing set data with the customizationData SetDefinition set = SetDefinition.ZipTogether(m_Sets[setName], customizationData); List <Entity> entList = new List <Entity>(); // And for each of the entities in it's Entities list, foreach (XmlNode node in set.Entities) { // Produce the base entity, using the stored node as customization data. entList.Add(ProduceEntity(node.Attributes["base"].Value, node)); } // And return that list. return(entList); } return(null); }