using System; using System.Collections.Generic; using System.IO; using System.Xml; namespace Oni.Level { using Metadata; using Xml; partial class LevelImporter { private class Film { public string Name; public Vector3 Position; public float Facing; public float DesiredFacing; public float HeadFacing; public float HeadPitch; public readonly string[] Animations = new string[2]; public int Length; public readonly List Frames = new List(); } private class FilmFrame { public Vector2 MouseDelta; public InstanceMetadata.FILMKeys Keys; public uint Time; } private void ReadFilms(XmlReader xml, string basePath) { if (!xml.IsStartElement("Films") || xml.SkipEmpty()) return; xml.ReadStartElement("Films"); while (xml.IsStartElement()) { xml.ReadStartElement("Import"); string filePath = Path.Combine(basePath, xml.ReadElementContentAsString()); xml.ReadEndElement(); if (!File.Exists(filePath)) { error.WriteLine("Could not find file '{0}'", filePath); continue; } string extension = Path.GetExtension(filePath); string name = Path.GetFileNameWithoutExtension(filePath); if (string.Equals(extension, ".oni", StringComparison.OrdinalIgnoreCase)) { var outputFilePath = Path.Combine(outputDirPath, name + ".oni"); File.Copy(filePath, outputFilePath, true); } else if (string.Equals(extension, ".dat", StringComparison.OrdinalIgnoreCase)) { var film = ReadBinFilm(filePath); var datWriter = new DatWriter(); WriteDatFilm(datWriter, film); datWriter.Write(outputDirPath); } else if (string.Equals(extension, ".xml", StringComparison.OrdinalIgnoreCase)) { var film = ReadXmlFilm(filePath); var datWriter = new DatWriter(); WriteDatFilm(datWriter, film); datWriter.Write(outputDirPath); } else { error.WriteLine("Unsupported film file type {0}", extension); } } xml.ReadEndElement(); } private static Film ReadBinFilm(string filePath) { string name = Path.GetFileNameWithoutExtension(filePath); if (name.StartsWith("FILM", StringComparison.Ordinal)) name = name.Substring(4); var film = new Film(); film.Name = name; using (var reader = new BinaryReader(filePath, true)) { film.Animations[0] = reader.ReadString(128); film.Animations[1] = reader.ReadString(128); film.Position = reader.ReadVector3(); film.Facing = reader.ReadSingle(); film.DesiredFacing = reader.ReadSingle(); film.HeadFacing = reader.ReadSingle(); film.HeadPitch = reader.ReadSingle(); film.Length = reader.ReadInt32(); reader.Skip(28); int numFrames = reader.ReadInt32(); film.Frames.Capacity = numFrames; for (int i = 0; i < numFrames; i++) { var frame = new FilmFrame(); frame.MouseDelta = reader.ReadVector2(); frame.Keys = (InstanceMetadata.FILMKeys)reader.ReadUInt64(); frame.Time = reader.ReadUInt32(); reader.Skip(4); film.Frames.Add(frame); } } return film; } private static Film ReadXmlFilm(string filePath) { string name = Path.GetFileNameWithoutExtension(filePath); if (name.StartsWith("FILM", StringComparison.Ordinal)) name = name.Substring(4); var film = new Film(); film.Name = name; var settings = new XmlReaderSettings { IgnoreWhitespace = true, IgnoreProcessingInstructions = true, IgnoreComments = true }; using (var xml = XmlReader.Create(filePath, settings)) { xml.ReadStartElement("Oni"); name = xml.GetAttribute("Name"); if (!string.IsNullOrEmpty(name)) film.Name = name; xml.ReadStartElement("FILM"); film.Position = xml.ReadElementContentAsVector3("Position"); film.Facing = xml.ReadElementContentAsFloat("Facing", ""); film.DesiredFacing = xml.ReadElementContentAsFloat("DesiredFacing", ""); film.HeadFacing = xml.ReadElementContentAsFloat("HeadFacing", ""); film.HeadPitch = xml.ReadElementContentAsFloat("HeadPitch", ""); film.Length = xml.ReadElementContentAsInt("FrameCount", ""); xml.ReadStartElement("Animations"); film.Animations[0] = xml.ReadElementContentAsString("Link", ""); film.Animations[1] = xml.ReadElementContentAsString("Link", ""); xml.ReadEndElement(); xml.ReadStartElement("Frames"); while (xml.IsStartElement()) { var frame = new FilmFrame(); switch (xml.LocalName) { case "FILMFrame": xml.ReadStartElement(); frame.MouseDelta.X = xml.ReadElementContentAsFloat("MouseDeltaX", ""); frame.MouseDelta.Y = xml.ReadElementContentAsFloat("MouseDeltaY", ""); frame.Keys = xml.ReadElementContentAsEnum("Keys"); frame.Time = (uint)xml.ReadElementContentAsInt("Frame", ""); xml.ReadEndElement(); break; case "Frame": xml.ReadStartElement(); while (xml.IsStartElement()) { switch (xml.LocalName) { case "Time": frame.Time = (uint)xml.ReadElementContentAsInt(); break; case "MouseDelta": frame.MouseDelta = xml.ReadElementContentAsVector2(); break; case "Keys": frame.Keys = xml.ReadElementContentAsEnum(); break; } } xml.ReadEndElement(); break; default: xml.Skip(); continue; } film.Frames.Add(frame); } xml.ReadEndElement(); xml.ReadEndElement(); } return film; } private static void WriteDatFilm(DatWriter filmWriter, Film film) { var descriptor = filmWriter.CreateInstance(TemplateTag.FILM, film.Name); var animations = new ImporterDescriptor[2]; for (int i = 0; i < animations.Length; i++) { if (!string.IsNullOrEmpty(film.Animations[i])) animations[i] = filmWriter.CreateInstance(TemplateTag.TRAM, film.Animations[i]); } using (var writer = descriptor.OpenWrite()) { writer.Write(film.Position); writer.Write(film.Facing); writer.Write(film.DesiredFacing); writer.Write(film.HeadFacing); writer.Write(film.HeadPitch); writer.Write(film.Length); writer.Write(animations); writer.Skip(12); writer.Write(film.Frames.Count); foreach (var frame in film.Frames) { writer.Write(frame.MouseDelta); writer.Write((ulong)frame.Keys); writer.Write(frame.Time); writer.Skip(4); } } } } }