Files
OpenAssetTools/src/ZoneLoading/Game/T4/ZoneLoaderFactoryT4.cpp
T

96 lines
3.8 KiB
C++

#include "ZoneLoaderFactoryT4.h"
#include "ContentLoaderT4.h"
#include "Game/GameLanguage.h"
#include "Game/T4/GameT4.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 "Loading/Steps/StepSkipBytes.h"
#include "Utils/ClassUtils.h"
#include "Utils/Endianness.h"
#include <cstring>
using namespace T4;
namespace
{
void SetupBlock(ZoneMemory& zoneMemory)
{
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
zoneMemory.AddBlock(XBLOCK_DEF(T4::XFILE_BLOCK_TEMP, XBlockType::BLOCK_TYPE_TEMP));
zoneMemory.AddBlock(XBLOCK_DEF(T4::XFILE_BLOCK_RUNTIME, XBlockType::BLOCK_TYPE_RUNTIME));
zoneMemory.AddBlock(XBLOCK_DEF(T4::XFILE_BLOCK_LARGE_RUNTIME, XBlockType::BLOCK_TYPE_RUNTIME));
zoneMemory.AddBlock(XBLOCK_DEF(T4::XFILE_BLOCK_PHYSICAL_RUNTIME, XBlockType::BLOCK_TYPE_RUNTIME));
zoneMemory.AddBlock(XBLOCK_DEF(T4::XFILE_BLOCK_VIRTUAL, XBlockType::BLOCK_TYPE_NORMAL));
zoneMemory.AddBlock(XBLOCK_DEF(T4::XFILE_BLOCK_LARGE, XBlockType::BLOCK_TYPE_NORMAL));
zoneMemory.AddBlock(XBLOCK_DEF(T4::XFILE_BLOCK_PHYSICAL, XBlockType::BLOCK_TYPE_NORMAL));
#undef XBLOCK_DEF
}
} // namespace
std::optional<ZoneLoaderInspectionResult> ZoneLoaderFactory::InspectZoneHeader(ZoneDataPeeking& filePeek) const
{
const auto& header = filePeek.PeekStruct<ZoneHeader>();
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_variant_id = GameVariantId::T4_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(ZoneDataPeeking& filePeek,
const std::string& fileName,
std::optional<std::unique_ptr<ProgressCallback>> progressCallback) const
{
const auto inspectResult = InspectZoneHeader(filePeek);
if (!inspectResult)
return nullptr;
// Create new zone
auto zone = std::make_unique<Zone>(fileName, 0, inspectResult->m_variant_id);
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(zonePtr->Memory());
// Skip the initial header that we peeked at before
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(sizeof(ZoneHeader)));
zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE)));
zoneLoader->AddLoadingStep(step::CreateStepLoadZoneSizes());
zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks(zonePtr));
zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent(
[zonePtr](ZoneInputStream& stream)
{
return std::make_unique<ContentLoader>(*zonePtr, stream);
},
32u,
ZoneConstants::ZONE_POINTER_OFFSET_BIT_COUNT,
ZoneConstants::ZONE_POINTER_BLOCK_BIT_COUNT,
ZoneConstants::INSERT_BLOCK,
zonePtr,
std::move(progressCallback)));
return zoneLoader;
}