private static MiloFile ParseDirectory(Stream stream) { int version = stream.ReadInt32BE(); if (!(version == 25 || version == 28)) // RBN1 and RBN2 milos { throw new NotSupportedException($"Milo directory version of {version} is not supported"); } string dirType = stream.ReadLengthUTF8(true), dirName = stream.ReadLengthUTF8(true); MiloFile milo = new MiloFile(dirType, dirName); stream.Position += 8; // Skips string count + total length // Reads entry types/names int count = stream.ReadInt32BE(); string[] types = new string[count]; string[] names = new string[count]; for (int i = 0; i < count; i++) { types[i] = stream.ReadLengthUTF8(true); names[i] = stream.ReadLengthUTF8(true); } // Skips unknown data var next = FindNext(stream, ADDE_PADDING); stream.Seek(next + 4, SeekOrigin.Current); // Reads each file for (int i = 0; i < names.Length; i++) { long start = stream.Position; int size = FindNext(stream, ADDE_PADDING); byte[] data = stream.ReadBytes(size); stream.Position += 4; //milo.Entries.Add(new MiloEntry(names[i], types[i], stream.ReadBytes(size))); if (types[i].Equals("CharLipSync", StringComparison.CurrentCultureIgnoreCase)) { // Parse LipSync data using (var ms = new MemoryStream(data)) { CharLipSync lipsync = CharLipSync.FromStream(ms, names[i]); milo.Entries.Add(lipsync); } } } return(milo); }
public static CharLipSync FromStream(Stream stream, string name) { // Does not include DTA parsing so DC lipsync files are not supported at this time CharLipSync lipsync = new CharLipSync(); lipsync._name = name; lipsync.Version = stream.ReadInt32BE(); lipsync.SubVersion = stream.ReadInt32BE(); lipsync.DTAImport = stream.ReadLengthUTF8(true); int dtb = stream.ReadByte(); if (dtb != 0) { throw new Exception("Parsing of LipSync files with embedded DTB is not currently supported"); } stream.Position += 4; // Skips zeros int visemeCount = stream.ReadInt32BE(); lipsync.Visemes = Enumerable.Range(0, visemeCount).Select(x => stream.ReadLengthUTF8(true)).ToArray(); int keyFrameCount = stream.ReadInt32BE(); stream.Position += 4; // Skips total size of following data lipsync.Frames = new KeyFrame[keyFrameCount]; for (int i = 0; i < keyFrameCount; i++) { int eventCount = stream.ReadByte(); lipsync.Frames[i] = new KeyFrame(); lipsync.Frames[i].Events = new List <VisemeEvent>(); for (int j = 0; j < eventCount; j++) { lipsync.Frames[i].Events.Add(new VisemeEvent(lipsync.Visemes[stream.ReadByte()], (byte)stream.ReadByte())); } } // There's some other data ofter this sometimes but it's not needed return(lipsync); }