Exemple #1
0
    /// <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);
    }
Exemple #2
0
        public override void Read(CGameCtnBlockInfoMobil n, GameBoxReader r)
        {
            Version = r.ReadInt32();
            r.ReadByte();
            var num = r.ReadInt32();

            if (num == 16777216) // TODO: figure out why
            {
                r.ReadSingle();
                r.ReadSingle();

                r.ReadSingle();
                r.ReadSingle();

                r.ReadSingle();
                r.ReadSingle();
            }

            if (Version >= 20)
            {
                r.ReadInt32();
                r.ReadInt32();
            }

            r.ReadInt32();
            r.ReadInt32();
            r.ReadInt32();
            r.ReadInt32();
            r.ReadInt32();
            r.ReadInt32();
            r.ReadInt32();

            if (Version >= 20)
            {
                r.ReadInt32();
                r.ReadInt32();
                r.ReadInt32(); // 3

                r.ReadInt32();
                r.ReadInt32();
                r.ReadInt32();
                r.ReadInt32();
                r.ReadByte();
                r.ReadVec3();
                n.RoadChunks = r.ReadArray(r => r.ReadNodeRef <CPlugRoadChunk>());
            }
        }
 public override void Read(CGameCtnCollection n, GameBoxReader r, GameBoxWriter unknownW)
 {
     _ = r.ReadByte();
     _ = r.ReadString();
     _ = r.ReadInt32();
     _ = r.ReadString();
     _ = r.ReadArray <int>(3);
 }
    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();
    }
Exemple #5
0
    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 override void Read(CGameCtnCollection n, GameBoxReader r, GameBoxWriter unknownW)
 {
     Version        = r.ReadByte();
     n.CollectionID = r.ReadByte();
     _ = r.ReadBytes(6);
     n.CollectionPackMask = r.ReadByte();
     n.DisplayName        = r.ReadString();
     _ = r.ReadInt32();
     n.CollectionIcon = r.ReadString();
     _ = r.ReadArray <int>(2);
     n.BlockInfoFlat = r.ReadId(this);
     n.Vehicle       = r.ReadIdent(this);
     _ = r.ReadInt32();
     _ = r.ReadArray <float>(4);
     n.LoadingScreen = r.ReadString();
     _ = r.ReadArray <int>(7);
     _ = r.ReadString();
     _ = r.ReadInt32();
 }
    private static ScriptArray ReadScriptArray(GameBoxReader r)
    {
        ScriptVariable indexVar;

        var indexType = r.ReadByte(); // index

        if ((ScriptType)indexType == ScriptType.Struct)
        {
            indexVar = ReadScriptStruct(out int _, r);
        }
        else
        {
            indexVar = new ScriptVariable((ScriptType)indexType);
        }

        var arrayType = r.ReadByte(); // value

        var valueVar = (ScriptType)arrayType switch
        {
            ScriptType.Array => ReadScriptArray(r),
            ScriptType.Struct => ReadScriptStruct(out int _, r),
            _ => new ScriptVariable((ScriptType)arrayType),
        };

        var 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);
    }
Exemple #8
0
            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;
                        }
                    }
                }
            }
Exemple #9
0
        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
                    },
                };
            }
        }
Exemple #10
0
 public override void Read(CGameCtnBlockInfo n, GameBoxReader r) // WIP
 {
     n.BlockName = r.ReadId();
     r.ReadInt32();
     r.ReadInt32();
     r.ReadInt32();
     r.ReadInt32();
     r.ReadInt32();
     r.ReadInt32();
     r.ReadInt32();
     r.ReadArray(r => r.ReadNodeRef <CGameCtnBlockUnitInfo>());
     r.ReadArray(r => r.ReadNodeRef <CGameCtnBlockUnitInfo>());
     r.ReadInt32();
     r.ReadInt32();
     r.ReadNodeRef <CSceneMobil>();
     r.ReadInt32();
     r.ReadInt32();
     r.ReadNodeRef <CSceneMobil>();
     r.ReadByte();
     r.ReadInt32();
     r.ReadInt32();
 }
Exemple #11
0
            public override void Read(CGameCtnReplayRecord n, GameBoxReader r, GameBoxWriter unknownW)
            {
                Version = r.ReadInt32();

                if (Version >= 2)
                {
                    n.MapInfo  = r.ReadIdent();
                    n.Time     = r.ReadTimeSpan();
                    n.Nickname = r.ReadString();

                    if (Version >= 6)
                    {
                        n.DriverLogin = r.ReadString();

                        if (Version >= 8)
                        {
                            U01       = r.ReadByte();
                            n.TitleID = r.ReadId();
                        }
                    }
                }
            }
Exemple #12
0
        public override void Read(CGameCtnReplayRecord n, GameBoxReader r)
        {
            Version = r.ReadInt32();

            if (Version >= 2)
            {
                n.mapInfo        = r.ReadIdent();
                n.time           = r.ReadInt32_msn();
                n.playerNickname = r.ReadString();

                if (Version >= 6)
                {
                    n.playerLogin = r.ReadString();

                    if (Version >= 8)
                    {
                        U01       = r.ReadByte();
                        n.titleID = r.ReadId();
                    }
                }
            }
        }
Exemple #13
0
            public override void Read(CGameCtnMacroBlockInfo n, GameBoxReader r, GameBoxWriter unknownW)
            {
                n.Blocks = r.ReadArray(i =>
                {
                    Int3?coord        = null;
                    Direction?dir     = null;
                    Vec3?position     = null;
                    Vec3?pitchYawRoll = null;

                    var ver   = r.ReadInt32();
                    var ident = r.ReadIdent();
                    int flags = 0;

                    if (ver >= 2)
                    {
                        if (ver < 5)
                        {
                        }

                        flags = r.ReadInt32();

                        if (ver >= 4)
                        {
                            if ((flags & (1 << 26)) != 0) // free block
                            {
                                position     = r.ReadVec3();
                                pitchYawRoll = r.ReadVec3();
                            }
                            else
                            {
                                coord = (Int3)r.ReadByte3();
                                dir   = (Direction)r.ReadByte();
                            }
                        }
                    }

                    if (ver >= 3)
                    {
                        if (r.ReadNodeRef() != null)
                        {
                            throw new NotImplementedException();
                        }
                    }

                    if (ver >= 4)
                    {
                        if (r.ReadNodeRef() != null)
                        {
                            throw new NotImplementedException();
                        }
                    }

                    var correctFlags = flags & 15;

                    if ((flags & 0x20000) != 0) // Fixes inner pillars of some blocks
                    {
                        correctFlags |= 0x400000;
                    }

                    if ((flags & 0x10000) != 0) // Fixes ghost blocks
                    {
                        correctFlags |= 0x10000000;
                    }

                    var block = new CGameCtnBlock()
                    {
                        BlockInfo = ident,
                        Coord     = coord.GetValueOrDefault(),
                        Direction = dir.GetValueOrDefault(),
                        Flags     = correctFlags
                    };

                    if ((flags & (1 << 26)) != 0)
                    {
                        block.IsFree = true;
                        block.AbsolutePositionInMap += position.GetValueOrDefault();
                        block.PitchYawRoll          += pitchYawRoll.GetValueOrDefault();
                    }

                    return(block);
                }).Where(x => x != null).ToArray();
            }
Exemple #14
0
            public override void Read(CGameCtnMacroBlockInfo n, GameBoxReader r, GameBoxWriter unknownW)
            {
                Version = r.ReadInt32();

                n.AnchoredObjects = r.ReadArray(i =>
                {
                    var v = r.ReadInt32();

                    var itemModel = r.ReadIdent();

                    Vec3 pitchYawRoll  = default;
                    Vec3 pivotPosition = default;
                    float scale        = 1;

                    if (v < 3)
                    {
                        var quarterY = r.ReadByte();

                        if (v != 0)
                        {
                            var additionalDir = r.ReadByte();
                        }
                    }
                    else
                    {
                        pitchYawRoll = r.ReadVec3();
                    }

                    var blockCoord = r.ReadInt3();
                    var lookback   = r.ReadId();
                    var pos        = r.ReadVec3();

                    if (v < 5)
                    {
                        r.ReadInt32();
                    }
                    if (v < 6)
                    {
                        r.ReadInt32();
                    }
                    if (v >= 6)
                    {
                        r.ReadInt16(); // 0
                    }
                    if (v >= 7)
                    {
                        pivotPosition = r.ReadVec3();
                    }
                    if (v >= 8)
                    {
                        r.ReadNodeRef(); // probably waypoint
                    }
                    if (v >= 9)
                    {
                        scale = r.ReadSingle(); // 1
                    }
                    if (v >= 10)
                    {
                        r.ReadArray <int>(3); // 0 1 -1
                    }
                    return(new CGameCtnAnchoredObject()
                    {
                        ItemModel = itemModel,
                        PitchYawRoll = pitchYawRoll,
                        BlockUnitCoord = (Byte3)blockCoord,
                        AbsolutePositionInMap = pos,
                        PivotPosition = pivotPosition,
                        Scale = scale,
                    });
                });

                var num = r.ReadInt32();

                if (num == 1)
                {
                    r.ReadInt32();
                    r.ReadInt32();
                }
            }
Exemple #15
0
            public override void Read(CPlugEntRecordData n, GameBoxReader r)
            {
                Version          = r.ReadInt32();
                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 gbxr = new GameBoxReader(cs))
                            {
                                var u01         = gbxr.ReadInt32();
                                var ghostLength = gbxr.ReadInt32(); // milliseconds
                                var objects     = gbxr.ReadArray <object>(r1 =>
                                {
                                    var nodeId = r1.ReadUInt32();
                                    NodeCacheManager.Names.TryGetValue(nodeId, out string nodeName);

                                    return(new
                                    {
                                        nodeId,
                                        nodeName,
                                        obj_u01 = r1.ReadInt32(),
                                        obj_u02 = r1.ReadInt32(),
                                        obj_u03 = r1.ReadInt32(),
                                        mwbuffer = r1.ReadInt32(),
                                        obj_u05 = r1.ReadInt32()
                                    });
                                });

                                if (Version >= 2)
                                {
                                    var objcts2 = gbxr.ReadArray <object>(r1 =>
                                    {
                                        var u02 = r1.ReadInt32();
                                        var u03 = r1.ReadInt32();

                                        uint?clas       = null;
                                        string clasName = null;
                                        if (Version >= 4)
                                        {
                                            clas = r1.ReadUInt32();
                                            NodeCacheManager.Names.TryGetValue(clas.Value, out clasName);
                                        }

                                        return(new
                                        {
                                            u02,
                                            u03,
                                            clas,
                                            clasName
                                        });
                                    });
                                }

                                var u04 = gbxr.ReadByte();
                                while (u04 != 0)
                                {
                                    var bufferType        = gbxr.ReadInt32();
                                    var u06               = gbxr.ReadInt32();
                                    var u07               = gbxr.ReadInt32();
                                    var ghostLengthFinish = gbxr.ReadInt32(); // ms

                                    if (Version < 6)
                                    {
                                        // temp_79f24995b2b->field_0x28 = temp_79f24995b2b->field_0xc
                                    }
                                    else
                                    {
                                        var u08 = gbxr.ReadInt32();
                                    }

                                    // Reads byte on every loop until the byte is 0, should be 1 otherwise
                                    for (byte x; (x = gbxr.ReadByte()) != 0;)
                                    {
                                        var timestamp = gbxr.ReadInt32();
                                        var buffer    = gbxr.ReadBytes(); // MwBuffer

                                        if (buffer.Length > 0)
                                        {
                                            var unknownData = new byte[buffer.Length];

                                            using (var bufMs = new MemoryStream(buffer))
                                                using (var bufR = new GameBoxReader(bufMs))
                                                {
                                                    var sampleProgress = (int)bufMs.Position;

                                                    Sample sample = new Sample()
                                                    {
                                                        BufferType = (byte)bufferType
                                                    };

                                                    switch (bufferType)
                                                    {
                                                    case 0:
                                                        break;

                                                    case 2:
                                                        var buf2unknownData = bufR.ReadBytes(5);
                                                        Buffer.BlockCopy(buf2unknownData, 0, unknownData, 0, buf2unknownData.Length);

                                                        var(position, rotation, speed, velocity) = bufR.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:
                                                        var buf4unknownData = bufR.ReadBytes(47);
                                                        Buffer.BlockCopy(buf4unknownData, 0, unknownData, 0, buf4unknownData.Length);

                                                        var buf4transform = bufR.ReadTransform();

                                                        var buf4unknownData2 = bufR.ReadBytes(4);

                                                        sample.Timestamp = TimeSpan.FromMilliseconds(timestamp);
                                                        sample.Position  = buf4transform.position;
                                                        sample.Rotation  = buf4transform.rotation;
                                                        sample.Speed     = buf4transform.speed * 3.6f;
                                                        sample.Velocity  = buf4transform.velocity;
                                                        sample.Unknown   = buf4unknownData;

                                                        break;

                                                    case 10:
                                                        break;

                                                    default:
                                                        break;
                                                    }

                                                    sampleProgress = (int)(bufMs.Position - sampleProgress);

                                                    var moreUnknownData = bufR.ReadBytes((int)bufMs.Length - sampleProgress);
                                                    Buffer.BlockCopy(moreUnknownData, 0, unknownData, sampleProgress, moreUnknownData.Length);

                                                    sample.Unknown = unknownData;

                                                    samples.Add(sample);
                                                }
                                        }
                                    }

                                    u04 = gbxr.ReadByte();

                                    if (Version >= 2)
                                    {
                                        for (byte x; (x = gbxr.ReadByte()) != 0;)
                                        {
                                            var type      = gbxr.ReadInt32();
                                            var timestamp = gbxr.ReadInt32();
                                            var buffer    = gbxr.ReadBytes(); // MwBuffer
                                        }
                                    }
                                }

                                if (Version >= 3)
                                {
                                    for (byte x; (x = gbxr.ReadByte()) != 0;)
                                    {
                                        var u19 = gbxr.ReadInt32();
                                        var u20 = gbxr.ReadInt32();
                                        var u21 = gbxr.ReadBytes(); // MwBuffer
                                    }

                                    if (Version == 7)
                                    {
                                        for (byte x; (x = gbxr.ReadByte()) != 0;)
                                        {
                                            var u23 = gbxr.ReadInt32();
                                            var u24 = gbxr.ReadBytes(); // MwBuffer
                                        }
                                    }

                                    if (Version >= 8)
                                    {
                                        var u23 = gbxr.ReadInt32();

                                        if (u23 != 0)
                                        {
                                            if (Version == 8)
                                            {
                                                for (byte x; (x = gbxr.ReadByte()) != 0;)
                                                {
                                                    var u25 = gbxr.ReadInt32();
                                                    var u26 = gbxr.ReadBytes(); // MwBuffer
                                                }
                                            }
                                            else
                                            {
                                                for (byte x; (x = gbxr.ReadByte()) != 0;)
                                                {
                                                    var u28 = gbxr.ReadInt32();
                                                    var u29 = gbxr.ReadBytes(); // MwBuffer
                                                    var u30 = gbxr.ReadBytes(); // MwBuffer
                                                }

                                                if (Version >= 10)
                                                {
                                                    var period = gbxr.ReadInt32();
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                    return(samples);
                });
            }
Exemple #16
0
        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, 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);
                            }
                });
            }
    private static ScriptVariable ReadType(ScriptVariable type, GameBoxReader r)
    {
        switch (type.Type)
        {
        case ScriptType.Boolean:
            type.Value = 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 = (ScriptArray)type;

            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(), r);
                    }
                }
                else
                {
                    key = ReadType(array.Reference.Key.Clone(), r);
                    for (var i = 0; i < numElements; i++)
                    {
                        array.Elements[key] = ReadType(array.Reference.Value.Clone(), r);
                    }
                }
            }
            break;

        case ScriptType.Struct:
            var strc = (ScriptStruct)type;
            for (var i = 0; i < strc.Members.Length; i++)
            {
                strc.Members[i] = ReadType(strc.Members[i], r);
            }
            break;

        default:
            throw new Exception(type.Type.ToString());
        }

        return(type);
    }
    private static ScriptStruct ReadScriptStruct(out int defaultLength, GameBoxReader r)
    {
        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(r);
                break;

            case ScriptType.Struct:
                member         = ReadScriptStruct(out int defLength, r);
                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);
    }
 public override void Read(CGameCtnCollection n, GameBoxReader r)
 {
     _ = r.ReadByte();
     _ = r.ReadString();
 }
        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);
            });
        }