From 9306210227a07bcc212bf38734342acc177ed899 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 9 Dec 2023 14:33:56 +0100 Subject: [PATCH 1/2] feature: Load GSC bin files from gsc-tool from raw --- .../AssetLoaders/AssetLoaderScriptFile.cpp | 76 +++++++++++++++++++ .../IW5/AssetLoaders/AssetLoaderScriptFile.h | 19 +++++ src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp | 3 +- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp create mode 100644 src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.h diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp new file mode 100644 index 000000000..d3b5d2807 --- /dev/null +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp @@ -0,0 +1,76 @@ +#include "AssetLoaderScriptFile.h" + +#include "Game/IW5/IW5.h" +#include "Pool/GlobalAssetPool.h" + +#include +#include +#include + +using namespace IW5; + +void* AssetLoaderScriptFile::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + auto* scriptFile = memory->Create(); + memset(scriptFile, 0, sizeof(ScriptFile)); + scriptFile->name = memory->Dup(assetName.c_str()); + return scriptFile; +} + +bool AssetLoaderScriptFile::CanLoadFromRaw() const +{ + return true; +} + +// See https://github.com/xensik/gsc-tool#file-format for an in-depth explanation about the .gscbin format +bool AssetLoaderScriptFile::LoadFromRaw( + const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto file = searchPath->Open(assetName + ".gscbin"); + if (!file.IsOpen()) + return false; + + const auto fileBuffer = std::make_unique(static_cast(file.m_length)); + file.m_stream->read(fileBuffer.get(), file.m_length); + if (file.m_stream->gcount() != file.m_length) + return false; + + auto* scriptFile = memory->Create(); + scriptFile->name = memory->Dup(assetName.c_str()); + + // Retrieve data from the buffer + size_t offset = 0; + + // Read past the name pointer, we will use the one from assetName + offset += strlen(fileBuffer.get()) + 1; + + memcpy(&scriptFile->compressedLen, fileBuffer.get() + offset, sizeof(scriptFile->compressedLen)); + offset += sizeof(scriptFile->compressedLen); + + memcpy(&scriptFile->len, fileBuffer.get() + offset, sizeof(scriptFile->len)); + offset += sizeof(scriptFile->len); + + memcpy(&scriptFile->bytecodeLen, fileBuffer.get() + offset, sizeof(scriptFile->bytecodeLen)); + offset += sizeof(scriptFile->bytecodeLen); + + // Get the file size + auto fileSize = file.m_length; + + if (offset + scriptFile->compressedLen > fileSize || offset + scriptFile->bytecodeLen > fileSize) + { + std::cerr << "Error: Specified length in " << assetName << " GSC BIN structure exceeds the actual file size" << std::endl; + return false; + } + + scriptFile->buffer = static_cast(memory->Alloc(scriptFile->compressedLen)); + memcpy(const_cast(scriptFile->buffer), fileBuffer.get() + offset, scriptFile->compressedLen); + offset += scriptFile->compressedLen; + + scriptFile->bytecode = static_cast(memory->Alloc(scriptFile->bytecodeLen)); + memcpy(scriptFile->bytecode, fileBuffer.get() + offset, scriptFile->bytecodeLen); + offset += scriptFile->bytecodeLen; + + manager->AddAsset(ASSET_TYPE_SCRIPTFILE, assetName, scriptFile); + + return true; +} diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.h b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.h new file mode 100644 index 000000000..d621dcb8a --- /dev/null +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.h @@ -0,0 +1,19 @@ +#pragma once +#include "AssetLoading/BasicAssetLoader.h" +#include "AssetLoading/IAssetLoadingManager.h" +#include "Game/IW5/IW5.h" +#include "SearchPath/ISearchPath.h" + +namespace IW5 +{ + class AssetLoaderScriptFile final : public BasicAssetLoader + { + static constexpr size_t COMPRESSED_BUFFER_SIZE_PADDING = 64; + + public: + _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromRaw() const override; + bool + LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; + }; +} // namespace IW5 diff --git a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp index 6073c8328..c81ebeab1 100644 --- a/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp +++ b/src/ObjLoading/Game/IW5/ObjLoaderIW5.cpp @@ -5,6 +5,7 @@ #include "AssetLoaders/AssetLoaderMenuDef.h" #include "AssetLoaders/AssetLoaderMenuList.h" #include "AssetLoaders/AssetLoaderRawFile.h" +#include "AssetLoaders/AssetLoaderScriptFile.h" #include "AssetLoaders/AssetLoaderStringTable.h" #include "AssetLoading/AssetLoadingManager.h" #include "Game/IW5/GameAssetPoolIW5.h" @@ -60,7 +61,7 @@ ObjLoader::ObjLoader() REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_IMPACT_FX, FxImpactTable)) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SURFACE_FX, SurfaceFxTable)) REGISTER_ASSET_LOADER(AssetLoaderRawFile) - REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SCRIPTFILE, ScriptFile)) + REGISTER_ASSET_LOADER(AssetLoaderScriptFile) REGISTER_ASSET_LOADER(AssetLoaderStringTable) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_LEADERBOARD, LeaderboardDef)) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_STRUCTURED_DATA_DEF, StructuredDataDefSet)) From 0ad19648644e09614dbfb1ab37a49b294a65ca7c Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 9 Dec 2023 22:49:32 +0100 Subject: [PATCH 2/2] fix: address review comments --- .../Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp | 10 ++++++---- .../Game/IW5/AssetLoaders/AssetLoaderScriptFile.h | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp index d3b5d2807..2cbf1d177 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.cpp @@ -53,10 +53,13 @@ bool AssetLoaderScriptFile::LoadFromRaw( memcpy(&scriptFile->bytecodeLen, fileBuffer.get() + offset, sizeof(scriptFile->bytecodeLen)); offset += sizeof(scriptFile->bytecodeLen); - // Get the file size - auto fileSize = file.m_length; + if (scriptFile->compressedLen <= 0 || scriptFile->bytecodeLen <= 0) + { + std::cerr << "Error: Invalid length of the buffers in " << assetName << " specified" << std::endl; + return false; + } - if (offset + scriptFile->compressedLen > fileSize || offset + scriptFile->bytecodeLen > fileSize) + if (offset + (scriptFile->compressedLen + scriptFile->bytecodeLen) > file.m_length) { std::cerr << "Error: Specified length in " << assetName << " GSC BIN structure exceeds the actual file size" << std::endl; return false; @@ -68,7 +71,6 @@ bool AssetLoaderScriptFile::LoadFromRaw( scriptFile->bytecode = static_cast(memory->Alloc(scriptFile->bytecodeLen)); memcpy(scriptFile->bytecode, fileBuffer.get() + offset, scriptFile->bytecodeLen); - offset += scriptFile->bytecodeLen; manager->AddAsset(ASSET_TYPE_SCRIPTFILE, assetName, scriptFile); diff --git a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.h b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.h index d621dcb8a..3c1dc051f 100644 --- a/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.h +++ b/src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderScriptFile.h @@ -8,8 +8,6 @@ namespace IW5 { class AssetLoaderScriptFile final : public BasicAssetLoader { - static constexpr size_t COMPRESSED_BUFFER_SIZE_PADDING = 64; - public: _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; _NODISCARD bool CanLoadFromRaw() const override;