-
-
Notifications
You must be signed in to change notification settings - Fork 184
/
lcesave.hexpat
98 lines (85 loc) · 3.76 KB
/
lcesave.hexpat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#pragma author DexrnZacAttack
#pragma description Minecraft LCE Save File
// NOTE: SPEGHETTI CODE!
import std.string;
import std.mem;
import std.core;
import hex.dec;
#ifdef __IMHEX__
import hex.core;
#endif
#pragma pattern_limit 1000000
#pragma array_limit 1000000
fn getFileType(str filename) {
// EWWWWWWW HOW DO I FIX THIS
match (std::string::substr(filename, std::string::length(filename) - 4, 4)) {
(".mcr"):
if (std::string::starts_with(filename, "r."))
return "Overworld Region";
else if (std::string::starts_with(filename, "DIM-1"))
return "Nether Region";
else if (std::string::starts_with(filename, "DIM1"))
return "End Region";
else
return "Unknown Region";
(".dat"):
if (std::string::starts_with(filename, "players"))
return "Player";
else if (std::string::starts_with(filename, "data/")) {
if (std::string::starts_with(filename, "data/map_"))
return "Map File";
else
return "Other DAT File";
} else if (std::string::starts_with(filename, "level"))
return "Level File";
else
return "Unknown DAT";
(_): return "File";
}
};
struct LCEIndex {
char16 filename[0x40] [[name("File Name")]]; // name of the file.
u32 filesize [[name("File Size")]]; // how big the file is
u32 offset [[name("File Offset")]]; // where the file is located
if (parent.header.curVersion > 1)
u64 timestamp [[name("File Timestamp")]]; // useless as it writes weirdly, and differently on certain consoles. (e.g using time since last reset, etc)
u8 file[filesize] @ offset [[name(this.filename),comment(getFileType(std::string::to_string(filename))),attribute_name(this.filename)]]; // files in the index
#ifdef __IMHEX__
hex::core::add_virtual_file(std::string::to_string(filename), file);
#endif
} [[name("(" + getFileType(std::string::to_string(filename)) + ") " + std::string::to_string(this.filename))]];
struct LCEHeader {
u32 offset [[name("Index Offset")]]; // where the index is located
u32 count [[name("Index File Count")]]; // amount of files in the index
u16 minVersion [[name("Minimum LCE file version")]]; // Minimum LCE version supported by file
u16 curVersion [[name("Current LCE file version")]]; // Version that the file was written with
};
struct CompressedSave {
be u64 zlibSize;
u8 zlibData[std::mem::size() - 8];
std::mem::Section zlib = std::mem::create_section(std::format("Compressed Save"));
hex::dec::zlib_decompress(zlibData, zlib, 15);
u8 decompressed[zlibSize] @ 0x00 in zlib;
#ifdef __IMHEX__
hex::core::add_virtual_file("save", decompressed);
#endif
std::error("This save is ZLib-compressed, grab the decompressed save from the Virtual Filesystem tab and use this pattern on it.");
};
struct LCESave {
u8 zlibMagic[2] @ 0x08 [[hidden]];
// check if header matches
if (zlibMagic[0] == 0x78 && zlibMagic[1] == 0x9C)
CompressedSave compSave @ 0x00;
// if not we will have continued.
le u16 endianCheck @ 0x0A [[hidden]];
// check if version is bigger than 14
if (endianCheck > 14)
std::core::set_endian(std::mem::Endian::Big);
// rest of the processing
LCEHeader header [[name("Header")]];
if (header.curVersion > 1)
LCEIndex index[header.count] @ header.offset [[name("File Index")]]; // the index
else
LCEIndex index[header.count / 136] @ header.offset [[name("File Index")]]; // the index (pre-release)
} [[name("Save " + "(Version " + std::string::to_string(header.curVersion) + ")")]];
LCESave Save @ 0x00;