Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for 2024.2 tile layer compression #1722

Merged
merged 9 commits into from
Apr 30, 2024

Conversation

CST1229
Copy link
Contributor

@CST1229 CST1229 commented Apr 3, 2024

Description

GM 2024.2 added compression to tile data in rooms, and this PR adds support for it by just decompressing it upon load and recompressing it on save (to preserve compatibility as much as possible). Also allows setting a 2024 GM version in SetGMS2Version.

The compression is a basic RLE similar to the one the IDE has used for a while, except with bytes:
Basically, the tile data is a sequence of what I call "runs", that each consist of 1 byte (which acts as a length/"opcode", I assume this is a signed byte but I'm gonna just treat it as unsigned) followed by some number of uint32 tile IDs.
If the opcode is between 0-127, then the next opcode tile IDs are just put directly into the tile data; a "verbatim run". There can be a 0-length verbatim run, though this normally never happens.
If it's between 128-255, then the next tile ID is repeated opcode - 127 times; a "repeat run" (yes, not minus 128, so there cannot be a 0-length repeat run).
If the length of a run needs to go above 127/128, they are just split (so e.g for 177 tiles in a row, there'd be a repeat run of length 128, then another repeat run of length 49).
GM encodes singular tiles as verbatim runs.

Caveats

The 2024.2 detection might throw a false negative if the size of the compressed tile data somehow happens to be TilesX * TilesY * 4 bytes long. I'm not sure if that can even happen due to compressed tile data not being 4-byte-aligned due to the opcodes.

Notes

Haven't tested this much.

Copy link

github-actions bot commented Apr 3, 2024

Copy link
Member

@BenjaminUrquhart BenjaminUrquhart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that I've had a moment to test this, it seems to fail if all rooms have their first layer as not a tile layer (see: TetherGeist). Gonna poke around and see if I can get something working.

@BenjaminUrquhart
Copy link
Member

BenjaminUrquhart commented Apr 25, 2024

I've fixed the detection locally, but now it fails to load the tileset (10th room of TetherGeist, layer 28)

 ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at UndertaleModLib.Models.UndertaleRoom.Layer.LayerTilesData.ReadCompressedTileData(UndertaleReader reader) in C:\Users\benja\source\repos\UndertaleModTool\UndertaleModLib\Models\UndertaleRoom.cs:line 1749
   at UndertaleModLib.Models.UndertaleRoom.Layer.LayerTilesData.Unserialize(UndertaleReader reader) in C:\Users\benja\source\repos\UndertaleModTool\UndertaleModLib\Models\UndertaleRoom.cs:line 1664
   at UndertaleModLib.UndertaleReader.ReadUndertaleObject[T](T obj) in C:\Users\benja\source\repos\UndertaleModTool\UndertaleModLib\UndertaleIO.cs:line 580

This corresponds to this line

                 byte length = reader.ReadByte();
                 if (length >= 128)
                 {
                     // Repeat run
                     int runLength = length - 128 + 1;
                     uint tile = reader.ReadUInt32();
                     for (int i = 0; i < runLength; i++)
                     {
                         TileData[y][x] = tile; // <----  right here
                         if (NextTile())
                             break;
                     }
                 }

There were 3 misalignment warnings beforehand so something went wrong before this

@BenjaminUrquhart
Copy link
Member

It appears if the last 2 tiles in the layer are different, 2 blank tiles are inserted to work around a GMAC bug, and that's why there are misalignments. There is still an index out of bounds in TetherGeist even when accounting for these.

There are still problems loading certain games (see: TetherGeist) but it gets rid of the load warnings
This works with my simple test project, the only actual 2024.2 game I have on hand has other issues so I can't test it more.
Copy link
Member

@BenjaminUrquhart BenjaminUrquhart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and made the changes myself, turns out my test game has other loading problems, but rooms themselves seem to be fine.

@BenjaminUrquhart BenjaminUrquhart requested a review from Miepee April 30, 2024 05:14
@BenjaminUrquhart BenjaminUrquhart merged commit 1d370a1 into UnderminersTeam:master Apr 30, 2024
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants