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

lcesave.hexpat: use Virtual Filesystem + ZLib support + auto endian detection #309

Merged
merged 4 commits into from
Nov 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 36 additions & 9 deletions patterns/lcesave.hexpat
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
#pragma author DexrnZacAttack
#pragma description Decompressed Minecraft LCE Save File
#pragma description Minecraft LCE Save File

#pragma endian big
/* ^ switch this to little for Switch, PS4, or Xbox One */


// NOTE: This pattern was only tested on Nightly@974c4ba, things may break/not work on older versions.
// ALSO NOTE: SPEGHETTI CODE!

// TODO: re-add nbt pattern
// TODO: clean up getFileType
// NOTE: SPEGHETTI CODE!

import std.string;
import std.mem;
import std.core;
import hex.dec;
#ifdef __IMHEX__
Copy link
Contributor

Choose a reason for hiding this comment

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

Where does the __IMHEX__ define come from?

Copy link
Contributor

@paxcut paxcut Nov 2, 2024

Choose a reason for hiding this comment

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

It is defined internally before pattern is evaluated. All patterns have it. In the source code you will find it in content_registry.cpp line 612

 runtime.addDefine("__IMHEX__");
 runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion());

Patterns shouldn't test for it, that's done internally in includes\hex\impl\imhex_check.pat

Copy link
Contributor

Choose a reason for hiding this comment

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

DexrnZacAttack, why are you testing for this define?

Copy link
Contributor

Choose a reason for hiding this comment

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

It isn't my place to reply since you asked the author directly, but note that the commit that adds the test for the define has "ifdefs to fix actions moment " as comment, so I suspect that it has to do with unit tests which wouldn't define the IMHEX variable because tests don't use the runtime. Also it would make little sense to warn user during a test run which is supposed to run automatically.

Copy link
Contributor

@C3pa C3pa Nov 2, 2024

Choose a reason for hiding this comment

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

Thanks, Paxcut.

Copy link
Contributor Author

@DexrnZacAttack DexrnZacAttack Nov 11, 2024

Choose a reason for hiding this comment

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

Thanks, Paxcut.

Just saw this thread, yes this is the case, as the actions stuff was failing without that check.

import hex.core;
#endif
#pragma pattern_limit 1000000
#pragma array_limit 1000000

Expand Down Expand Up @@ -51,16 +50,44 @@ struct LCEIndex {
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
Expand Down
Loading