internal static T?Parse <T>(GameBoxReader r, uint?classID = null, IProgress <GameBoxReadProgress>?progress = null) where T : CMwNod { if (!classID.HasValue) { classID = r.ReadUInt32(); } if (classID == uint.MaxValue) { return(null); } classID = Remap(classID.Value); if (!NodeCacheManager.AvailableClasses.TryGetValue(classID.Value, out Type? type)) { throw new NotImplementedException($"Node ID 0x{classID.Value:X8} is not implemented. ({NodeCacheManager.Names.Where(x => x.Key == Chunk.Remap(classID.Value)).Select(x => x.Value).FirstOrDefault() ?? "unknown class"})"); } NodeCacheManager.AvailableClassConstructors.TryGetValue(classID.Value, out Func <CMwNod>?constructor); if (constructor is null) { throw new ThisShouldNotHappenException(); } var node = (T)constructor(); node.SetIDAndChunks(); Parse(node, r, progress); return(node); }
public static T Parse <T>(GameBoxReader r, uint?classID = null, IProgress <GameBoxReadProgress> progress = null) where T : CMwNod { if (!classID.HasValue) { classID = r.ReadUInt32(); } if (classID == uint.MaxValue) { return(null); } classID = Remap(classID.Value); if (!NodeCacheManager.AvailableClasses.TryGetValue(classID.Value, out Type type)) { throw new NotImplementedException($"Node ID 0x{classID.Value:X8} is not implemented. ({NodeCacheManager.Names.Where(x => x.Key == Chunk.Remap(classID.Value)).Select(x => x.Value).FirstOrDefault() ?? "unknown class"})"); } var node = (T)Activator.CreateInstance(type); Parse(node, r, progress); return(node); }
/// <exception cref="TextFormatNotSupportedException">Text-formatted GBX files are not supported.</exception> internal bool Read(GameBoxReader reader) { if (!reader.HasMagic(GameBox.Magic)) { Log.Write("GBX magic missing! Corrupted file or not a GBX file.", ConsoleColor.Red); return(false); } Log.Write("GBX recognized!", ConsoleColor.Green); Version = reader.ReadInt16(); Log.Write("- Version: " + Version.ToString()); if (Version >= 3) { ByteFormat = (GameBoxByteFormat)reader.ReadByte(); Log.Write("- Byte format: " + ByteFormat.ToString()); if (ByteFormat == GameBoxByteFormat.Text) { throw new TextFormatNotSupportedException(); } CompressionOfRefTable = (GameBoxCompression)reader.ReadByte(); Log.Write("- Ref. table compression: " + CompressionOfRefTable.ToString()); CompressionOfBody = (GameBoxCompression)reader.ReadByte(); Log.Write("- Body compression: " + CompressionOfBody.ToString()); if (Version >= 4) { UnknownByte = (char)reader.ReadByte(); Log.Write("- Unknown byte: " + UnknownByte.ToString()); } ID = CMwNod.Remap(reader.ReadUInt32()); Log.Write("- Class ID: 0x" + ID.Value.ToString("X8")); if (Version >= 6) { var userDataSize = reader.ReadInt32(); Log.Write($"- User data size: {(userDataSize / 1024f).ToString()} kB"); if (userDataSize > 0) { UserData = reader.ReadBytes(userDataSize); } } NumNodes = reader.ReadInt32(); Log.Write("- Number of nodes: " + NumNodes.ToString()); } Log.Write("Header completed!", ConsoleColor.Green); return(true); }
public static NadeoPakList Parse(Stream stream) { using var r = new GameBoxReader(stream); var version = r.ReadByte(); var numPacks = r.ReadByte(); var crc32 = r.ReadUInt32(); var salt = r.ReadUInt32(); var nameKey = ComputeMD5("6611992868945B0B59536FC3226F3FD0" + salt); var packs = new NadeoPakListItem[numPacks]; for (var i = 0; i < numPacks; i++) { var flags = r.ReadByte(); var nameLength = r.ReadByte(); var encryptedName = r.ReadBytes(nameLength); var encryptedKeyString = r.ReadBytes(32); for (var j = 0; j < encryptedName.Length; j++) { encryptedName[j] ^= nameKey[j % nameKey.Length]; } var name = Encoding.ASCII.GetString(encryptedName); var keyStringKey = ComputeMD5(name + salt + "B97C1205648A66E04F86A1B5D5AF9862"); for (var j = 0; j < encryptedKeyString.Length; j++) { encryptedKeyString[j] ^= keyStringKey[j % keyStringKey.Length]; } var key = ComputeMD5(Encoding.ASCII.GetString(encryptedKeyString) + "NadeoPak"); packs[i] = new NadeoPakListItem(name, flags, key); } var signature = r.ReadBytes(0x10); return(new NadeoPakList(version, crc32, salt, packs, signature)); }
public void Read(GameBoxReader r) { var classId = r.ReadUInt32(); Version = r.ReadInt32(); if (Version < 3) { return; } var typeCount = r.ReadByte(); var types = new ScriptVariable[typeCount]; for (var i = 0; i < typeCount; i++) { var varType = r.ReadByte(); types[i] = (ScriptType)varType switch { ScriptType.Array => ReadScriptArray(r), ScriptType.Struct => ReadScriptStruct(out int _, r), _ => new ScriptVariable((ScriptType)varType), }; } var varCount = r.ReadByte(); var metadata = new ScriptVariable[varCount]; for (var i = 0; i < varCount; i++) { var metadataVarName = r.ReadString(StringLengthPrefix.Byte); var typeIndex = r.ReadByte(); var type = types[typeIndex]; metadata[i] = ReadType(type.Clone(), r); metadata[i].Name = metadataVarName; } Metadata = metadata.ToList(); var facade = r.ReadUInt32(); }
public override void Read(CGameCtnReplayRecord n, GameBoxReader r) { n.eventsDuration = r.ReadInt32(); if (n.eventsDuration != 0) { U01 = r.ReadInt32(); // All control names available in the game var controlNames = r.ReadArray(r1 => { // Maybe bindings r1.ReadInt32(); r1.ReadInt32(); return(r1.ReadString()); // Input name }); var numEntries = r.ReadInt32() - 1; n.controlEntries = new ControlEntry[numEntries]; for (var i = 0; i < numEntries; i++) { var time = TimeSpan.FromMilliseconds(r.ReadInt32() - 10000); var controlNameIndex = r.ReadInt32(); var data = r.ReadUInt32(); var name = controlNames[controlNameIndex]; switch (name) { case "Steer (analog)": // Data is bugged n.controlEntries[i] = new ControlEntryAnalog(true) { Name = name, Time = time, Data = data }; break; default: n.controlEntries[i] = new ControlEntry() { Name = name, Time = time, Data = data }; break; } } Array.Reverse(n.controlEntries); // Inputs are originally reversed U02 = r.ReadInt32(); } }
public override void Read(CGameCtnReplayRecord n, GameBoxReader r) { n.eventsDuration = r.ReadInt32(); if (n.eventsDuration != 0) { U01 = r.ReadInt32(); var controlNames = r.ReadArray(r1 => r1.ReadId()); var numEntries = r.ReadInt32(); U02 = r.ReadInt32(); n.controlEntries = new ControlEntry[numEntries]; for (var i = 0; i < numEntries; i++) { var time = TimeSpan.FromMilliseconds(r.ReadInt32() - 100000); var controlNameIndex = r.ReadByte(); var data = r.ReadUInt32(); var name = controlNames[controlNameIndex]; switch (name) { case "Steer": case "Gas": case "AccelerateReal": case "BrakeReal": n.controlEntries[i] = new ControlEntryAnalog() { Name = name, Time = time, Data = data }; break; default: n.controlEntries[i] = new ControlEntry() { Name = name, Time = time, Data = data }; break; } } } }
public override void Read(CGameCtnReplayRecord n, GameBoxReader r) { n.eventsDuration = r.ReadInt32(); if (n.eventsDuration == 0) { return; } U01 = r.ReadInt32(); var controlNames = r.ReadArray(r1 => r1.ReadId()); var numEntries = r.ReadInt32(); U02 = r.ReadInt32(); n.controlEntries = new ControlEntry[numEntries]; for (var i = 0; i < numEntries; i++) { var time = TimeSpan.FromMilliseconds(r.ReadInt32() - 100000); var controlNameIndex = r.ReadByte(); var data = r.ReadUInt32(); var name = controlNames[controlNameIndex]; n.controlEntries[i] = (string)name switch { "Steer" or "Gas" or "AccelerateReal" or "BrakeReal" => new ControlEntryAnalog(name) { Time = time, Data = data }, _ => new ControlEntry(name) { Time = time, Data = data }, }; } }
private void ReadFiles(GameBoxReader r, NadeoPakFolder[] folders) { var numFiles = r.ReadInt32(); var files = new NadeoPakFile[numFiles]; for (var i = 0; i < numFiles; i++) { var folderIndex = r.ReadInt32(); // index into folders var name = r.ReadString(); var unknown = r.ReadInt32(); var uncompressedSize = r.ReadInt32(); var compressedSize = r.ReadInt32(); var offset = r.ReadInt32(); var classID = CMwNod.Remap(r.ReadUInt32()); // indicates the type of the file var flags = r.ReadUInt64(); var folder = folders.ElementAtOrDefault(folderIndex); var file = new NadeoPakFile(this, folder, name, uncompressedSize, compressedSize, offset, classID, flags) { U01 = unknown }; files[i] = file; if (folder == null) { Files.Add(file); } else { folder.Files.Add(file); } } this.files = files; }
internal static void Parse <T>(T node, GameBoxReader r, IProgress <GameBoxReadProgress>?progress = null) where T : CMwNod { var stopwatch = Stopwatch.StartNew(); node.GBX = r.Body?.GBX; var type = node.GetType(); uint?previousChunkId = null; while (!r.BaseStream.CanSeek || r.BaseStream.Position < r.BaseStream.Length) { if (r.BaseStream.CanSeek && r.BaseStream.Position + 4 > r.BaseStream.Length) { Debug.WriteLine($"Unexpected end of the stream: {r.BaseStream.Position.ToString()}/{r.BaseStream.Length.ToString()}"); var bytes = r.ReadBytes((int)(r.BaseStream.Length - r.BaseStream.Position)); break; } var chunkId = r.ReadUInt32(); if (chunkId == 0xFACADE01) // no more chunks { break; } var logChunk = new StringBuilder("[") .Append(node.ClassName) .Append("] 0x") .Append(chunkId.ToString("X8")); if (r.BaseStream.CanSeek) // Decompressed body can always seek { logChunk.Append(" (") .Append(((float)r.BaseStream.Position / r.BaseStream.Length).ToString("0.00%")) .Append(')'); } if (node.GBX is null || !node.GBX.ID.HasValue || Remap(node.GBX.ID.Value) != node.ID) { logChunk.Insert(0, "~ "); } Log.Write(logChunk.ToString()); Chunk chunk; chunkId = Chunk.Remap(chunkId); var reflected = NodeCacheManager.AvailableChunkClasses[type].TryGetValue(chunkId, out Type? chunkClass); if (reflected && chunkClass is null) { throw new ThisShouldNotHappenException(); } var skippable = reflected && chunkClass !.BaseType !.GetGenericTypeDefinition() == typeof(SkippableChunk <>); // Unknown or skippable chunk if (!reflected || skippable) { var skip = r.ReadUInt32(); if (skip != 0x534B4950) { if (reflected) { break; } var logChunkError = $"[{node.ClassName}] 0x{chunkId.ToString("X8")} ERROR (wrong chunk format or unknown unskippable chunk)"; if (node.GBX is not null && node.GBX.ID.HasValue && Remap(node.GBX.ID.Value) == node.ID) { Log.Write(logChunkError, ConsoleColor.Red); } else { Log.Write("~ " + logChunkError, ConsoleColor.Red); } #if DEBUG // Read the rest of the body var streamPos = r.BaseStream.Position; var uncontrollableData = r.ReadToEnd(); r.BaseStream.Position = streamPos; #endif throw new ChunkParseException(chunkId, previousChunkId); /* Usually breaks in the current state and causes confusion * * var buffer = BitConverter.GetBytes(chunkID); * using (var restMs = new MemoryStream(ushort.MaxValue)) * { * restMs.Write(buffer, 0, buffer.Length); * * while (r.PeekUInt32() != 0xFACADE01) * restMs.WriteByte(r.ReadByte()); * * node.Rest = restMs.ToArray(); * } * Debug.WriteLine("FACADE found.");*/ } var chunkDataSize = r.ReadInt32(); var chunkData = new byte[chunkDataSize]; if (chunkDataSize > 0) { r.Read(chunkData, 0, chunkDataSize); } if (reflected) { var attributesAvailable = NodeCacheManager.AvailableChunkAttributes[type].TryGetValue( chunkId, out IEnumerable <Attribute>?attributes); if (!attributesAvailable) { throw new ThisShouldNotHappenException(); } if (attributes is null) { throw new ThisShouldNotHappenException(); } var ignoreChunkAttribute = default(IgnoreChunkAttribute); var chunkAttribute = default(ChunkAttribute); foreach (var att in attributes) { if (att is IgnoreChunkAttribute ignoreChunkAtt) { ignoreChunkAttribute = ignoreChunkAtt; } if (att is ChunkAttribute chunkAtt) { chunkAttribute = chunkAtt; } } if (chunkAttribute is null) { throw new ThisShouldNotHappenException(); } NodeCacheManager.AvailableChunkConstructors[type].TryGetValue(chunkId, out Func <Chunk>?constructor); if (constructor is null) { throw new ThisShouldNotHappenException(); } var c = constructor(); c.Node = node; ((ISkippableChunk)c).Data = chunkData; if (chunkData == null || chunkData.Length == 0) { ((ISkippableChunk)c).Discovered = true; } node.Chunks.Add(c); #if DEBUG c.Debugger.RawData = chunkData; #endif if (ignoreChunkAttribute == null) { c.OnLoad(); if (chunkAttribute.ProcessSync) { ((ISkippableChunk)c).Discover(); } } chunk = c; } else { Debug.WriteLine("Unknown skippable chunk: " + chunkId.ToString("X")); chunk = (Chunk)Activator.CreateInstance(typeof(SkippableChunk <>).MakeGenericType(type), node, chunkId, chunkData) !; #if DEBUG chunk.Debugger.RawData = chunkData; #endif node.Chunks.Add(chunk); } }
public static void Parse <T>(T node, GameBoxReader r, IProgress <GameBoxReadProgress> progress = null) where T : CMwNod { var stopwatch = Stopwatch.StartNew(); node.GBX = r.GBX; var type = node.GetType(); var chunks = new ChunkSet { Node = node }; node.Chunks = chunks; uint?previousChunk = null; while (!r.BaseStream.CanSeek || r.BaseStream.Position < r.BaseStream.Length) { if (r.BaseStream.CanSeek && r.BaseStream.Position + 4 > r.BaseStream.Length) { Debug.WriteLine($"Unexpected end of the stream: {r.BaseStream.Position}/{r.BaseStream.Length}"); var bytes = r.ReadBytes((int)(r.BaseStream.Length - r.BaseStream.Position)); break; } var chunkID = r.ReadUInt32(); if (chunkID == 0xFACADE01) // no more chunks { break; } else { var logChunk = $"[{node.ClassName}] 0x{chunkID:X8}"; if (r.BaseStream.CanSeek) { logChunk += $" ({(float)r.BaseStream.Position / r.BaseStream.Length:0.00%})"; } if (node.GBX?.ID.HasValue == true && Remap(node.GBX.ID.Value) == node.ID) { Log.Write(logChunk); } else { Log.Write($"~ {logChunk}"); } } Chunk chunk; var chunkRemapped = Chunk.Remap(chunkID); Type chunkClass = null; var reflected = ((chunkRemapped & 0xFFFFF000) == node.ID || NodeCacheManager.AvailableInheritanceClasses[type].Contains(chunkRemapped & 0xFFFFF000)) && (NodeCacheManager.AvailableChunkClasses[type].TryGetValue(chunkRemapped, out chunkClass) || NodeCacheManager.AvailableChunkClasses[type].TryGetValue(chunkID & 0xFFF, out chunkClass)); var skippable = reflected && chunkClass.BaseType.GetGenericTypeDefinition() == typeof(SkippableChunk <>); // Unknown or skippable chunk if (!reflected || skippable) { var skip = r.ReadUInt32(); if (skip != 0x534B4950) { if (chunkID != 0 && !reflected) { var logChunkError = $"[{node.ClassName}] 0x{chunkID:X8} ERROR (wrong chunk format or unknown unskippable chunk)"; if (node.GBX?.ID.HasValue == true && Remap(node.GBX.ID.Value) == node.ID) { Log.Write(logChunkError, ConsoleColor.Red); } else { Log.Write($"~ {logChunkError}", ConsoleColor.Red); } throw new Exception($"Wrong chunk format or unskippable chunk: 0x{chunkID:X8} (" + $"{NodeCacheManager.Names.Where(x => x.Key == Chunk.Remap(chunkID & 0xFFFFF000)).Select(x => x.Value).FirstOrDefault() ?? "unknown class"})" + $"\nPrevious chunk: 0x{previousChunk ?? 0:X8} (" + $"{(previousChunk.HasValue ? (NodeCacheManager.Names.Where(x => x.Key == Chunk.Remap(previousChunk.Value & 0xFFFFF000)).Select(x => x.Value).FirstOrDefault() ?? "unknown class") : "not a class")})"); /* Usually breaks in the current state and causes confusion * * var buffer = BitConverter.GetBytes(chunkID); * using (var restMs = new MemoryStream(ushort.MaxValue)) * { * restMs.Write(buffer, 0, buffer.Length); * * while (r.PeekUInt32() != 0xFACADE01) * restMs.WriteByte(r.ReadByte()); * * node.Rest = restMs.ToArray(); * } * Debug.WriteLine("FACADE found.");*/ } break; } var chunkDataSize = r.ReadInt32(); var chunkData = new byte[chunkDataSize]; if (chunkDataSize > 0) { r.Read(chunkData, 0, chunkDataSize); } if (reflected) { var ignoreChunkAttribute = chunkClass.GetCustomAttribute <IgnoreChunkAttribute>(); var constructor = Array.Find(chunkClass.GetConstructors(), x => x.GetParameters().Length == 0); if (constructor == null) { throw new ArgumentException($"{type.FullName} doesn't have a parameterless constructor."); } var c = (Chunk)constructor.Invoke(new object[0]); c.Node = node; c.GBX = node.GBX; ((ISkippableChunk)c).Data = chunkData; if (chunkData == null || chunkData.Length == 0) { ((ISkippableChunk)c).Discovered = true; } chunks.Add(c); if (ignoreChunkAttribute == null) { c.OnLoad(); if (chunkClass.GetCustomAttribute <ChunkAttribute>().ProcessSync) { ((ISkippableChunk)c).Discover(); } } chunk = c; } else { Debug.WriteLine("Unknown skippable chunk: " + chunkID.ToString("X")); chunk = (Chunk)Activator.CreateInstance(typeof(SkippableChunk <>).MakeGenericType(type), node, chunkRemapped, chunkData); chunk.GBX = node.GBX; chunks.Add(chunk); } } else // Known or unskippable chunk { var constructor = Array.Find(chunkClass.GetConstructors(), x => x.GetParameters().Length == 0); if (constructor == null) { throw new ArgumentException($"{type.FullName} doesn't have a parameterless constructor."); } var c = (Chunk)constructor.Invoke(new object[0]); c.Node = node; c.OnLoad(); chunks.Add(c); //r.Chunk = (Chunk)c; // Set chunk temporarily for reading var posBefore = r.BaseStream.Position; GameBoxReaderWriter gbxrw = new GameBoxReaderWriter(r); var attributes = chunkClass.GetCustomAttributes(); var ignoreChunkAttribute = default(IgnoreChunkAttribute); var autoReadWriteChunkAttribute = default(AutoReadWriteChunkAttribute); foreach (var att in attributes) { if (att is IgnoreChunkAttribute ignoreChunkAtt) { ignoreChunkAttribute = ignoreChunkAtt; } if (att is AutoReadWriteChunkAttribute autoReadWriteChunkAtt) { autoReadWriteChunkAttribute = autoReadWriteChunkAtt; } } try { if (ignoreChunkAttribute == null) { if (autoReadWriteChunkAttribute == null) { c.ReadWrite(node, gbxrw); } else { var unknown = new GameBoxWriter(c.Unknown, r.Lookbackable); var unknownData = r.ReadUntilFacade(); unknown.Write(unknownData, 0, unknownData.Length); } } else { throw new Exception($"Chunk 0x{chunkID & 0xFFF:x3} from class {node.ClassName} is known but its content is unknown to read."); } } catch (EndOfStreamException) { Debug.WriteLine($"Unexpected end of the stream while reading the chunk."); } c.Progress = (int)(r.BaseStream.Position - posBefore); chunk = c; } progress?.Report(new GameBoxReadProgress(GameBoxReadProgressStage.Body, (float)r.BaseStream.Position / r.BaseStream.Length, node.GBX, chunk)); previousChunk = chunkID; } stopwatch.Stop(); var logNodeCompletion = $"[{node.ClassName}] DONE! ({stopwatch.Elapsed.TotalMilliseconds}ms)"; if (node.GBX.ID.HasValue == true && Remap(node.GBX.ID.Value) == node.ID) { Log.Write(logNodeCompletion, ConsoleColor.Green); } else { Log.Write($"~ {logNodeCompletion}", ConsoleColor.Green); } }
public override void Read(CPlugEntRecordData n, GameBoxReader r, GameBoxWriter unknownW) { Version = r.ReadInt32(); UncompressedSize = r.ReadInt32(); CompressedSize = r.ReadInt32(); Data = r.ReadBytes(CompressedSize); // ... WIP ... Task.Run(() => { using (var ms = new MemoryStream(Data)) using (var cs = new CompressedStream(ms, System.IO.Compression.CompressionMode.Decompress)) using (var gbxr = new GameBoxReader(cs)) { var u01 = gbxr.ReadInt32(); var numSamples = gbxr.ReadInt32(); var objects = gbxr.ReadArray <object>(i => { var nodeId = gbxr.ReadUInt32(); Names.TryGetValue(nodeId, out string nodeName); return(new { id = nodeId, name = nodeName, rest = gbxr.ReadArray <int>(5) }); }); if (Version >= 2) { var objcts2 = gbxr.ReadArray <object>(i => { var u02 = gbxr.ReadInt32(); var u03 = gbxr.ReadInt32(); uint?clas = null; string clasName = null; if (Version >= 4) { clas = gbxr.ReadUInt32(); Names.TryGetValue(clas.Value, out clasName); } return(new object[] { u02, u03, clas, clasName }); }); } var u04 = gbxr.ReadByte(); var u05 = gbxr.ReadArray <int>(4); if (Version >= 6) { //var u06 = gbxr.ReadUInt32(); } var u07 = gbxr.ReadByte(); var u08 = gbxr.ReadByte(); if (Version >= 2) { var u09 = gbxr.ReadByte(); var u10 = gbxr.ReadArray <int>(3); var u11 = gbxr.ReadByte(); if (Version >= 3) { var u12 = gbxr.ReadByte(); if (Version == 7) { } if (Version >= 8) { var u13 = gbxr.ReadInt32(); } } } var u14 = gbxr.ReadArray <int>(5); } }); }
public void Read(GameBoxReader r) { var classId = r.ReadUInt32(); Version = r.ReadInt32(); var typeCount = r.ReadByte(); var types = new ScriptVariable[typeCount]; for (var i = 0; i < typeCount; i++) { var varType = r.ReadByte(); switch ((ScriptType)varType) { case ScriptType.Array: types[i] = ReadScriptArray(); break; case ScriptType.Struct: types[i] = ReadScriptStruct(out int defaultLength); break; default: types[i] = new ScriptVariable((ScriptType)varType); break; } } var varCount = r.ReadByte(); var metadata = new ScriptVariable[varCount]; for (var i = 0; i < varCount; i++) { var metadataVarName = r.ReadString(StringLengthPrefix.Byte); var typeIndex = r.ReadByte(); var type = types[typeIndex]; metadata[i] = ReadType(type.Clone()); metadata[i].Name = metadataVarName; } Metadata = metadata.ToList(); var facade = r.ReadUInt32(); ScriptArray ReadScriptArray() { ScriptVariable indexVar; var indexType = r.ReadByte(); // index if ((ScriptType)indexType == ScriptType.Struct) { indexVar = ReadScriptStruct(out int defaultLength); } else { indexVar = new ScriptVariable((ScriptType)indexType); } ScriptVariable valueVar; var arrayType = r.ReadByte(); // value if ((ScriptType)arrayType == ScriptType.Array) { valueVar = ReadScriptArray(); } else if ((ScriptType)arrayType == ScriptType.Struct) { valueVar = ReadScriptStruct(out int defaultLength); } else { valueVar = new ScriptVariable((ScriptType)arrayType); } ScriptArray array = new ScriptArray(new KeyValuePair <ScriptVariable, ScriptVariable>(indexVar, valueVar)); int counterArray = 0; while (r.ReadByte() == 0) { counterArray++; } r.BaseStream.Position -= 1; array.Unknown = counterArray; return(array); } ScriptStruct ReadScriptStruct(out int defaultLength) { var strc = new ScriptStruct(); var numMembers = r.ReadByte(); var structName = r.ReadString(); strc.StructName = structName; strc.Members = new ScriptVariable[numMembers]; defaultLength = 0; for (var i = 0; i < numMembers; i++) { ScriptVariable member; var memberName = r.ReadString(); var memberType = r.ReadByte(); switch ((ScriptType)memberType) { case ScriptType.Array: member = ReadScriptArray(); break; case ScriptType.Struct: member = ReadScriptStruct(out int defLength); defaultLength += defLength; break; default: member = new ScriptVariable((ScriptType)memberType); break; } switch (member.Type) { case ScriptType.Integer: r.ReadInt32(); defaultLength += 4; break; case ScriptType.Real: r.ReadSingle(); defaultLength += 4; break; case ScriptType.Vec2: r.ReadVec2(); defaultLength += 8; break; case ScriptType.Vec3: r.ReadVec3(); defaultLength += 12; break; case ScriptType.Int3: r.ReadInt3(); defaultLength += 12; break; case ScriptType.Int2: r.ReadInt2(); defaultLength += 8; break; case ScriptType.Array: break; case ScriptType.Struct: break; default: r.ReadByte(); defaultLength += 1; break; } member.Name = memberName; strc.Members[i] = member; } int counter = 0; while (r.ReadByte() == 0) { counter++; } r.BaseStream.Position -= 1; //int counter = 0; //while (r.ReadByte() == 0) counter++; // probably size of the struct in byte count? //r.BaseStream.Position -= 1; strc.Size = defaultLength + counter; // strc.Unknown = counter; //Progress += defaultLength; return(strc); } ScriptVariable ReadType(ScriptVariable type) { switch (type.Type) { case ScriptType.Boolean: type.Value = Convert.ToBoolean(r.ReadBoolean(true)); break; case ScriptType.Integer: type.Value = r.ReadInt32(); break; case ScriptType.Real: type.Value = r.ReadSingle(); break; case ScriptType.Text: type.Value = r.ReadString(StringLengthPrefix.Byte); break; case ScriptType.Vec2: type.Value = r.ReadVec2(); break; case ScriptType.Vec3: type.Value = r.ReadVec3(); break; case ScriptType.Int3: type.Value = r.ReadInt3(); break; case ScriptType.Int2: type.Value = r.ReadInt2(); break; case ScriptType.Array: var array = type as ScriptArray; var numElements = r.ReadByte(); if (numElements > 0) { ScriptVariable key; if (array.Reference.Key.Type == ScriptType.Void) { for (var i = 0; i < numElements; i++) { array.Elements[new ScriptVariable(ScriptType.Void) { Value = i }] = ReadType(array.Reference.Value.Clone()); } } else { key = ReadType(array.Reference.Key.Clone()); for (var i = 0; i < numElements; i++) { array.Elements[key] = ReadType(array.Reference.Value.Clone()); } } } break; case ScriptType.Struct: var strc = type as ScriptStruct; for (var i = 0; i < strc.Members.Length; i++) { strc.Members[i] = ReadType(strc.Members[i]); } break; default: throw new Exception(type.Type.ToString()); } return(type); } }
public override void Read(CPlugEntRecordData n, GameBoxReader r) { Version = r.ReadInt32(); // 10 UncompressedSize = r.ReadInt32(); CompressedSize = r.ReadInt32(); data = r.ReadBytes(CompressedSize); n.samples = Task.Run(() => { var samples = new ObservableCollection <Sample>(); using var ms = new MemoryStream(data); using var cs = new CompressedStream(ms, CompressionMode.Decompress); using var r = new GameBoxReader(cs); var u01 = r.ReadInt32(); var ghostLength = r.ReadInt32(); // milliseconds var objects = r.ReadArray <object>(r => { var nodeId = r.ReadUInt32(); NodeCacheManager.Names.TryGetValue(nodeId, out string?nodeName); return(new { nodeId, nodeName, obj_u01 = r.ReadInt32(), obj_u02 = r.ReadInt32(), obj_u03 = r.ReadInt32(), mwbuffer = r.ReadInt32(), obj_u05 = r.ReadInt32() }); }); if (Version >= 2) { var objcts2 = r.ReadArray <object>(r => { var u02 = r.ReadInt32(); var u03 = r.ReadInt32(); uint?clas = null; string?clasName = null; if (Version >= 4) { clas = r.ReadUInt32(); NodeCacheManager.Names.TryGetValue(clas.Value, out clasName); } return(new { u02, u03, clas, clasName }); }); } var u04 = r.ReadByte(); while (u04 != 0) { var bufferType = r.ReadInt32(); var u06 = r.ReadInt32(); var u07 = r.ReadInt32(); var ghostLengthFinish = r.ReadInt32(); // ms if (Version < 6) { // temp_79f24995b2b->field_0x28 = temp_79f24995b2b->field_0xc } else { var u08 = r.ReadInt32(); } // Reads byte on every loop until the byte is 0, should be 1 otherwise for (byte x; (x = r.ReadByte()) != 0;) { var timestamp = r.ReadInt32(); var buffer = r.ReadBytes(); // MwBuffer if (buffer.Length > 0) { using var bufferMs = new MemoryStream(buffer); using var bufferR = new GameBoxReader(bufferMs); var sampleProgress = (int)bufferMs.Position; var sample = new Sample(buffer) { BufferType = (byte)bufferType }; switch (bufferType) { case 0: break; case 2: { bufferMs.Position = 5; var(position, rotation, speed, velocity) = bufferR.ReadTransform(); // Only position matches sample.Timestamp = TimeSpan.FromMilliseconds(timestamp); sample.Position = position; sample.Rotation = rotation; sample.Speed = speed * 3.6f; sample.Velocity = velocity; break; } case 4: { bufferMs.Position = 5; var rpmByte = bufferR.ReadByte(); bufferMs.Position = 14; var steerByte = bufferR.ReadByte(); var steer = ((steerByte / 255f) - 0.5f) * 2; bufferMs.Position = 91; var gearByte = bufferR.ReadByte(); var gear = gearByte / 5f; sample.Gear = gear; sample.RPM = rpmByte; sample.Steer = steer; bufferMs.Position = 15; var u15 = bufferR.ReadByte(); bufferMs.Position = 18; var brakeByte = bufferR.ReadByte(); var brake = brakeByte / 255f; var gas = u15 / 255f + brake; sample.Brake = brake; sample.Gas = gas; bufferMs.Position = 47; var(position, rotation, speed, velocity) = bufferR.ReadTransform(); sample.Timestamp = TimeSpan.FromMilliseconds(timestamp); sample.Position = position; sample.Rotation = rotation; sample.Speed = speed * 3.6f; sample.Velocity = velocity; break; } case 10: break; default: break; } samples.Add(sample); } } u04 = r.ReadByte(); if (Version >= 2) { while (r.ReadByte() != 0) { var type = r.ReadInt32(); var timestamp = r.ReadInt32(); var buffer = r.ReadBytes(); // MwBuffer } } } if (Version >= 3) { while (r.ReadByte() != 0) { var u19 = r.ReadInt32(); var u20 = r.ReadInt32(); var u21 = r.ReadBytes(); // MwBuffer } if (Version == 7) { while (r.ReadByte() != 0) { var u23 = r.ReadInt32(); var u24 = r.ReadBytes(); // MwBuffer } } if (Version >= 8) { var u23 = r.ReadInt32(); if (u23 != 0) { if (Version == 8) { while (r.ReadByte() != 0) { var u25 = r.ReadInt32(); var u26 = r.ReadBytes(); // MwBuffer } } else { while (r.ReadByte() != 0) { var u28 = r.ReadInt32(); var u29 = r.ReadBytes(); // MwBuffer var u30 = r.ReadBytes(); // MwBuffer } if (Version >= 10) { var period = r.ReadInt32(); } } } } } return(samples); }); }