Skip to content

Commit

Permalink
GMSTool:
Browse files Browse the repository at this point in the history
 * Added new option `--generate-uncompressed-gms`. It converts compressed GMS file to uncompressed and stores it by the passed path. You can replace your GMS file to generated and the game will work with it. It could help developers with reverse engineering of this format in the future.
  • Loading branch information
DronCode committed Jan 28, 2021
1 parent 844c0d4 commit c7539aa
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Tools/GMSInfo/include/GMS/GMS.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace ReGlacier

[[nodiscard]] const std::vector<std::string>& GetExcludedAnimations() const;
[[nodiscard]] const std::vector<GMSLinkRef>& GetLinkReferences() const;

[[nodiscard]] std::unique_ptr<uint8_t[]> GetUncompressedBuffer(unsigned int& uncompressedSize);
private:
bool LoadEntities(std::unique_ptr<char[]>&& buffer, size_t bufferSize);
bool LoadImportTable(const char* gmsBuffer, size_t bufferSize);
Expand Down
1 change: 1 addition & 0 deletions Tools/GMSInfo/include/LevelDescription.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace ReGlacier
void PrintInfo();
void ExportUncompressedGMS(const std::string& path);
bool ExportLocalizationToJson(std::string_view path);
bool GenerateGMSWithUncompressedBody(std::string_view path);

void SetIgnoreGMSFlag(bool flag);
void SetIgnoreANMFlag(bool flag);
Expand Down
5 changes: 5 additions & 0 deletions Tools/GMSInfo/source/GMS/GMS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,11 @@ namespace ReGlacier
return m_linkRefs;
}

std::unique_ptr<uint8_t[]> GMS::GetUncompressedBuffer(unsigned int& uncompressedSize)
{
return GetRawGMS(uncompressedSize);
}

bool GMS::LoadEntities(std::unique_ptr<char[]>&& gmsBuffer, size_t bufferSize)
{
std::unique_ptr<char[]> data = std::move(gmsBuffer);
Expand Down
36 changes: 36 additions & 0 deletions Tools/GMSInfo/source/LevelDescription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,42 @@ namespace ReGlacier
return m_context->LOCInstance->SaveAsJson(path);
}

bool LevelDescription::GenerateGMSWithUncompressedBody(std::string_view path)
{
#pragma pack(push, 1)
/**
* SGMS Header format
*
* +0x0 - uncompressed size
* +0x4 - buffer size (for zip)
* +0x8 - is compressed flag
*/
struct SGMSHeader_t
{
unsigned int iUncompressedSize { 0 };
unsigned int iBufferSize { 0 };
bool bIsUncompressed : 1 { false };
};
#pragma pack(pop)

SGMSHeader_t header { 0 };
auto buffer = m_context->GMSInstance->GetUncompressedBuffer(header.iUncompressedSize);
header.iBufferSize = header.iUncompressedSize;
header.bIsUncompressed = true;

FILE* fp = fopen(path.data(), "wb");
if (!fp) {
spdlog::error("LevelDescription::GenerateGMSUncompressedBody| Failed to open file {}", path);
return false;
}

fwrite(&header, sizeof(SGMSHeader_t), 1, fp);
fwrite(buffer.get(), sizeof(uint8_t), header.iUncompressedSize, fp);
fclose(fp);

return true;
}

void LevelDescription::SetIgnoreGMSFlag(bool flag) { m_context->Flags[IgnoreFlags::IgnoreGMS] = flag; }
void LevelDescription::SetIgnoreANMFlag(bool flag) { m_context->Flags[IgnoreFlags::IgnoreANM] = flag; }
void LevelDescription::SetIgnoreLOCFlag(bool flag) { m_context->Flags[IgnoreFlags::IgnoreLOC] = flag; }
Expand Down
13 changes: 13 additions & 0 deletions Tools/GMSInfo/source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ int main(int argc, char** argv)
std::string typesDataBaseFilePath = kDefaultTypeStorageFile;
std::string uncompressedGMSPath;
std::string exportLocalizationToFilePath;
std::string generateUncompressedGMSPath;

CLI::App app { "GMS Tool" };

Expand All @@ -45,6 +46,7 @@ int main(int argc, char** argv)
app.add_option("--ignore-prp", ignorePRP, "Ignore .PRP file");
app.add_option("--ignore-tex", ignoreTEX, "Ignore .TEX file");
app.add_option("--ignore-snd", ignoreSND, "Ignore .SND file");
app.add_option("--generate-uncompressed-gms", generateUncompressedGMSPath, "Generate GMS with uncompressed body");
CLI11_PARSE(app, argc, argv);

if (!ReGlacier::TypesDataBase::GetInstance().Load(typesDataBaseFilePath))
Expand Down Expand Up @@ -79,7 +81,9 @@ int main(int argc, char** argv)
level->PrintInfo();

if (!uncompressedGMSPath.empty())
{
level->ExportUncompressedGMS(uncompressedGMSPath);
}

if (!exportLocalizationToFilePath.empty())
{
Expand All @@ -98,5 +102,14 @@ int main(int argc, char** argv)
}
}

if (!generateUncompressedGMSPath.empty())
{
if (!level->GenerateGMSWithUncompressedBody(generateUncompressedGMSPath)) {
spdlog::error("Failed to generate uncompressed GMS. See logs for defails");
} else {
spdlog::info("Uncompressed GMS was saved into file {}", generateUncompressedGMSPath);
}
}

return 0;
}

0 comments on commit c7539aa

Please sign in to comment.