Ejemplo n.º 1
0
 public override void Write(CPlugEntRecordData n, GameBoxWriter w)
 {
     w.Write(Version);
     w.Write(UncompressedSize);
     w.Write(CompressedSize);
     w.WriteBytes(data);
 }
Ejemplo n.º 2
0
 public override void Write(CPlugEntRecordData n, GameBoxWriter w)
 {
     w.Write(Version);
     w.Write(UncompressedSize);
     w.Write(CompressedSize);
     w.Write(Data, 0, Data.Length);
 }
Ejemplo n.º 3
0
        public void Write(GameBoxWriter w)
        {
            w.Write(ExternalNodes.Length);
            w.Write(RootFolder.Folders.Count);

            // ...
        }
Ejemplo n.º 4
0
 public override void Write(CGameCtnMediaBlockFxBloom n, GameBoxWriter w, GameBoxReader unknownR)
 {
     w.Write(n.Keys, x =>
     {
         w.Write(x.Time);
         w.Write(x.Intensity);
         w.Write(x.Sensitivity);
     });
 }
 public override void Write(CGameCtnMediaBlockFxBlurDepth n, GameBoxWriter w, GameBoxReader unknownR)
 {
     w.Write(n.Keys, x =>
     {
         w.Write(x.Time);
         w.Write(x.LensSize);
         w.Write(x.ForceFocus);
         w.Write(x.FocusZ);
     });
 }
Ejemplo n.º 6
0
            public override void Write(CGameCtnMediaClipGroup n, GameBoxWriter w)
            {
                w.Write(n.ClipsVersion);

                w.Write(n.Clips, (x, w1) => w1.Write(x.Item1));
                w.Write(n.Clips, (x, w1) =>
                {
                    w1.Write(x.Item2.Coords, (y, w2) => w2.Write(y));
                });
            }
            public override void Write(CGameCtnMediaBlockDirtyLens n, GameBoxWriter w, GameBoxReader unknownR)
            {
                w.Write(Version);

                w.Write(n.Keys, x =>
                {
                    w.Write(x.Time);
                    w.Write(x.Intensity);
                });
            }
Ejemplo n.º 8
0
        public override void Write(CGameCtnMediaClipGroup n, GameBoxWriter w)
        {
            w.Write(n.ClipsVersion);

            w.Write(n.Clips, (x, w1) => w1.Write(x.Clip));
            w.Write(n.Clips, (x, w1) =>
            {
                w1.Write(x.Trigger.Coords, (y, w2) => w2.Write(y));
                w1.Write(x.Trigger.U01);
                w1.Write(x.Trigger.U02);
                w1.Write(x.Trigger.U03);
                w1.Write(x.Trigger.U04);
            });
        }
Ejemplo n.º 9
0
            public override void Write(CGameCtnMediaClipGroup n, GameBoxWriter w, GameBoxReader unknownR)
            {
                w.Write(Version);

                w.Write(n.Clips, x => w.Write(x.Item1));
                w.Write(n.Clips, x =>
                {
                    var trigger = x.Item2;

                    w.Write(trigger.Coords, y => w.Write(y));
                    w.Write(trigger.U01);
                    w.Write(trigger.U02);
                    w.Write(trigger.U03);
                    w.Write(trigger.U04);
                });
            }
Ejemplo n.º 10
0
            public override void Write(CGameCtnMediaClipGroup n, GameBoxWriter w)
            {
                w.Write(n.ClipsVersion);

                w.Write(n.Clips, (x, w1) => w1.Write(x.Item1));
                w.Write(n.Clips, (x, w1) =>
                {
                    var trigger = x.Item2;

                    w1.Write(trigger.U01);
                    w1.Write(trigger.U02);
                    w1.Write(trigger.U03);
                    w1.Write(trigger.U04);
                    w1.Write((int)trigger.Condition);
                    w1.Write(trigger.ConditionValue);
                    w1.Write(trigger.Coords, (y, w2) => w2.Write(y));
                });
            }
Ejemplo n.º 11
0
    /// <exception cref="IOException">An I/O error occurs.</exception>
    /// <exception cref="ObjectDisposedException">The stream is closed.</exception>
    /// <exception cref="MissingLzoException"></exception>
    public void Write(GameBoxWriter w, IDRemap remap = default)
    {
        GBX.Remap = remap;

        if (GBX.Header.CompressionOfBody == GameBoxCompression.Uncompressed)
        {
            GBX.Node.Write(w);
            return;
        }

        using var msBody   = new MemoryStream();
        using var gbxwBody = new GameBoxWriter(msBody, body: this);

        GBX.Node.Write(gbxwBody, remap);

        var buffer = msBody.ToArray();

        var output = Lzo.Compress(buffer);

        w.Write((int)msBody.Length); // Uncompressed
        w.Write(output.Length);      // Compressed
        w.WriteBytes(output);        // Compressed body data
    }
Ejemplo n.º 12
0
            public override void Write(CGameCtnMediaBlockFog n, GameBoxWriter w, GameBoxReader unknownR)
            {
                w.Write(Version);

                w.Write(n.Keys, x =>
                {
                    w.Write(x.Time);
                    w.Write(x.Intensity);
                    w.Write(x.SkyIntensity);
                    w.Write(x.Distance);

                    if (Version >= 1)
                    {
                        w.Write(x.Coefficient.GetValueOrDefault(1));
                        w.Write(x.Coefficient.GetValueOrDefault());

                        if (Version >= 2)
                        {
                            w.Write(x.CloudsOpacity.GetValueOrDefault(1));
                            w.Write(x.CloudsSpeed.GetValueOrDefault(1));
                        }
                    }
                });
            }
Ejemplo n.º 13
0
        public override void Write(CGameCtnMediaClipGroup n, GameBoxWriter w)
        {
            w.Write(n.ClipsVersion);

            w.Write(n.Clips, (x, w) => w.Write(x.Clip));
            w.Write(n.Clips, (x, w) =>
            {
                w.Write(x.Trigger.Coords, (y, w) => w.Write(y));
            });
        }
Ejemplo n.º 14
0
            public override void Write(CGameCtnMediaClipGroup n, GameBoxWriter w, GameBoxReader unknownR)
            {
                w.Write(Version);

                w.Write(n.Clips, x => w.Write(x.Item1));
                w.Write(n.Clips, x =>
                {
                    w.Write(x.Item2.Coords, y => w.Write(y));
                });
            }
 public override void Write(CGameCtnMediaBlockCameraCustom n, GameBoxWriter w, GameBoxReader unknownR)
 {
     w.Write(n.Keys?.ToArray(), x =>
     {
         w.Write(x.Time);
         w.Write((int)x.Unknown.ElementAtOrDefault(0));
         w.Write((int)x.Unknown.ElementAtOrDefault(1));
         w.Write((int)x.Unknown.ElementAtOrDefault(2));
         w.Write(x.Position);
         w.Write(x.PitchYawRoll);
         w.Write(x.FOV);
         w.Write((int)x.Unknown.ElementAtOrDefault(3));
         w.Write((int)x.Unknown.ElementAtOrDefault(4));
         w.Write((int)x.Unknown.ElementAtOrDefault(5));
         w.Write((int)x.Unknown.ElementAtOrDefault(6));
         w.Write(x.TargetPosition.GetValueOrDefault());
         w.Write(x.LeftTangent);
         w.Write(x.RightTangent);
     });
 }
Ejemplo n.º 16
0
        public void Write(GameBoxWriter w, IDRemap remap)
        {
            var stopwatch = Stopwatch.StartNew();

            int counter = 0;

            var type = GetType();
            var writingNotSupported = type.GetCustomAttribute <WritingNotSupportedAttribute>() != null;

            if (writingNotSupported)
            {
                throw new NotSupportedException($"Writing of {type.Name} is not supported.");
            }

            foreach (Chunk chunk in Chunks)
            {
                counter++;

                var logChunk = $"[{ClassName}] 0x{chunk.ID:X8} ({(float)counter / Chunks.Count:0.00%})";
                if (GBX.ID.HasValue == true && Remap(GBX.ID.Value) == ID)
                {
                    Log.Write(logChunk);
                }
                else
                {
                    Log.Write($"~ {logChunk}");
                }

                chunk.Node             = this;
                chunk.Unknown.Position = 0;

                if (chunk is ILookbackable l)
                {
                    l.IdWritten = false;
                    l.IdStrings.Clear();
                }

                using (var ms = new MemoryStream())
                    using (var msW = new GameBoxWriter(ms, w.Lookbackable))
                    {
                        var rw = new GameBoxReaderWriter(msW);

                        try
                        {
                            if (chunk is ISkippableChunk s && !s.Discovered)
                            {
                                s.Write(msW);
                            }
                            else if (!Attribute.IsDefined(chunk.GetType(), typeof(AutoReadWriteChunkAttribute)))
                            {
                                chunk.ReadWrite(this, rw);
                            }
                            else
                            {
                                msW.Write(chunk.Unknown.ToArray(), 0, (int)chunk.Unknown.Length);
                            }

                            w.Write(Chunk.Remap(chunk.ID, remap));

                            if (chunk is ISkippableChunk)
                            {
                                w.Write(0x534B4950);
                                w.Write((int)ms.Length);
                            }

                            w.Write(ms.ToArray(), 0, (int)ms.Length);
                        }
Ejemplo n.º 17
0
        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);
            }
        }
Ejemplo n.º 18
0
 public override void Write(CGameCtnMediaBlockCameraPath n, GameBoxWriter w, GameBoxReader unknownR)
 {
     w.Write(n.Keys, x =>
     {
         w.Write(x.Time);
         w.Write(x.Position);
         w.Write(x.PitchYawRoll);
         w.Write(x.FOV);
         w.Write(x.AnchorRot);
         w.Write(x.Anchor);
         w.Write(x.AnchorVis);
         w.Write(x.Target);
         w.Write(x.TargetPosition);
         w.Write((float)x.Unknown[0]);
         w.Write((float)x.Unknown[1]);
         w.Write((float)x.Unknown[2]);
         w.Write((float)x.Unknown[3]);
         w.Write((float)x.Unknown[4]);
     });
 }
Ejemplo n.º 19
0
 public override void Write(CGameCtnMediaBlockFxColors n, GameBoxWriter w, GameBoxReader unknownR)
 {
     w.Write(n.Keys, x =>
     {
         w.Write(x.Time);
         w.Write(x.Intensity);
         w.Write(x.BlendZ);
         w.Write(x.Distance);
         w.Write(x.FarDistance);
         w.Write(x.Inverse);
         w.Write(x.Hue);
         w.Write(x.Saturation);
         w.Write(x.Brightness);
         w.Write(x.Contrast);
         w.Write(x.RGB);
         w.Write(x.U01);
         w.Write(x.U02);
         w.Write(x.U03);
         w.Write(x.U04);
         w.Write(x.FarInverse);
         w.Write(x.FarHue);
         w.Write(x.FarSaturation);
         w.Write(x.FarBrightness);
         w.Write(x.FarContrast);
         w.Write(x.FarRGB);
         w.Write(x.FarU01);
         w.Write(x.FarU02);
         w.Write(x.FarU03);
         w.Write(x.FarU04);
     });
 }
Ejemplo n.º 20
0
    internal void Write(GameBoxWriter w)
    {
        var allFiles = GetAllFiles();
        var numFiles = allFiles.Count();

        w.Write(numFiles);

        if (numFiles <= 0)
        {
            return;
        }

        w.Write(AncestorLevel);
        w.Write(Folders.Count);

        WriteFolders(Folders);

        void WriteFolders(IEnumerable <Folder> folders)
        {
            if (folders == null)
            {
                return;
            }

            foreach (var folder in folders)
            {
                w.Write(folder.Name);
                w.Write(folder.Folders.Count);

                WriteFolders(folder.Folders);
            }
        }

        foreach (var file in allFiles)
        {
            w.Write(file.Flags);

            if ((file.Flags & 4) == 0)
            {
                w.Write(file.FileName);
            }
            else
            {
                w.Write(file.ResourceIndex.GetValueOrDefault());
            }

            w.Write(file.NodeIndex);

            if (Header.Version >= 5)
            {
                w.Write(file.UseFile.GetValueOrDefault());
            }

            if ((file.Flags & 4) == 0)
            {
                w.Write(file.FolderIndex.GetValueOrDefault());
            }
        }
    }
Ejemplo n.º 21
0
            public override void Write(CGameCtnMediaBlockCameraPath n, GameBoxWriter w, GameBoxReader unknownR)
            {
                w.Write(Version);

                w.Write(n.Keys, x =>
                {
                    w.Write(x.Time);
                    w.Write(x.Position);
                    w.Write(x.PitchYawRoll);
                    w.Write(x.FOV);
                    if (Version >= 3)
                    {
                        w.Write(x.NearZ.GetValueOrDefault());
                    }
                    w.Write(x.AnchorRot);
                    w.Write(x.Anchor);
                    w.Write(x.AnchorVis);
                    w.Write(x.Target);
                    w.Write(x.TargetPosition);

                    w.Write((float)x.Unknown[0]);
                    w.Write((float)x.Unknown[1]);
                    w.Write((float)x.Unknown[2]);
                    w.Write((float)x.Unknown[3]);
                    w.Write((float)x.Unknown[4]);

                    if (Version >= 4)
                    {
                        w.Write((int)x.Unknown[5]);
                        w.Write((int)x.Unknown[6]);
                    }
                });
            }
Ejemplo n.º 22
0
    public void Write(GameBoxWriter w)
    {
        w.Write(0x11002000);
        w.Write(Version);

        var listOfTypes  = new List <ScriptVariable>();
        var typeIndicies = new int[Metadata.Count];

        for (var i = 0; i < Metadata.Count; i++)
        {
            var type = Metadata[i].Clone();
            type.Name = null !;
            type.Clear();

            bool exists = false;
            for (var j = 0; j < listOfTypes.Count; j++)
            {
                exists = type.TypeEquals(listOfTypes[j]);
                if (exists)
                {
                    typeIndicies[i] = j;
                    break;
                }
            }
            if (!exists)
            {
                listOfTypes.Add(type);
                if (i == 0)
                {
                    typeIndicies[i] = 0;
                }
                else
                {
                    typeIndicies[i] = typeIndicies.Max() + 1;
                }
            }
        }

        w.Write((byte)listOfTypes.Count);

        foreach (var t in listOfTypes)
        {
            w.Write((byte)t.Type);
            if (t.Type == ScriptType.Array)
            {
                WriteScriptArray((ScriptArray)t);
            }
            else if (t.Type == ScriptType.Struct)
            {
                WriteScriptStruct((ScriptStruct)t);
            }
        }

        w.Write((byte)Metadata.Count);

        for (var i = 0; i < Metadata.Count; i++)
        {
            var m = Metadata[i];
            w.Write(m.Name, StringLengthPrefix.Byte);
            w.Write((byte)typeIndicies[i]);
            WriteType(m);
        }

        void WriteScriptArray(ScriptArray variable)
        {
            var reference = variable.Reference;

            w.Write((byte)reference.Key.Type);

            if (reference.Key.Type == ScriptType.Struct)
            {
                WriteScriptStruct((ScriptStruct)reference.Key);
            }

            w.Write((byte)reference.Value.Type);

            if (reference.Value.Type == ScriptType.Array)
            {
                WriteScriptArray((ScriptArray)reference.Value);
            }
            else if (reference.Value.Type == ScriptType.Struct)
            {
                WriteScriptStruct((ScriptStruct)reference.Value);
            }

            for (var i = 0; i < variable.Unknown; i++)
            {
                w.Write((byte)0);
            }
        }

        void WriteScriptStruct(ScriptStruct variable)
        {
            w.Write((byte)variable.Members.Length);
            w.Write(variable.StructName);

            foreach (var member in variable.Members)
            {
                w.Write(member.Name);
                w.Write((byte)member.Type);

                switch (member.Type)
                {
                case ScriptType.Array:
                    WriteScriptArray((ScriptArray)member);
                    break;

                case ScriptType.Struct:
                    WriteScriptStruct((ScriptStruct)member);
                    break;
                }

                switch (member.Type)
                {
                case ScriptType.Integer:
                    w.Write(0);
                    break;

                case ScriptType.Real:
                    w.Write(0f);
                    break;

                case ScriptType.Vec2:
                    w.Write(new Vec2());
                    break;

                case ScriptType.Vec3:
                    w.Write(new Vec3());
                    break;

                case ScriptType.Int3:
                    w.Write(new Int3());
                    break;

                case ScriptType.Int2:
                    w.Write(new Int2());
                    break;

                case ScriptType.Array:
                    break;

                case ScriptType.Struct:
                    break;

                default:
                    w.Write((byte)0);
                    break;
                }
            }

            for (var i = 0; i < variable.Unknown; i++)
            {
                w.Write((byte)0);
            }
        }

        void WriteType(ScriptVariable type)
        {
            switch (type.Type)
            {
            case ScriptType.Boolean:
                w.Write((bool)type.Value, true);
                break;

            case ScriptType.Integer:
                w.Write((int)type.Value);
                break;

            case ScriptType.Real:
                w.Write((float)type.Value);
                break;

            case ScriptType.Text:
                w.Write((string)type.Value, StringLengthPrefix.Byte);
                break;

            case ScriptType.Vec2:
                w.Write((Vec2)type.Value);
                break;

            case ScriptType.Vec3:
                w.Write((Vec3)type.Value);
                break;

            case ScriptType.Int3:
                w.Write((Int3)type.Value);
                break;

            case ScriptType.Int2:
                w.Write((Int2)type.Value);
                break;

            case ScriptType.Array:
                var array = (ScriptArray)type;

                w.Write((byte)array.Elements.Count);

                if (array.Elements.Count > 0)
                {
                    if (array.Reference.Key.Type != ScriptType.Void)
                    {
                        WriteType(array.Reference.Key);
                    }

                    foreach (var e in array.Elements)
                    {
                        WriteType(e.Value);
                    }
                }
                break;

            case ScriptType.Struct:
                var strc = (ScriptStruct)type;
                foreach (var m in strc.Members)
                {
                    WriteType(m);
                }
                break;

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

        w.Write(0xFACADE01);
    }