Skip to content

Instantly share code, notes, and snippets.

@DefaultO
Last active June 26, 2022 16:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DefaultO/655c04daabf3782d1d485804f3761de4 to your computer and use it in GitHub Desktop.
Save DefaultO/655c04daabf3782d1d485804f3761de4 to your computer and use it in GitHub Desktop.
Improved World Data Serializing for the Game Growtopia
void Example()
{
List<TileInfo> tiles = new List<TileInfo>();
long start = Stopwatch.GetTimestamp();
byte[] worldData = m.ReadBytes("Growtopia.exe+0xFAB370,ab0,108,28,0", sizeof(TileInfo) * 100 * 60);
foreach (byte[] copySlice in worldData.Slices(sizeof(TileInfo)))
{
tiles.Add(Serializer.Deserialize<TileInfo>(copySlice));
}
// Console.WriteLine(tiles.Count());
long end = Stopwatch.GetTimestamp();
Console.WriteLine($"Parsing whole World Data took {end - start} ticks, or {(end - start) / 10000} ms");
start = Stopwatch.GetTimestamp();
byte[] tileInfo = m.ReadBytes($"Growtopia.exe+0xFAB370,ab0,108,28,{((sizeof(TileInfo) * 100 * 60) - 90).ToString("X")}", sizeof(TileInfo));
TileInfo tileInfoStruct = Serializer.Deserialize<TileInfo>(tileInfo);
end = Stopwatch.GetTimestamp();
Console.WriteLine($"Parsing X: 100 Y: 60 took {end - start} ticks, or {(end - start) / 10000} ms");
start = Stopwatch.GetTimestamp();
tileInfo = m.ReadBytes($"Growtopia.exe+0xFAB370,ab0,108,28,0", sizeof(TileInfo));
tileInfoStruct = Serializer.Deserialize<TileInfo>(tileInfo);
end = Stopwatch.GetTimestamp();
Console.WriteLine($"Parsing X: 1 Y: 1 took {end - start} ticks, or {(end - start) / 10000} ms");
}
// ...
public struct TileInfo
{
uint junk_1; // 0000
public short ForegroundID; // 0004
public short BackgroundID; // 0006
uint junk_2; // 0008
uint junk_3; // 000C
uint junk_4; // 0010
uint junk_5; // 0014
uint junk_6; // 0018
uint junk_7; // 001C
uint junk_8; // 0020 - Bottom Left Pixel Position X?
uint junk_9; // 0024 - Bottom Left Pixel Position Y?
public ushort TileExtra; // 0028
uint junk_10; // 0030
uint junk_11; // 0034
uint junk_12; // 0038
uint junk_13; // 003C
uint junk_14; // 0040
uint junk_15; // 0044
uint junk_16; // 0048
uint junk_17; // 004C
uint junk_18; // 0050
uint junk_19; // 0054
uint junk_20; // 0058
uint junk_21; // 005C
uint junk_22; // 0060
uint junk_23; // 0064
uint junk_24; // 0068
double junk_25; // 006C
uint junk_26; // 0074
uint junk_27; // 0078
uint junk_28; // 007C
uint junk_29; // 0080
uint junk_30; // 0084
uint junk_31; // 0088
uint junk_32; // 008C
}
// ...
public static class Serializer
{
public static unsafe byte[] Serialize<T>(T value) where T : unmanaged
{
byte[] buffer = new byte[sizeof(T)];
fixed (byte* bufferPtr = buffer)
{
Buffer.MemoryCopy(&value, bufferPtr, sizeof(T), sizeof(T));
}
return buffer;
}
public static unsafe T Deserialize<T>(byte[] buffer) where T : unmanaged
{
T result = new T();
fixed (byte* bufferPtr = buffer)
{
Buffer.MemoryCopy(bufferPtr, &result, sizeof(T), sizeof(T));
}
return result;
}
public static T[] CopySlice<T>(this T[] source, int index, int length, bool padToLength = false)
{
int n = length;
T[] slice = null;
if (source.Length < index + length)
{
n = source.Length - index;
if (padToLength)
{
slice = new T[length];
}
}
if (slice == null) slice = new T[n];
Array.Copy(source, index, slice, 0, n);
return slice;
}
public static IEnumerable<T[]> Slices<T>(this T[] source, int count, bool padToLength = false)
{
for (var i = 0; i < source.Length; i += count)
yield return source.CopySlice(i, count, padToLength);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment