using System; using System.Collections.Generic; using System.Xml; using Oni.Metadata; using Oni.Particles; namespace Oni.Xml { internal class OnieXmlImporter : RawXmlImporter { #region Private data private List impactEffects = new List(); private List sounds = new List(); private List particles = new List(); private Dictionary materials = new Dictionary(); private List> impactList; private List> materialList; private List impactNodes; private List materialNodes; #endregion private OnieXmlImporter(XmlReader xml, BinaryWriter writer) : base(xml, writer) { } public static void Import(XmlReader xml, BinaryWriter writer) { var importer = new OnieXmlImporter(xml, writer); importer.Read(); importer.Write(); } #region private class ImpactLookupNode private class ImpactNode { private int impactIndex; private List materialNodes; public ImpactNode(int impactIndex) { this.impactIndex = impactIndex; this.materialNodes = new List(); } public int ImpactIndex { get { return impactIndex; } } public List MaterialNodes { get { return materialNodes; } } } #endregion #region private class MaterialLookupNode private class MaterialNode { private int materialIndex; private List impactEffects; public MaterialNode(int materialIndex) { this.materialIndex = materialIndex; this.impactEffects = new List(); } public int MaterialIndex { get { return materialIndex; } } public List ImpactEffects { get { return impactEffects; } } } #endregion private void Read() { impactList = new List>(); while (Xml.IsStartElement("Impact")) { int impactIndex = impactList.Count; var impactName = Xml.GetAttribute("Name"); impactList.Add(new KeyValuePair(impactName, impactIndex)); if (Xml.IsEmptyElement) { Xml.ReadStartElement(); continue; } Xml.ReadStartElement(); while (Xml.IsStartElement("Material")) { var materialName = Xml.GetAttribute("Name"); int materialIndex; if (!materials.TryGetValue(materialName, out materialIndex)) { materialIndex = materials.Count; materials.Add(materialName, materialIndex); } if (Xml.IsEmptyElement) { Xml.ReadStartElement(); continue; } Xml.ReadStartElement(); while (Xml.IsStartElement("ImpactEffect")) { Xml.ReadStartElement(); var impactEffect = new ImpactEffect(Xml, impactName, materialName) { ImpactIndex = impactIndex, MaterialIndex = materialIndex }; if (impactEffect.Sound != null) { impactEffect.SoundIndex = sounds.Count; sounds.Add(impactEffect.Sound); } else { impactEffect.SoundIndex = -1; } if (impactEffect.Particles != null && impactEffect.Particles.Length > 0) { impactEffect.ParticleIndex = particles.Count; particles.AddRange(impactEffect.Particles); } else { impactEffect.ParticleIndex = -1; } impactEffects.Add(impactEffect); Xml.ReadEndElement(); } Xml.ReadEndElement(); } Xml.ReadEndElement(); } materialList = new List>(materials); materialList.Sort((x, y) => x.Value.CompareTo(y.Value)); impactNodes = new List(); materialNodes = new List(); foreach (var impact in impactList) { var impactNode = new ImpactNode(impact.Value); impactNodes.Add(impactNode); foreach (var material in materialList) { var materialNode = new MaterialNode(material.Value); foreach (var effect in impactEffects) { if (effect.MaterialIndex == material.Value && effect.ImpactIndex == impact.Value) materialNode.ImpactEffects.Add(effect); } if (materialNode.ImpactEffects.Count > 0) { impactNode.MaterialNodes.Add(materialNode); materialNodes.Add(materialNode); } } } } private void Write() { Writer.Write(2); Writer.Write(impactList.Count); Writer.Write(materialList.Count); Writer.Write(particles.Count); Writer.Write(sounds.Count); Writer.Write(impactEffects.Count); Writer.Write(materialNodes.Count); foreach (KeyValuePair impact in impactList) { Writer.Write(impact.Key, 128); Writer.Write(0); } foreach (KeyValuePair material in materialList) { Writer.Write(material.Key, 128); Writer.Write(0); } int currentMaterialIndex = 0; foreach (var impactNode in impactNodes) { Writer.WriteInt16(impactNode.ImpactIndex); Writer.WriteInt16(impactNode.MaterialNodes.Count); Writer.Write(currentMaterialIndex); currentMaterialIndex += impactNode.MaterialNodes.Count; } foreach (var particle in particles) { particle.Write(Writer); } foreach (var sound in sounds) { sound.Write(Writer); } foreach (var materialNode in materialNodes) { foreach (var effect in materialNode.ImpactEffects) effect.Write(Writer); } int currentImpactEffectIndex = 0; foreach (var materialNode in materialNodes) { Writer.WriteInt16(materialNode.MaterialIndex); Writer.WriteInt16(materialNode.ImpactEffects.Count); Writer.Write(currentImpactEffectIndex); currentImpactEffectIndex += materialNode.ImpactEffects.Count; } } } }