diff --git a/src/ZoneCommon/Game/IW3/ZoneConstantsIW3.h b/src/ZoneCommon/Game/IW3/ZoneConstantsIW3.h index e7efa17b..f6e5bdb8 100644 --- a/src/ZoneCommon/Game/IW3/ZoneConstantsIW3.h +++ b/src/ZoneCommon/Game/IW3/ZoneConstantsIW3.h @@ -13,7 +13,8 @@ namespace IW3 public: static constexpr const char* MAGIC_UNSIGNED = "IWffu100"; - static constexpr int ZONE_VERSION = 5; + static constexpr int ZONE_VERSION_PC = 5; + static constexpr int ZONE_VERSION_XENON = 1; static_assert(std::char_traits::length(MAGIC_UNSIGNED) == sizeof(ZoneHeader::m_magic)); diff --git a/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp b/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp index 0a81643c..7400ac11 100644 --- a/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp +++ b/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp @@ -9,15 +9,20 @@ #include "Loading/Processor/ProcessorInflate.h" #include "Loading/Steps/StepAddProcessor.h" #include "Loading/Steps/StepAllocXBlocks.h" +#include "Loading/Steps/StepDumpData.h" #include "Loading/Steps/StepLoadZoneContent.h" #include "Loading/Steps/StepLoadZoneSizes.h" #include "Utils/ClassUtils.h" +#include "Utils/Endianness.h" +#include "Utils/Logging/Log.h" #include #include +#include #include using namespace IW3; +namespace fs = std::filesystem; namespace { @@ -41,20 +46,35 @@ namespace std::optional ZoneLoaderFactory::InspectZoneHeader(const ZoneHeader& header) const { - if (header.m_version != ZoneConstants::ZONE_VERSION) - return std::nullopt; - - if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits::length(ZoneConstants::MAGIC_UNSIGNED))) + if (endianness::FromLittleEndian(header.m_version) == ZoneConstants::ZONE_VERSION_PC) { - return ZoneLoaderInspectionResult{ - .m_game_id = GameId::IW3, - .m_endianness = GameEndianness::LE, - .m_word_size = GameWordSize::ARCH_32, - .m_platform = GamePlatform::PC, - .m_is_official = true, - .m_is_signed = false, - .m_is_encrypted = false, - }; + if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits::length(ZoneConstants::MAGIC_UNSIGNED))) + { + return ZoneLoaderInspectionResult{ + .m_game_id = GameId::IW3, + .m_endianness = GameEndianness::LE, + .m_word_size = GameWordSize::ARCH_32, + .m_platform = GamePlatform::PC, + .m_is_official = true, + .m_is_signed = false, + .m_is_encrypted = false, + }; + } + } + else if (endianness::FromBigEndian(header.m_version) == ZoneConstants::ZONE_VERSION_XENON) + { + if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits::length(ZoneConstants::MAGIC_UNSIGNED))) + { + return ZoneLoaderInspectionResult{ + .m_game_id = GameId::IW3, + .m_endianness = GameEndianness::BE, + .m_word_size = GameWordSize::ARCH_32, + .m_platform = GamePlatform::XBOX, + .m_is_official = false, + .m_is_signed = false, + .m_is_encrypted = false, + }; + } } return std::nullopt; @@ -81,21 +101,32 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE))); - // Start of the XFile struct - zoneLoader->AddLoadingStep(step::CreateStepLoadZoneSizes()); - zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks()); + if (inspectResult->m_endianness == GameEndianness::LE) + { + // Start of the XFile struct + zoneLoader->AddLoadingStep(step::CreateStepLoadZoneSizes()); + zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks()); - // Start of the zone content - zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent( - [zonePtr](ZoneInputStream& stream) - { - return std::make_unique(*zonePtr, stream); - }, - 32u, - ZoneConstants::OFFSET_BLOCK_BIT_COUNT, - ZoneConstants::INSERT_BLOCK, - zonePtr->Memory(), - std::move(progressCallback))); + // Start of the zone content + zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent( + [zonePtr](ZoneInputStream& stream) + { + return std::make_unique(*zonePtr, stream); + }, + 32u, + ZoneConstants::OFFSET_BLOCK_BIT_COUNT, + ZoneConstants::INSERT_BLOCK, + zonePtr->Memory(), + std::move(progressCallback))); + } + else + { + fs::path dumpFileNamePath = fs::path(fileName).filename(); + dumpFileNamePath.replace_extension(".dat"); + std::string dumpFileName = dumpFileNamePath.string(); + con::warn("Dumping xbox assets is not supported, making a full fastfile data dump to {}", dumpFileName); + zoneLoader->AddLoadingStep(step::CreateStepDumpData(dumpFileName, 0xFFFFFFFF)); + } return zoneLoader; } diff --git a/src/ZoneWriting/Game/IW3/ZoneWriterFactoryIW3.cpp b/src/ZoneWriting/Game/IW3/ZoneWriterFactoryIW3.cpp index 2621980c..c9f47bb2 100644 --- a/src/ZoneWriting/Game/IW3/ZoneWriterFactoryIW3.cpp +++ b/src/ZoneWriting/Game/IW3/ZoneWriterFactoryIW3.cpp @@ -38,7 +38,7 @@ namespace ZoneHeader CreateHeaderForParams() { ZoneHeader header{}; - header.m_version = ZoneConstants::ZONE_VERSION; + header.m_version = ZoneConstants::ZONE_VERSION_PC; memcpy(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, sizeof(ZoneHeader::m_magic)); return header;