feat: initial T4 support (#807)

* feat: initial T4 support

* chore: adjust t4 symbols a bit for accuracy

* chore: add PackIndex asset to T4

* chore: remove unused AssetXModelPieces

* chore: add default and global asset pools loader for T4

* chore: use separate defines for T4 in ImageDumper

* chore: remove unnecessary namespaces in gfximage_actions

* chore: small things

* chore: fix T4 PhysPreset type

* chore: use proper XQuat2 type for T4 xanims

* chore: fix errors on T4 types

* chore: use iw3 like struct for XModelStreamInfo

* docs: add basic docs for T4

* chore: add basic ObjCompiler setup for T4

* chore: adjust loaded sound definition

* chore: make sure t4 material has the correct alignment

* chore: make sure t4 uses similar names for assets as other games

* fix: asset references should not be reusable

* chore: add content writer for t4

* feat: add t4 localize loader

* chore: reorder game ids to be alphabetically ordered

---------

Co-authored-by: Jan Laupetin <[email protected]>
This commit is contained in:
mo
2026-06-07 14:06:33 +02:00
committed by GitHub
co-authored by Jan Laupetin
parent 04628fc52c
commit 44d6710991
88 changed files with 6787 additions and 18 deletions
@@ -0,0 +1,44 @@
#include "LocalizeDumperT4.h"
#include "Dumping/Localize/StringFileDumper.h"
#include "Localize/LocalizeCommon.h"
#include "Utils/Logging/Log.h"
#include <format>
using namespace T4;
namespace localize
{
void DumperT4::Dump(AssetDumpingContext& context)
{
auto localizeAssets = context.m_zone.m_pools.PoolAssets<AssetLocalize>();
if (localizeAssets.empty())
return;
const auto language = LocalizeCommon::GetNameOfLanguage(context.m_zone.m_language);
const auto assetFile = context.OpenAssetFile(std::format("{}/localizedstrings/{}.str", language, context.m_zone.m_name));
if (assetFile)
{
StringFileDumper stringFileDumper(context.m_zone, *assetFile);
stringFileDumper.SetLanguageName(language);
stringFileDumper.SetConfigFile(R"(G:\CoD5\cod\cod5\bin\StringEd.cfg)");
stringFileDumper.SetNotes("");
for (const auto* localizeEntry : localizeAssets)
{
stringFileDumper.WriteLocalizeEntry(localizeEntry->m_name, localizeEntry->Asset()->value);
}
stringFileDumper.Finalize();
}
else
{
con::error("Could not create string file for dumping localized strings of zone '{}'", context.m_zone.m_name);
}
context.IncrementProgress();
}
} // namespace localize
@@ -0,0 +1,13 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/T4/T4.h"
namespace localize
{
class DumperT4 final : public AbstractSingleProgressAssetDumper<T4::AssetLocalize>
{
public:
void Dump(AssetDumpingContext& context) override;
};
} // namespace localize
+16
View File
@@ -0,0 +1,16 @@
#include "ObjWriterT4.h"
#include "Game/T4/Image/ImageDumperT4.h"
#include "Localize/LocalizeDumperT4.h"
#include "RawFile/RawFileDumperT4.h"
#include "StringTable/StringTableDumperT4.h"
using namespace T4;
void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
{
RegisterAssetDumper(std::make_unique<image::DumperT4>());
RegisterAssetDumper(std::make_unique<localize::DumperT4>());
RegisterAssetDumper(std::make_unique<raw_file::DumperT4>());
RegisterAssetDumper(std::make_unique<string_table::DumperT4>());
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include "ObjWriter.h"
namespace T4
{
class ObjWriter final : public IObjWriter
{
protected:
void RegisterAssetDumpers(AssetDumpingContext& context) override;
};
} // namespace T4
@@ -0,0 +1,18 @@
#include "RawFileDumperT4.h"
using namespace T4;
namespace raw_file
{
void DumperT4::DumpAsset(AssetDumpingContext& context, const XAssetInfo<RawFile>& asset)
{
const auto* rawFile = asset.Asset();
const auto assetFile = context.OpenAssetFile(asset.m_name);
if (!assetFile)
return;
auto& stream = *assetFile;
stream.write(rawFile->buffer, rawFile->len);
}
} // namespace raw_file
@@ -0,0 +1,13 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/T4/T4.h"
namespace raw_file
{
class DumperT4 final : public AbstractAssetDumper<T4::AssetRawFile>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<T4::RawFile>& asset) override;
};
} // namespace raw_file
@@ -0,0 +1,29 @@
#include "StringTableDumperT4.h"
#include "Csv/CsvStream.h"
using namespace T4;
namespace string_table
{
void DumperT4::DumpAsset(AssetDumpingContext& context, const XAssetInfo<StringTable>& asset)
{
const auto* stringTable = asset.Asset();
const auto assetFile = context.OpenAssetFile(asset.m_name);
if (!assetFile)
return;
CsvOutputStream csv(*assetFile);
for (auto row = 0; row < stringTable->rowCount; row++)
{
for (auto column = 0; column < stringTable->columnCount; column++)
{
csv.WriteColumn(stringTable->values[column + row * stringTable->columnCount]);
}
csv.NextRow();
}
}
} // namespace string_table
@@ -0,0 +1,13 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/T4/T4.h"
namespace string_table
{
class DumperT4 final : public AbstractAssetDumper<T4::AssetStringTable>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<T4::StringTable>& asset) override;
};
} // namespace string_table
@@ -1,4 +1,4 @@
#options GAME (IW3, IW4, IW5, T5, T6)
#options GAME (IW3, IW4, IW5, T4, T5, T6)
#filename "Game/" + GAME + "/Image/ImageDumper" + GAME + ".cpp"
@@ -8,6 +8,10 @@
#define FEATURE_IW3
#define DX9
#define IWI6
#elif GAME == "T4"
#define FEATURE_T4
#define DX9
#define IWI6
#elif GAME == "IW4"
#define FEATURE_IW4
#define DX9
@@ -80,7 +84,7 @@ namespace
#endif
const auto& loadDef = *image.texture.loadDef;
#ifdef FEATURE_IW3
#if defined(FEATURE_IW3) || defined(FEATURE_T4)
textureLoader.Width(loadDef.dimensions[0]).Height(loadDef.dimensions[1]).Depth(loadDef.dimensions[2]);
#else
textureLoader.Width(image.width).Height(image.height).Depth(image.depth);
+1 -1
View File
@@ -1,4 +1,4 @@
#options GAME(IW3, IW4, IW5, T5, T6)
#options GAME(IW3, IW4, IW5, T4, T5, T6)
#filename "Game/" + GAME + "/Image/ImageDumper" + GAME + ".h"
+3 -1
View File
@@ -3,6 +3,7 @@
#include "Game/IW3/ObjWriterIW3.h"
#include "Game/IW4/ObjWriterIW4.h"
#include "Game/IW5/ObjWriterIW5.h"
#include "Game/T4/ObjWriterT4.h"
#include "Game/T5/ObjWriterT5.h"
#include "Game/T6/ObjWriterT6.h"
#include "ObjWriting.h"
@@ -40,10 +41,11 @@ void IObjWriter::RegisterAssetDumper(std::unique_ptr<IAssetDumper> dumper)
IObjWriter* IObjWriter::GetObjWriterForGame(GameId game)
{
static IObjWriter* objWriters[static_cast<unsigned>(GameId::COUNT)]{
static IObjWriter* objWriters[]{
new IW3::ObjWriter(),
new IW4::ObjWriter(),
new IW5::ObjWriter(),
new T4::ObjWriter(),
new T5::ObjWriter(),
new T6::ObjWriter(),
};