Skip to content

Changes in GameMaker Studio 2

Liu Wenyuan edited this page Sep 13, 2020 · 1 revision

Not all of this is fully figured out and verified, please report any mistakes!

This document describes the changes to the data format of Studio 2 compared to Studio 1.4. I assume you are familiar with how the old version worked because the changes are not that huge - if you are not, please read some other resources first.

EMBI

This is a new chunk. Doesn't seem to be commonly used, see https://github.com/krzys-h/UndertaleModTool/issues/4#issuecomment-421844420 for guesses on the format

GLOB

This chunk exists in GMS1.4 too, but we never saw it used. See https://github.com/krzys-h/UndertaleModTool/issues/2 for discussion on this. The chunk appears to be a (length-prefixed) list of IDs of Code objects. From the names, they seem to be global initialization scripts.

GEN8

Half of the old "license data" is set to zeroes. Some new data at the end:

            if (Major >= 2)
            {
                byte GMS2License1[40]; // License data or encrypted something? Has quite high entropy
                float GMS2Unknown1MaybeFPS = 30.0f;
                uint GMS2Unknown2 = 1;
                byte GMS2License2[16]; // more high entropy data
            }

TXTR

There is one new value prepended before every entry. The value I observed is 1, but apparently there are others too. Everything else is exactly like it used to be.

BGND

The backgrounds now don't go here - they go into SPRT. This chunk is just tile sets now. The structure starts off the same but there is some tile set parameters added at the end of every entry (some additional example values listed in the comments)

            if (data.GEN8.Major >= 2)
            {
                uint UnknownAlways2 = 2; // 2/2
                uint TileWidth = 32; // 32/64
                uint TileHeight = 32; // 32/64
                uint OutputBorderX = 2; // 2/2
                uint OutputBorderY = 2; // 2/2
                uint TileColumns = 32; // 32/23
                uint ItemsPerTileCount = 1; // 1/32
                uint TileCount = 1024; // 1024/1024
                uint UnknownAlwaysZero = 0;
                long FrameLength = 66666; // time for each frame (in microseconds seemingly)
                uint TileIds[TileCount*ItemsPerTileCount];
            }

SPRT

There is some more data inserted after OriginY and before the list of textures starts. Meaning unknown.

// ... after OriginY
            if (data.GEN8.Major >= 2)
            {
                int GMS2Unknown1 = -1;
                uint GMS2Unknown2 = 1;
                uint GMS2Unknown3 = 0;
                float GMS2Unknown4 = 15.0f; // animation speed?
                uint GMS2Unknown5 = 0;
            }
// ... before Textures

ROOM

This is the biggest change. GMS2 introduced Layers, which are a replacement for the old Depth property. The Backgrounds and Tiles lists are now always empty. GameObjects has stuff, but it's not used directly, but rather referenced from Layers. Views work like they used to.

At the end of the old room entry (but before the lists) there is a pointer to the layer list. The format is specified below (note that I mostly didn't even try to decode the meaning yet, just the structure)

        public enum LayerType
        {
            Instances = 2,
            Tiles = 4,
            Background = 1,
            Assets = 3
        }
        public class Layer
        {
            UndertaleString LayerName; // "Instances" // "Tiles_1" // "Background"
            uint LayerId; // 0 // 1 // 2
            LayerType LayerType; // 2 // 4 // 1
            uint LayerDepth; // 0 // 100 // 200
            float XOffset; // 0 // 0 // 0
            float YOffset; // 0 // 0 // 0
            float HSpeed; // 0 // 0 // 0
            float VSpeed; // 0 // 0 // 0
            bool IsVisible; // 1 // 1 // 1
            // one of the type-dependent classes below follows
        }

        public class LayerInstancesData
        {
            uint InstanceCount;
            uint InstanceIds[InstanceCount]; // 100000, 100001, 100002, 100003 // Instance IDs for objects defined in UndertaleRoom.GameObjects list
        }

        public class LayerTilesData
        {
            ResourceId<BGND> Background; // tile set ID (i.e. ID into BGND)
            uint TilesX;
            uint TilesY;
            uint TileData[TilesX*TilesY]; // Values from the big array at the end of BGND object
        }

        public class LayerBackgroundData
        {
            bool Visible;
            bool Foreground;
            ResourceId<SPRT> Sprite; // ID into SPRT (!!!!!!!!!)
            bool TiledHorizontally;
            bool TiledVertically;
            bool Stretch;
            int Color; // (includes alpha channel)
            float FirstFrame;
            float AnimationSpeed;
            int AnimationSpeedType; // 0 = in FPS, 1 = "frames per game frame"
        }

        public class LayerAssetsData
        {
            Ptr<UndertalePointerList<Tile>> LegacyTiles;
            Ptr<UndertalePointerList<SpriteEntry>> Sprites;
            UndertalePointerList<Tile> LegacyTiles;
            UndertalePointerList<SpriteEntry> Sprites;
            
            // Tile matches standard UndertaleRoom.Tile, but the BackgroundDefinition ID goes to SPRT instead of BGND

            public class SpriteEntry
            {
                UndertaleString Name;
                ResourceId<SPRT> Sprite;
                int X;
                int Y;
                float ScaleX;
                float ScaleY;
                int Color;
                float AnimationSpeed;
                int AnimationSpeedType; // 0 = in FPS, 1 = "frames per game frame"
                float FrameIndex;
                float Rotation;
            }
        }

OBJT.Events

There are two new event types (for a total of 15 now). 13 is unknown, 14 is apparently named PreCreate and doesn't seem to have subtypes. It's used in literally every GMS2 sample.