From 157e5403026c451187519b1feeb864672ce9480e Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 27 Apr 2021 19:31:26 +0200 Subject: [PATCH] more t5 stuffs --- src/Common/Game/T5/CommonT5.cpp | 55 ++++++ src/Common/Game/T5/CommonT5.h | 9 + .../AssetLoaders/AssetLoaderLocalizeEntry.cpp | 51 ++++++ .../AssetLoaders/AssetLoaderLocalizeEntry.h | 17 ++ .../T5/AssetLoaders/AssetLoaderRawFile.cpp | 43 +++++ .../Game/T5/AssetLoaders/AssetLoaderRawFile.h | 16 ++ .../AssetLoaders/AssetLoaderStringTable.cpp | 92 ++++++++++ .../T5/AssetLoaders/AssetLoaderStringTable.h | 16 ++ src/ObjLoading/Game/T5/ObjLoaderT5.cpp | 161 ++++++++++++++++++ src/ObjLoading/Game/T5/ObjLoaderT5.h | 36 ++++ src/ObjLoading/ObjLoading.cpp | 2 + .../T5/AssetDumpers/AssetDumperGfxImage.cpp | 48 ++++++ .../T5/AssetDumpers/AssetDumperGfxImage.h | 24 +++ .../AssetDumpers/AssetDumperLocalizeEntry.cpp | 53 ++++++ .../AssetDumpers/AssetDumperLocalizeEntry.h | 13 ++ .../AssetDumperPhysConstraints.cpp | 0 .../AssetDumpers/AssetDumperPhysConstraints.h | 0 .../T5/AssetDumpers/AssetDumperRawFile.cpp | 24 +++ .../Game/T5/AssetDumpers/AssetDumperRawFile.h | 17 ++ .../T5/AssetDumpers/AssetDumperSndBank.cpp | 0 .../Game/T5/AssetDumpers/AssetDumperSndBank.h | 0 .../AssetDumpers/AssetDumperStringTable.cpp | 37 ++++ .../T5/AssetDumpers/AssetDumperStringTable.h | 17 ++ src/ObjWriting/Game/T5/ZoneDumperT5.cpp | 69 ++++++++ src/ObjWriting/Game/T5/ZoneDumperT5.h | 12 ++ src/ZoneCode/Game/T5/T5.gen | 1 + src/ZoneCode/Game/T5/T5.h | 8 + src/ZoneCode/Game/T5/T5_Commands.txt | 80 +++++++++ 28 files changed, 901 insertions(+) create mode 100644 src/ObjWriting/Game/T5/AssetDumpers/AssetDumperPhysConstraints.cpp create mode 100644 src/ObjWriting/Game/T5/AssetDumpers/AssetDumperPhysConstraints.h create mode 100644 src/ObjWriting/Game/T5/AssetDumpers/AssetDumperSndBank.cpp create mode 100644 src/ObjWriting/Game/T5/AssetDumpers/AssetDumperSndBank.h diff --git a/src/Common/Game/T5/CommonT5.cpp b/src/Common/Game/T5/CommonT5.cpp index e69de29b..b65cf7c9 100644 --- a/src/Common/Game/T5/CommonT5.cpp +++ b/src/Common/Game/T5/CommonT5.cpp @@ -0,0 +1,55 @@ +#include "CommonT5.h" + +#include + +int CommonT5::Com_HashKey(const char* str, const int maxLen) +{ + if (str == nullptr) + return 0; + + int hash = 0; + for (int i = 0; i < maxLen; i++) + { + if (str[i] == '\0') + break; + + hash += str[i] * (0x77 + i); + } + + return hash ^ ((hash ^ (hash >> 10)) >> 10); +} + +int CommonT5::Com_HashString(const char* str) +{ + if (!str) + return 0; + + auto result = 0x1505; + auto offset = 0; + while (str[offset]) + { + const auto c = tolower(str[offset++]); + result = c + 33 * result; + } + + return result; +} + +int CommonT5::Com_HashString(const char* str, const int len) +{ + if (!str) + return 0; + + int result = 0x1505; + int offset = 0; + while (str[offset]) + { + if (len > 0 && offset >= len) + break; + + const int c = tolower(str[offset++]); + result = c + 33 * result; + } + + return result; +} \ No newline at end of file diff --git a/src/Common/Game/T5/CommonT5.h b/src/Common/Game/T5/CommonT5.h index e69de29b..baec165c 100644 --- a/src/Common/Game/T5/CommonT5.h +++ b/src/Common/Game/T5/CommonT5.h @@ -0,0 +1,9 @@ +#pragma once + +class CommonT5 +{ +public: + static int Com_HashKey(const char* str, int maxLen); + static int Com_HashString(const char* str); + static int Com_HashString(const char* str, int len); +}; \ No newline at end of file diff --git a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderLocalizeEntry.cpp b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderLocalizeEntry.cpp index e69de29b..1884c432 100644 --- a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderLocalizeEntry.cpp +++ b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderLocalizeEntry.cpp @@ -0,0 +1,51 @@ +#include "AssetLoaderLocalizeEntry.h" + +#include + +#include "Localize/LocalizeCommon.h" +#include "Parsing/LocalizeFile/LocalizeFileReader.h" + +using namespace T5; + +XAssetInfoGeneric* AssetLoaderLocalizeEntry::LoadFromGlobalAssetPools(const std::string& assetName) const +{ + return nullptr; +} + +void* AssetLoaderLocalizeEntry::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + return nullptr; +} + +bool AssetLoaderLocalizeEntry::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderLocalizeEntry::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + std::string fileName; + { + std::ostringstream str; + str << LocalizeCommon::GetNameOfLanguage(zone->m_language) << "/localizedstrings/" << assetName << ".str"; + fileName = str.str(); + } + + const auto file = searchPath->Open(fileName); + if (!file.IsOpen()) + return false; + + LocalizeFileReader reader(*file.m_stream, assetName, zone->m_language); + const auto localizeEntries = reader.ReadLocalizeFile(); + + for (const auto& entry : localizeEntries) + { + auto* localizeEntry = memory->Create(); + localizeEntry->name = memory->Dup(entry.m_key.c_str()); + localizeEntry->value = memory->Dup(entry.m_value.c_str()); + + manager->AddAsset(ASSET_TYPE_LOCALIZE_ENTRY, entry.m_key, localizeEntry); + } + + return true; +} diff --git a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderLocalizeEntry.h b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderLocalizeEntry.h index e69de29b..65a2854f 100644 --- a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderLocalizeEntry.h +++ b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderLocalizeEntry.h @@ -0,0 +1,17 @@ +#pragma once +#include "Game/T5/T5.h" +#include "AssetLoading/BasicAssetLoader.h" +#include "AssetLoading/IAssetLoadingManager.h" +#include "SearchPath/ISearchPath.h" + +namespace T5 +{ + class AssetLoaderLocalizeEntry final : public BasicAssetLoader + { + public: + _NODISCARD XAssetInfoGeneric* LoadFromGlobalAssetPools(const std::string& assetName) const override; + _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; + }; +} diff --git a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderRawFile.cpp b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderRawFile.cpp index e69de29b..23b4574d 100644 --- a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderRawFile.cpp +++ b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderRawFile.cpp @@ -0,0 +1,43 @@ +#include "AssetLoaderRawFile.h" + +#include + +#include "Game/T5/T5.h" +#include "Pool/GlobalAssetPool.h" + +using namespace T5; + +void* AssetLoaderRawFile::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + auto* rawFile = memory->Create(); + memset(rawFile, 0, sizeof(RawFile)); + rawFile->name = memory->Dup(assetName.c_str()); + return rawFile; +} + +bool AssetLoaderRawFile::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderRawFile::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto file = searchPath->Open(assetName); + if (!file.IsOpen()) + return false; + + auto* rawFile = memory->Create(); + rawFile->name = memory->Dup(assetName.c_str()); + rawFile->len = static_cast(file.m_length); + + auto* fileBuffer = static_cast(memory->Alloc(static_cast(file.m_length + 1))); + file.m_stream->read(fileBuffer, file.m_length); + if (file.m_stream->gcount() != file.m_length) + return false; + fileBuffer[rawFile->len] = '\0'; + + rawFile->buffer = fileBuffer; + manager->AddAsset(ASSET_TYPE_RAWFILE, assetName, rawFile); + + return true; +} diff --git a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderRawFile.h b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderRawFile.h index e69de29b..150ab4ac 100644 --- a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderRawFile.h +++ b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderRawFile.h @@ -0,0 +1,16 @@ +#pragma once +#include "Game/T5/T5.h" +#include "AssetLoading/BasicAssetLoader.h" +#include "AssetLoading/IAssetLoadingManager.h" +#include "SearchPath/ISearchPath.h" + +namespace T5 +{ + class AssetLoaderRawFile final : public BasicAssetLoader + { + 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; + }; +} diff --git a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.cpp b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.cpp index e69de29b..a5172535 100644 --- a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.cpp +++ b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.cpp @@ -0,0 +1,92 @@ +#include "AssetLoaderStringTable.h" + +#include + +#include "Csv/CsvStream.h" +#include "Game/T5/CommonT5.h" +#include "Game/T5/T5.h" +#include "Pool/GlobalAssetPool.h" + +using namespace T5; + +void* AssetLoaderStringTable::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + auto* stringTable = memory->Create(); + memset(stringTable, 0, sizeof(StringTable)); + stringTable->name = memory->Dup(assetName.c_str()); + return stringTable; +} + +bool AssetLoaderStringTable::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderStringTable::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto file = searchPath->Open(assetName); + if (!file.IsOpen()) + return false; + + auto* stringTable = memory->Create(); + stringTable->name = memory->Dup(assetName.c_str()); + + std::vector> csvLines; + std::vector currentLine; + auto maxCols = 0u; + const CsvInputStream csv(*file.m_stream); + + while (csv.NextRow(currentLine)) + { + if (currentLine.size() > maxCols) + maxCols = currentLine.size(); + csvLines.emplace_back(std::move(currentLine)); + } + + stringTable->columnCount = maxCols; + stringTable->rowCount = csvLines.size(); + const auto cellCount = static_cast(stringTable->rowCount) * static_cast(stringTable->columnCount); + + if (cellCount) + { + stringTable->values = static_cast(memory->Alloc(sizeof(StringTableCell) * cellCount)); + stringTable->cellIndex = static_cast(memory->Alloc(sizeof(int16_t) * cellCount)); + + for (auto c = 0u; c < cellCount; c++) + stringTable->cellIndex[c] = static_cast(c); + + for (auto row = 0u; row < csvLines.size(); row++) + { + const auto& rowValues = csvLines[row]; + for (auto col = 0u; col < maxCols; col++) + { + auto& cell = stringTable->values[row * maxCols + col]; + if (col >= rowValues.size() || rowValues[col].empty()) + cell.string = ""; + else + cell.string = memory->Dup(rowValues[col].c_str()); + + cell.hash = CommonT5::Com_HashString(cell.string); + } + } + + + std::sort(&stringTable->cellIndex[0], &stringTable->cellIndex[cellCount - 1], [stringTable, maxCols](const int16_t a, const int16_t b) + { + auto compareResult = stringTable->values[a].hash - stringTable->values[b].hash; + if (compareResult == 0) + compareResult = a % maxCols - b % maxCols; + return compareResult < 0; + }); + } + + else + { + stringTable->values = nullptr; + stringTable->cellIndex = nullptr; + } + + manager->AddAsset(ASSET_TYPE_STRINGTABLE, assetName, stringTable); + + return true; +} diff --git a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.h b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.h index e69de29b..e80a82be 100644 --- a/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.h +++ b/src/ObjLoading/Game/T5/AssetLoaders/AssetLoaderStringTable.h @@ -0,0 +1,16 @@ +#pragma once +#include "Game/T5/T5.h" +#include "AssetLoading/BasicAssetLoader.h" +#include "AssetLoading/IAssetLoadingManager.h" +#include "SearchPath/ISearchPath.h" + +namespace T5 +{ + class AssetLoaderStringTable final : public BasicAssetLoader + { + 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; + }; +} diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp index e69de29b..69e3b337 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp @@ -0,0 +1,161 @@ +#include "ObjLoaderT5.h" + +#include "Game/T5/GameT5.h" +#include "Game/T5/GameAssetPoolT5.h" +#include "ObjContainer/IPak/IPak.h" +#include "ObjLoading.h" +#include "AssetLoaders/AssetLoaderLocalizeEntry.h" +#include "AssetLoaders/AssetLoaderRawFile.h" +#include "AssetLoaders/AssetLoaderStringTable.h" +#include "AssetLoading/AssetLoadingManager.h" +#include "Image/Texture.h" +#include "Image/IwiLoader.h" + +using namespace T5; + +ObjLoader::ObjLoader() +{ +#define REGISTER_ASSET_LOADER(t) {auto l = std::make_unique(); m_asset_loaders_by_type[l->GetHandlingAssetType()] = std::move(l);} +#define BASIC_LOADER(assetType, assetClass) BasicAssetLoader + + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_PHYSPRESET, PhysPreset)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_PHYSCONSTRAINTS, PhysConstraints)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_DESTRUCTIBLEDEF, DestructibleDef)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_XANIMPARTS, XAnimParts)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_XMODEL, XModel)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MATERIAL, Material)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_TECHNIQUE_SET, MaterialTechniqueSet)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_IMAGE, GfxImage)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SOUND, snd_alias_list_t)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SOUND_PATCH, SndPatch)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_CLIPMAP, clipMap_t)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_CLIPMAP_PVS, clipMap_t)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_COMWORLD, ComWorld)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_GAMEWORLD_SP, GameWorldSp)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_GAMEWORLD_MP, GameWorldMp)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MAP_ENTS, MapEnts)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_GFXWORLD, GfxWorld)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_LIGHT_DEF, GfxLightDef)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_FONT, Font_s)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MENULIST, MenuList)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MENU, menuDef_t)) + REGISTER_ASSET_LOADER(AssetLoaderLocalizeEntry) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_WEAPON, WeaponDef)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_SNDDRIVER_GLOBALS, SndDriverGlobals)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_FX, FxEffectDef)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_IMPACT_FX, FxImpactTable)) + REGISTER_ASSET_LOADER(AssetLoaderRawFile) + REGISTER_ASSET_LOADER(AssetLoaderStringTable) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_PACK_INDEX, PackIndex)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_XGLOBALS, XGlobals)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_DDL, ddlRoot_t)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_GLASSES, Glasses)) + REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_EMBLEMSET, EmblemSet)) + +#undef BASIC_LOADER +#undef REGISTER_ASSET_LOADER +} + +bool ObjLoader::SupportsZone(Zone* zone) const +{ + return zone->m_game == &g_GameT5; +} + +bool ObjLoader::IsMpZone(Zone* zone) +{ + return zone->m_name.compare(0, 3, "mp_") == 0 + || zone->m_name.compare(zone->m_name.length() - 3, 3, "_mp") == 0; +} + +bool ObjLoader::IsZmZone(Zone* zone) +{ + return zone->m_name.compare(0, 3, "zm_") == 0 + || zone->m_name.compare(zone->m_name.length() - 3, 3, "_zm") == 0; +} + +void ObjLoader::LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const +{ +} + +void ObjLoader::UnloadContainersOfZone(Zone* zone) const +{ +} + +void ObjLoader::LoadImageFromLoadDef(GfxImage* image, Zone* zone) +{ + // TODO: Load Texture from LoadDef here +} + +void ObjLoader::LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone) +{ + Texture* loadedTexture = nullptr; + IwiLoader loader(zone->GetMemory()); + + const auto imageFileName = "images/" + std::string(image->name) + ".iwi"; + + { + const auto filePathImage = searchPath->Open(imageFileName); + if (filePathImage.IsOpen()) + { + loadedTexture = loader.LoadIwi(*filePathImage.m_stream); + } + } + + if (loadedTexture != nullptr) + { + image->texture.texture = loadedTexture; + image->cardMemory.platform[0] = 0; + + const auto textureMipCount = loadedTexture->GetMipMapCount(); + for (auto mipLevel = 0; mipLevel < textureMipCount; mipLevel++) + image->cardMemory.platform[0] += static_cast(loadedTexture->GetSizeOfMipLevel(mipLevel) * loadedTexture->GetFaceCount()); + } + else + { + printf("Could not find data for image \"%s\"\n", image->name); + } +} + +void ObjLoader::LoadImageData(ISearchPath* searchPath, Zone* zone) +{ + auto* assetPool = dynamic_cast(zone->m_pools.get()); + + if (assetPool && assetPool->m_image != nullptr) + { + for (auto* imageEntry : *assetPool->m_image) + { + auto* image = imageEntry->Asset(); + + if (image->cardMemory.platform[0] > 0) + { + continue; + } + + // Do not load linked assets + if (image->name && image->name[0] == ',') + { + continue; + } + + if (image->texture.loadDef && image->texture.loadDef->resourceSize > 0) + { + LoadImageFromLoadDef(image, zone); + } + else + { + LoadImageFromIwi(image, searchPath, zone); + } + } + } +} + +void ObjLoader::LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const +{ + LoadImageData(searchPath, zone); +} + +bool ObjLoader::LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const +{ + AssetLoadingManager assetLoadingManager(m_asset_loaders_by_type, *context); + return assetLoadingManager.LoadAssetFromLoader(assetType, assetName); +} diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.h b/src/ObjLoading/Game/T5/ObjLoaderT5.h index e69de29b..980d1e73 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.h +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include "IObjLoader.h" +#include "AssetLoading/IAssetLoader.h" +#include "SearchPath/ISearchPath.h" +#include "Game/T5/T5.h" + +namespace T5 +{ + class ObjLoader final : public IObjLoader + { + std::unordered_map> m_asset_loaders_by_type; + + static void LoadImageFromIwi(GfxImage* image, ISearchPath* searchPath, Zone* zone); + static void LoadImageFromLoadDef(GfxImage* image, Zone* zone); + static void LoadImageData(ISearchPath* searchPath, Zone* zone); + + static bool IsMpZone(Zone* zone); + static bool IsZmZone(Zone* zone); + + public: + ObjLoader(); + + bool SupportsZone(Zone* zone) const override; + + void LoadReferencedContainersForZone(ISearchPath* searchPath, Zone* zone) const override; + void UnloadContainersOfZone(Zone* zone) const override; + + void LoadObjDataForZone(ISearchPath* searchPath, Zone* zone) const override; + + bool LoadAssetForZone(AssetLoadingContext* context, asset_type_t assetType, const std::string& assetName) const override; + }; +} diff --git a/src/ObjLoading/ObjLoading.cpp b/src/ObjLoading/ObjLoading.cpp index 73c39baa..5a6a9dec 100644 --- a/src/ObjLoading/ObjLoading.cpp +++ b/src/ObjLoading/ObjLoading.cpp @@ -5,6 +5,7 @@ #include "IObjLoader.h" #include "Game/IW3/ObjLoaderIW3.h" #include "Game/IW4/ObjLoaderIW4.h" +#include "Game/T5/ObjLoaderT5.h" #include "Game/T6/ObjLoaderT6.h" #include "ObjContainer/IWD/IWD.h" #include "SearchPath/SearchPaths.h" @@ -16,6 +17,7 @@ const IObjLoader* const OBJ_LOADERS[] { new IW3::ObjLoader(), new IW4::ObjLoader(), + new T5::ObjLoader(), new T6::ObjLoader() }; diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.cpp b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.cpp index e69de29b..65a75f38 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.cpp +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.cpp @@ -0,0 +1,48 @@ +#include "AssetDumperGfxImage.h" + +#include + +#include "ObjWriting.h" +#include "Image/IwiWriter27.h" +#include "Image/DdsWriter.h" + +using namespace T5; + +AssetDumperGfxImage::AssetDumperGfxImage() +{ + switch (ObjWriting::Configuration.ImageOutputFormat) + { + case ObjWriting::Configuration_t::ImageOutputFormat_e::DDS: + m_writer = std::make_unique(); + break; + case ObjWriting::Configuration_t::ImageOutputFormat_e::IWI: + m_writer = std::make_unique(); + break; + default: + assert(false); + m_writer = nullptr; + break; + } +} + +bool AssetDumperGfxImage::ShouldDump(XAssetInfo* asset) +{ + const auto* image = asset->Asset(); + return image->loadedSize > 0; +} + +bool AssetDumperGfxImage::CanDumpAsRaw() +{ + return true; +} + +std::string AssetDumperGfxImage::GetFileNameForAsset(Zone* zone, XAssetInfo* asset) +{ + return "images/" + asset->m_name + m_writer->GetFileExtension(); +} + +void AssetDumperGfxImage::DumpRaw(AssetDumpingContext& context, XAssetInfo* asset, std::ostream& stream) +{ + const auto* image = asset->Asset(); + m_writer->DumpImage(stream, image->texture.texture); +} diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.h b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.h index e69de29b..e201838c 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.h +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperGfxImage.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T5/T5.h" +#include "Image/IImageWriter.h" + +namespace T5 +{ + class AssetDumperGfxImage final : public AbstractAssetDumper + { + std::unique_ptr m_writer; + + protected: + bool ShouldDump(XAssetInfo* asset) override; + bool CanDumpAsRaw() override; + std::string GetFileNameForAsset(Zone* zone, XAssetInfo* asset) override; + void DumpRaw(AssetDumpingContext& context, XAssetInfo* asset, std::ostream& stream) override; + + public: + AssetDumperGfxImage(); + }; +} diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperLocalizeEntry.cpp b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperLocalizeEntry.cpp index e69de29b..fb620b9c 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperLocalizeEntry.cpp +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperLocalizeEntry.cpp @@ -0,0 +1,53 @@ +#include "AssetDumperLocalizeEntry.h" + +#include +#include + +#include "Localize/LocalizeCommon.h" +#include "Dumping/Localize/StringFileDumper.h" + +using namespace T5; +namespace fs = std::filesystem; + +void AssetDumperLocalizeEntry::DumpPool(AssetDumpingContext& context, AssetPool* pool) +{ + if (pool->m_asset_lookup.empty()) + return; + + const auto language = LocalizeCommon::GetNameOfLanguage(context.m_zone->m_language); + fs::path stringsPath(context.m_base_path); + stringsPath.append(language); + stringsPath.append("localizedstrings"); + + create_directories(stringsPath); + + auto stringFilePath(stringsPath); + stringFilePath.append(context.m_zone->m_name + ".str"); + + std::ofstream stringFile(stringFilePath, std::fstream::out | std::ofstream::binary); + + if (stringFile.is_open()) + { + StringFileDumper stringFileDumper(context.m_zone, stringFile); + + stringFileDumper.SetLanguageName(language); + + // Magic string. Original string files do have this config file. The purpose of the config file is unknown though. + stringFileDumper.SetConfigFile(R"(C:\projects\cod\t5\bin\StringEd.cfg)"); + + stringFileDumper.SetNotes(""); + + for (auto* localizeEntry : *pool) + { + stringFileDumper.WriteLocalizeEntry(localizeEntry->m_name, localizeEntry->Asset()->value); + } + + stringFileDumper.Finalize(); + + stringFile.close(); + } + else + { + printf("Could not create string file for dumping localized strings of zone '%s'\n", context.m_zone->m_name.c_str()); + } +} \ No newline at end of file diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperLocalizeEntry.h b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperLocalizeEntry.h index e69de29b..03d4e99f 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperLocalizeEntry.h +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperLocalizeEntry.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T5/T5.h" + +namespace T5 +{ + class AssetDumperLocalizeEntry final : public IAssetDumper + { + public: + void DumpPool(AssetDumpingContext& context, AssetPool* pool) override; + }; +} diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperPhysConstraints.cpp b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperPhysConstraints.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperPhysConstraints.h b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperPhysConstraints.h new file mode 100644 index 00000000..e69de29b diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperRawFile.cpp b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperRawFile.cpp index e69de29b..a8c1ce27 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperRawFile.cpp +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperRawFile.cpp @@ -0,0 +1,24 @@ +#include "AssetDumperRawFile.h" + +using namespace T5; + +bool AssetDumperRawFile::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +bool AssetDumperRawFile::CanDumpAsRaw() +{ + return true; +} + +std::string AssetDumperRawFile::GetFileNameForAsset(Zone* zone, XAssetInfo* asset) +{ + return asset->m_name; +} + +void AssetDumperRawFile::DumpRaw(AssetDumpingContext& context, XAssetInfo* asset, std::ostream& stream) +{ + const auto* rawFile = asset->Asset(); + stream.write(rawFile->buffer, rawFile->len); +} \ No newline at end of file diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperRawFile.h b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperRawFile.h index e69de29b..91d9bacf 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperRawFile.h +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperRawFile.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T5/T5.h" + +namespace T5 +{ + class AssetDumperRawFile final : public AbstractAssetDumper + { + protected: + bool ShouldDump(XAssetInfo* asset) override; + bool CanDumpAsRaw() override; + + std::string GetFileNameForAsset(Zone* zone, XAssetInfo* asset) override; + void DumpRaw(AssetDumpingContext& context, XAssetInfo* asset, std::ostream& stream) override; + }; +} diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperSndBank.cpp b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperSndBank.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperSndBank.h b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperSndBank.h new file mode 100644 index 00000000..e69de29b diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperStringTable.cpp b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperStringTable.cpp index e69de29b..dad03712 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperStringTable.cpp +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperStringTable.cpp @@ -0,0 +1,37 @@ +#include "AssetDumperStringTable.h" + +#include "Csv/CsvStream.h" + +using namespace T5; + +bool AssetDumperStringTable::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +bool AssetDumperStringTable::CanDumpAsRaw() +{ + return true; +} + +std::string AssetDumperStringTable::GetFileNameForAsset(Zone* zone, XAssetInfo* asset) +{ + return asset->m_name; +} + +void AssetDumperStringTable::DumpRaw(AssetDumpingContext& context, XAssetInfo* asset, std::ostream& stream) +{ + const auto* stringTable = asset->Asset(); + CsvOutputStream csv(stream); + + for (auto row = 0; row < stringTable->rowCount; row++) + { + for (auto column = 0; column < stringTable->columnCount; column++) + { + const auto* cell = &stringTable->values[column + row * stringTable->columnCount]; + csv.WriteColumn(cell->string); + } + + csv.NextRow(); + } +} \ No newline at end of file diff --git a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperStringTable.h b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperStringTable.h index e69de29b..b6e9a43e 100644 --- a/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperStringTable.h +++ b/src/ObjWriting/Game/T5/AssetDumpers/AssetDumperStringTable.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T5/T5.h" + +namespace T5 +{ + class AssetDumperStringTable final : public AbstractAssetDumper + { + protected: + bool ShouldDump(XAssetInfo* asset) override; + bool CanDumpAsRaw() override; + + std::string GetFileNameForAsset(Zone* zone, XAssetInfo* asset) override; + void DumpRaw(AssetDumpingContext& context, XAssetInfo* asset, std::ostream& stream) override; + }; +} diff --git a/src/ObjWriting/Game/T5/ZoneDumperT5.cpp b/src/ObjWriting/Game/T5/ZoneDumperT5.cpp index e69de29b..cefa7564 100644 --- a/src/ObjWriting/Game/T5/ZoneDumperT5.cpp +++ b/src/ObjWriting/Game/T5/ZoneDumperT5.cpp @@ -0,0 +1,69 @@ +#include "ZoneDumperT5.h" + +#include "Game/T5/GameT5.h" +#include "Game/T5/GameAssetPoolT5.h" + +#include "AssetDumpers/AssetDumperRawFile.h" +#include "AssetDumpers/AssetDumperStringTable.h" +#include "AssetDumpers/AssetDumperLocalizeEntry.h" +#include "AssetDumpers/AssetDumperGfxImage.h" +#include "AssetDumpers/AssetDumperPhysConstraints.h" +#include "AssetDumpers/AssetDumperPhysPreset.h" +#include "AssetDumpers/AssetDumperSndBank.h" +#include "AssetDumpers/AssetDumperWeapon.h" + +using namespace T5; + +bool ZoneDumper::CanHandleZone(AssetDumpingContext& context) const +{ + return context.m_zone->m_game == &g_GameT5; +} + +bool ZoneDumper::DumpZone(AssetDumpingContext& context) const +{ +#define DUMP_ASSET_POOL(dumperType, poolName) \ + if(assetPools->poolName) \ + { \ + dumperType dumper; \ + dumper.DumpPool(context, assetPools->poolName); \ + } + + const auto* assetPools = dynamic_cast(context.m_zone->m_pools.get()); + + // DUMP_ASSET_POOL(AssetDumperPhysPreset, m_phys_preset); + // DUMP_ASSET_POOL(AssetDumperPhysConstraints, m_phys_constraints); + // DUMP_ASSET_POOL(AssetDumperDestructibleDef, m_destructible_def); + // DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts); + // DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel); + // DUMP_ASSET_POOL(AssetDumperMaterial, m_material); + // DUMP_ASSET_POOL(AssetDumperTechniqueSet, m_technique_set); + DUMP_ASSET_POOL(AssetDumperGfxImage, m_image); + // DUMP_ASSET_POOL(AssetDumperSndBank, m_sound_bank); + // DUMP_ASSET_POOL(AssetDumperSndPatch, m_sound_patch); + // DUMP_ASSET_POOL(AssetDumperClipMap, m_clip_map); + // DUMP_ASSET_POOL(AssetDumperComWorld, m_com_world); + // DUMP_ASSET_POOL(AssetDumperGameWorldSp, m_game_world_sp); + // DUMP_ASSET_POOL(AssetDumperGameWorldMp, m_game_world_mp); + // DUMP_ASSET_POOL(AssetDumperMapEnts, m_map_ents); + // DUMP_ASSET_POOL(AssetDumperGfxWorld, m_gfx_world); + // DUMP_ASSET_POOL(AssetDumperGfxLightDef, m_gfx_light_def); + // DUMP_ASSET_POOL(AssetDumperFont, m_font); + // DUMP_ASSET_POOL(AssetDumperMenuList, m_menu_list); + // DUMP_ASSET_POOL(AssetDumperMenuDef, m_menu_def); + DUMP_ASSET_POOL(AssetDumperLocalizeEntry, m_localize); + // DUMP_ASSET_POOL(AssetDumperWeapon, m_weapon); + // DUMP_ASSET_POOL(AssetDumperSndDriverGlobals, m_snd_driver_globals); + // DUMP_ASSET_POOL(AssetDumperFxEffectDef, m_fx); + // DUMP_ASSET_POOL(AssetDumperFxImpactTable, m_fx_impact_table); + DUMP_ASSET_POOL(AssetDumperRawFile, m_raw_file); + DUMP_ASSET_POOL(AssetDumperStringTable, m_string_table); + // DUMP_ASSET_POOL(AssetDumperPackIndex, m_pack_index); + // DUMP_ASSET_POOL(AssetDumperXGlobals, m_xglobals); + // DUMP_ASSET_POOL(AssetDumperDDLRoot, m_ddl); + // DUMP_ASSET_POOL(AssetDumperGlasses, m_glasses); + // DUMP_ASSET_POOL(AssetDumperEmblemSet, m_emblem_set); + + return true; + +#undef DUMP_ASSET_POOL +} diff --git a/src/ObjWriting/Game/T5/ZoneDumperT5.h b/src/ObjWriting/Game/T5/ZoneDumperT5.h index e69de29b..5d90906f 100644 --- a/src/ObjWriting/Game/T5/ZoneDumperT5.h +++ b/src/ObjWriting/Game/T5/ZoneDumperT5.h @@ -0,0 +1,12 @@ +#pragma once +#include "Dumping/IZoneDumper.h" + +namespace T5 +{ + class ZoneDumper final : public IZoneDumper + { + public: + bool CanHandleZone(AssetDumpingContext& context) const override; + bool DumpZone(AssetDumpingContext& context) const override; + }; +} diff --git a/src/ZoneCode/Game/T5/T5.gen b/src/ZoneCode/Game/T5/T5.gen index e69de29b..7bd8cb1e 100644 --- a/src/ZoneCode/Game/T5/T5.gen +++ b/src/ZoneCode/Game/T5/T5.gen @@ -0,0 +1 @@ +# This file exists for automatically generating zone loading code. \ No newline at end of file diff --git a/src/ZoneCode/Game/T5/T5.h b/src/ZoneCode/Game/T5/T5.h index e69de29b..dfcd4342 100644 --- a/src/ZoneCode/Game/T5/T5.h +++ b/src/ZoneCode/Game/T5/T5.h @@ -0,0 +1,8 @@ +#pragma once + +// Entry point for T5 code generation + +#include "../Common.h" +#include "../../../Common/Game/T5/T5_Assets.h" + +// EOF \ No newline at end of file diff --git a/src/ZoneCode/Game/T5/T5_Commands.txt b/src/ZoneCode/Game/T5/T5_Commands.txt index e69de29b..659a9f4d 100644 --- a/src/ZoneCode/Game/T5/T5_Commands.txt +++ b/src/ZoneCode/Game/T5/T5_Commands.txt @@ -0,0 +1,80 @@ +// Game: Black Ops (T5) +game T5; +architecture x86; + +// Game Assets +asset PhysPreset ASSET_TYPE_PHYSPRESET; +asset PhysConstraints ASSET_TYPE_PHYSCONSTRAINTS; +asset DestructibleDef ASSET_TYPE_DESTRUCTIBLEDEF; +asset XAnimParts ASSET_TYPE_XANIMPARTS; +asset XModel ASSET_TYPE_XMODEL; +asset Material ASSET_TYPE_MATERIAL; +asset MaterialTechniqueSet ASSET_TYPE_TECHNIQUE_SET; +asset GfxImage ASSET_TYPE_IMAGE; +asset SndBank ASSET_TYPE_SOUND; +asset SndPatch ASSET_TYPE_SOUND_PATCH; +asset clipMap_t ASSET_TYPE_CLIPMAP_PVS; +asset ComWorld ASSET_TYPE_COMWORLD; +asset GameWorldSp ASSET_TYPE_GAMEWORLD_SP; +asset GameWorldMp ASSET_TYPE_GAMEWORLD_MP; +asset MapEnts ASSET_TYPE_MAP_ENTS; +asset GfxWorld ASSET_TYPE_GFXWORLD; +asset GfxLightDef ASSET_TYPE_LIGHT_DEF; +asset Font_s ASSET_TYPE_FONT; +asset MenuList ASSET_TYPE_MENULIST; +asset menuDef_t ASSET_TYPE_MENU; +asset LocalizeEntry ASSET_TYPE_LOCALIZE_ENTRY; +asset WeaponVariantDef ASSET_TYPE_WEAPON; +asset SndDriverGlobals ASSET_TYPE_SNDDRIVER_GLOBALS; +asset FxEffectDef ASSET_TYPE_FX; +asset FxImpactTable ASSET_TYPE_IMPACT_FX; +asset RawFile ASSET_TYPE_RAWFILE; +asset StringTable ASSET_TYPE_STRINGTABLE; +asset XGlobals ASSET_TYPE_XGLOBALS; +asset ddlRoot_t ASSET_TYPE_DDL; +asset Glasses ASSET_TYPE_GLASSES; +asset EmblemSet ASSET_TYPE_EMBLEMSET; + +// Setup blocks +block temp XFILE_BLOCK_TEMP default; +block runtime XFILE_BLOCK_RUNTIME default; +block runtime XFILE_BLOCK_LARGE_RUNTIME; +block runtime XFILE_BLOCK_PHYSICAL_RUNTIME; +block normal XFILE_BLOCK_VIRTUAL default; +block normal XFILE_BLOCK_LARGE; +block normal XFILE_BLOCK_PHYSICAL; + +// Asset commands +#include "XAssets/PhysPreset.txt" +#include "XAssets/PhysConstraints.txt" +#include "XAssets/DestructibleDef.txt" +#include "XAssets/XAnimParts.txt" +#include "XAssets/XModel.txt" +#include "XAssets/Material.txt" +#include "XAssets/MaterialTechniqueSet.txt" +#include "XAssets/GfxImage.txt" +#include "XAssets/SndBank.txt" +#include "XAssets/SndPatch.txt" +#include "XAssets/clipMap_t.txt" +#include "XAssets/ComWorld.txt" +#include "XAssets/GameWorldSp.txt" +#include "XAssets/GameWorldMp.txt" +#include "XAssets/MapEnts.txt" +#include "XAssets/GfxWorld.txt" +#include "XAssets/GfxLightDef.txt" +#include "XAssets/Font_s.txt" +#include "XAssets/MenuList.txt" +#include "XAssets/menuDef_t.txt" +#include "XAssets/LocalizeEntry.txt" +#include "XAssets/WeaponVariantDef.txt" +#include "XAssets/SndDriverGlobals.txt" +#include "XAssets/FxEffectDef.txt" +#include "XAssets/FxImpactTable.txt" +#include "XAssets/RawFile.txt" +#include "XAssets/StringTable.txt" +#include "XAssets/XGlobals.txt" +#include "XAssets/ddlRoot_t.txt" +#include "XAssets/Glasses.txt" +#include "XAssets/EmblemSet.txt" + +// EOF \ No newline at end of file