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:
moandJan Laupetin authored and GitHub committed 2026-06-07 14:06:33 +02:00
1 parent 04628fc52c
commit 44d6710991
88 files changed
+6787 -18

No files matched your search

@@ -0,0 +1,89 @@
#include "ZoneLoaderFactoryT4.h"
#include "ContentLoaderT4.h"
#include "Game/GameLanguage.h"
#include "Game/T4/T4.h"
#include "Game/T4/ZoneConstantsT4.h"
#include "Loading/Processor/ProcessorInflate.h"
#include "Loading/Steps/StepAddProcessor.h"
#include "Loading/Steps/StepAllocXBlocks.h"
#include "Loading/Steps/StepLoadZoneContent.h"
#include "Loading/Steps/StepLoadZoneSizes.h"
#include "Utils/ClassUtils.h"
#include "Utils/Endianness.h"
#include <cstring>
using namespace T4;
namespace
{
void SetupBlock(ZoneLoader& zoneLoader)
{
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
zoneLoader.AddXBlock(XBLOCK_DEF(T4::XFILE_BLOCK_TEMP, XBlockType::BLOCK_TYPE_TEMP));
zoneLoader.AddXBlock(XBLOCK_DEF(T4::XFILE_BLOCK_RUNTIME, XBlockType::BLOCK_TYPE_RUNTIME));
zoneLoader.AddXBlock(XBLOCK_DEF(T4::XFILE_BLOCK_LARGE_RUNTIME, XBlockType::BLOCK_TYPE_RUNTIME));
zoneLoader.AddXBlock(XBLOCK_DEF(T4::XFILE_BLOCK_PHYSICAL_RUNTIME, XBlockType::BLOCK_TYPE_RUNTIME));
zoneLoader.AddXBlock(XBLOCK_DEF(T4::XFILE_BLOCK_VIRTUAL, XBlockType::BLOCK_TYPE_NORMAL));
zoneLoader.AddXBlock(XBLOCK_DEF(T4::XFILE_BLOCK_LARGE, XBlockType::BLOCK_TYPE_NORMAL));
zoneLoader.AddXBlock(XBLOCK_DEF(T4::XFILE_BLOCK_PHYSICAL, XBlockType::BLOCK_TYPE_NORMAL));
#undef XBLOCK_DEF
}
} // namespace
std::optional<ZoneLoaderInspectionResult> ZoneLoaderFactory::InspectZoneHeader(const ZoneHeader& header) const
{
if (endianness::FromLittleEndian(header.m_version) == ZoneConstants::ZONE_VERSION_PC
&& !memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
{
return ZoneLoaderInspectionResult{
.m_game_id = GameId::T4,
.m_endianness = GameEndianness::LE,
.m_word_size = GameWordSize::ARCH_32,
.m_platform = GamePlatform::PC,
// There is no way to know whether unsigned zones are official.
.m_is_official = false,
.m_is_signed = false,
.m_is_encrypted = false,
};
}
return std::nullopt;
}
std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneHeader& header,
const std::string& fileName,
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const
{
const auto inspectResult = InspectZoneHeader(header);
if (!inspectResult)
return nullptr;
// Create new zone
auto zone = std::make_unique<Zone>(fileName, 0, GameId::T4, inspectResult->m_platform);
auto* zonePtr = zone.get();
zone->m_language = GameLanguage::LANGUAGE_NONE;
// File is supported. Now setup all required steps for loading this file.
auto zoneLoader = std::make_unique<ZoneLoader>(std::move(zone));
SetupBlock(*zoneLoader);
zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
zoneLoader->AddLoadingStep(step::CreateStepLoadZoneSizes());
zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks());
zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent(
[zonePtr](ZoneInputStream& stream)
{
return std::make_unique<ContentLoader>(*zonePtr, stream);
},
32u,
ZoneConstants::OFFSET_BLOCK_BIT_COUNT,
ZoneConstants::INSERT_BLOCK,
zonePtr->Memory(),
std::move(progressCallback)));
return zoneLoader;
}