refactor: adapt iw4 and iw5 content writer and zone writer factory for both pc variants

This commit is contained in:
Jan Laupetin committed 2026-10-22 20:01:07 +02:00
1 parent 53c279ff4c
commit 8b16e81355
12 files changed
+142 -37

No files matched your search

+47 -13
View File
@@ -1,6 +1,7 @@
#include "ContentWriterIW4.h"
#include "Game/IW4/AssetWriter_iw4_pc32.h"
#include "Game/IW4/AssetWriter_iw4_pc64.h"
#include "Writing/WritingException.h"
#include <cassert>
@@ -67,8 +68,13 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart)
#ifdef ARCH_x86
static_assert(offsetof(ScriptStringList, strings) == 4u);
#endif
m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4));
#else
if (m_word_size == GameWordSize::ARCH_64)
m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(8));
else
m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4));
#endif
}
}
@@ -80,10 +86,19 @@ void ContentWriter::WriteXAsset(const bool atStreamStart)
#define WRITE_ASSET(type_index, typeName, headerEntry) \
case type_index: \
{ \
Writer_##typeName##_pc32 writer(varXAsset->header.headerEntry, m_zone, *m_stream); \
writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \
if (m_word_size == GameWordSize::ARCH_64) \
{ \
Writer_##typeName##_pc64 writer(varXAsset->header.headerEntry, m_zone, *m_stream); \
writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(8)); \
} \
else \
{ \
Writer_##typeName##_pc32 writer(varXAsset->header.headerEntry, m_zone, *m_stream); \
writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \
} \
break; \
}
#define SKIP_ASSET(type_index, typeName, headerEntry) \
case type_index: \
break;
@@ -156,11 +171,18 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun
#ifdef ARCH_x86
varXAssetWritten = m_stream->Write(varXAsset, count);
#else
const auto fill = m_stream->WriteWithFill(8u * count);
varXAssetWritten = fill.Offset();
if (m_word_size == GameWordSize::ARCH_64)
{
varXAssetWritten = m_stream->Write(varXAsset, count);
}
else
{
const auto fill = m_stream->WriteWithFill(8u * count);
varXAssetWritten = fill.Offset();
for (size_t index = 0; index < count; index++)
fill.Fill(varXAsset[index].type, 8u * index);
for (size_t index = 0; index < count; index++)
fill.Fill(varXAsset[index].type, 8u * index);
}
#endif
}
@@ -188,13 +210,20 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream)
static_assert(offsetof(XAssetList, assetCount) == 8u);
varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList));
#else
const auto fillAccessor = m_stream->WriteWithFill(16u);
varXAssetListWritten = fillAccessor.Offset();
if (m_word_size == GameWordSize::ARCH_64)
{
varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList));
}
else
{
const auto fillAccessor = m_stream->WriteWithFill(16u);
varXAssetListWritten = fillAccessor.Offset();
varScriptStringList = &varXAssetList->stringList;
fillAccessor.Fill(varScriptStringList->count, 0u);
varScriptStringList = &varXAssetList->stringList;
fillAccessor.Fill(varScriptStringList->count, 0u);
fillAccessor.Fill(varXAssetList->assetCount, 8u);
fillAccessor.Fill(varXAssetList->assetCount, 8u);
}
#endif
m_stream->PushBlock(XFILE_BLOCK_VIRTUAL);
@@ -214,8 +243,13 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream)
#ifdef ARCH_x86
static_assert(offsetof(XAssetList, assets) == 12u);
#endif
m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12));
#else
if (m_word_size == GameWordSize::ARCH_64)
m_stream->MarkFollowing(varXAssetListWritten.AtOffset(24));
else
m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12));
#endif
}
m_stream->PopBlock();
@@ -61,6 +61,7 @@ namespace
std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) const
{
auto writer = std::make_unique<ZoneWriter>();
const auto* variant = IGameVariant::GetVariantById(zone.m_variant_id);
// TODO Support signed fastfiles
bool isSecure = false;
@@ -69,7 +70,7 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>(std::make_unique<ContentWriter>(zone),
zone,
32u,
variant->GetWordSize() == GameWordSize::ARCH_64 ? 64u : 32u,
ZoneConstants::ZONE_POINTER_OFFSET_BIT_COUNT,
ZoneConstants::ZONE_POINTER_BLOCK_BIT_COUNT,
ZoneConstants::INSERT_BLOCK);
+46 -16
View File
@@ -1,6 +1,7 @@
#include "ContentWriterIW5.h"
#include "Game/IW5/AssetWriter_iw5_pc32.h"
#include "Game/IW5/AssetWriter_iw5_pc64.h"
#include "Writing/WritingException.h"
#include <cassert>
@@ -67,8 +68,13 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart)
#ifdef ARCH_x86
static_assert(offsetof(ScriptStringList, strings) == 4u);
#endif
m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4));
#else
if (m_word_size == GameWordSize::ARCH_64)
m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(8));
else
m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4));
#endif
}
}
@@ -80,13 +86,18 @@ void ContentWriter::WriteXAsset(const bool atStreamStart)
#define WRITE_ASSET(type_index, typeName, headerEntry) \
case type_index: \
{ \
Writer_##typeName##_pc32 writer(varXAsset->header.headerEntry, m_zone, *m_stream); \
writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \
if (m_word_size == GameWordSize::ARCH_64) \
{ \
Writer_##typeName##_pc64 writer(varXAsset->header.headerEntry, m_zone, *m_stream); \
writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(8)); \
} \
else \
{ \
Writer_##typeName##_pc32 writer(varXAsset->header.headerEntry, m_zone, *m_stream); \
writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \
} \
break; \
}
#define SKIP_ASSET(type_index, typeName, headerEntry) \
case type_index: \
break;
assert(varXAsset != nullptr);
@@ -159,11 +170,18 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun
#ifdef ARCH_x86
varXAssetWritten = m_stream->Write(varXAsset, count);
#else
const auto fill = m_stream->WriteWithFill(8u * count);
varXAssetWritten = fill.Offset();
if (m_word_size == GameWordSize::ARCH_64)
{
varXAssetWritten = m_stream->Write(varXAsset, count);
}
else
{
const auto fill = m_stream->WriteWithFill(8u * count);
varXAssetWritten = fill.Offset();
for (size_t index = 0; index < count; index++)
fill.Fill(varXAsset[index].type, 8u * index);
for (size_t index = 0; index < count; index++)
fill.Fill(varXAsset[index].type, 8u * index);
}
#endif
}
@@ -191,13 +209,20 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream)
static_assert(offsetof(XAssetList, assetCount) == 8u);
varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList));
#else
const auto fillAccessor = m_stream->WriteWithFill(16u);
varXAssetListWritten = fillAccessor.Offset();
if (m_word_size == GameWordSize::ARCH_64)
{
varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList));
}
else
{
const auto fillAccessor = m_stream->WriteWithFill(16u);
varXAssetListWritten = fillAccessor.Offset();
varScriptStringList = &varXAssetList->stringList;
fillAccessor.Fill(varScriptStringList->count, 0u);
varScriptStringList = &varXAssetList->stringList;
fillAccessor.Fill(varScriptStringList->count, 0u);
fillAccessor.Fill(varXAssetList->assetCount, 8u);
fillAccessor.Fill(varXAssetList->assetCount, 8u);
}
#endif
m_stream->PushBlock(XFILE_BLOCK_VIRTUAL);
@@ -217,8 +242,13 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream)
#ifdef ARCH_x86
static_assert(offsetof(XAssetList, assets) == 12u);
#endif
m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12));
#else
if (m_word_size == GameWordSize::ARCH_64)
m_stream->MarkFollowing(varXAssetListWritten.AtOffset(24));
else
m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12));
#endif
}
m_stream->PopBlock();
@@ -62,6 +62,7 @@ namespace
std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) const
{
auto writer = std::make_unique<ZoneWriter>();
const auto* variant = IGameVariant::GetVariantById(zone.m_variant_id);
// TODO Support signed fastfiles
bool isSecure = false;
@@ -70,7 +71,7 @@ std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(const Zone& zone) co
auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>(std::make_unique<ContentWriter>(zone),
zone,
32u,
variant->GetWordSize() == GameWordSize::ARCH_64 ? 64u : 32u,
ZoneConstants::ZONE_POINTER_OFFSET_BIT_COUNT,
ZoneConstants::ZONE_POINTER_BLOCK_BIT_COUNT,
ZoneConstants::INSERT_BLOCK);
@@ -4,6 +4,7 @@
ContentWriterBase::ContentWriterBase(const Zone& zone)
: m_zone(zone),
m_word_size(GameVariant::GetVariantById(zone.m_variant_id)->GetWordSize()),
m_stream(nullptr),
varXString(nullptr),
varXStringWritten(nullptr)
@@ -12,6 +13,7 @@ ContentWriterBase::ContentWriterBase(const Zone& zone)
ContentWriterBase::ContentWriterBase(const Zone& zone, ZoneOutputStream& stream)
: m_zone(zone),
m_word_size(GameVariant::GetVariantById(zone.m_variant_id)->GetWordSize()),
m_stream(&stream),
varXString(nullptr),
varXStringWritten(nullptr)
@@ -21,6 +21,7 @@ protected:
void WriteXStringArray(bool atStreamStart, size_t count);
const Zone& m_zone;
GameWordSize m_word_size;
ZoneOutputStream* m_stream;
const char** varXString;
@@ -1,4 +1,6 @@
>game,IW4
>variant,pc32
>name,SimpleZoneIW4
rawfile,SimpleZone.txt
@@ -0,0 +1,6 @@
>game,IW4
>variant,pc64
>name,SimpleZoneIW4
rawfile,SimpleZone.txt
+13 -3
View File
@@ -15,7 +15,7 @@ using namespace std::literals;
namespace
{
TEST_CASE("Simple Zone(IW4)", "[iw4][system][simple]")
void PerformTest(const std::string& zoneFileName, GameVariantId expectedGameVariantId)
{
const auto assetSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW4/Simple").string();
const auto sourceSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW4/Simple").string();
@@ -30,7 +30,7 @@ namespace
sourceSearchPath.c_str(),
"--output-folder",
outputPath.c_str(),
"SimpleZoneIW4",
zoneFileName.c_str(),
};
LinkerArgs args;
@@ -53,9 +53,19 @@ namespace
auto zone = std::move(*maybeZone);
REQUIRE(zone->m_game_id == GameId::IW4);
REQUIRE(zone->m_variant_id == GameVariantId::IW4_PC32);
REQUIRE(zone->m_variant_id == expectedGameVariantId);
REQUIRE(zone->m_name == "SimpleZoneIW4");
REQUIRE(zone->m_pools.GetTotalAssetCount() == 1);
REQUIRE(zone->m_pools.GetAsset<IW4::AssetRawFile>("SimpleZone.txt"));
}
TEST_CASE("Simple Zone(IW4|pc32)", "[iw4][pc32][system][simple]")
{
PerformTest("SimpleZoneIW4_32", GameVariantId::IW4_PC32);
}
TEST_CASE("Simple Zone(IW4|pc64)", "[iw4][pc64][system][simple]")
{
PerformTest("SimpleZoneIW4_64", GameVariantId::IW4_PC64);
}
} // namespace
@@ -1,4 +1,6 @@
>game,IW5
>variant,pc32
>name,SimpleZoneIW5
rawfile,SimpleZone.txt
@@ -0,0 +1,6 @@
>game,IW5
>variant,pc64
>name,SimpleZoneIW5
rawfile,SimpleZone.txt
+13 -3
View File
@@ -16,7 +16,7 @@ using namespace std::literals;
namespace
{
TEST_CASE("Simple Zone(IW5)", "[iw5][system][simple]")
void PerformTest(const std::string& zoneFileName, GameVariantId expectedGameVariantId)
{
const auto assetSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW5/Simple").string();
const auto sourceSearchPath = (oat::paths::GetSystemTestsDirectory() / "Game/IW5/Simple").string();
@@ -31,7 +31,7 @@ namespace
sourceSearchPath.c_str(),
"--output-folder",
outputPath.c_str(),
"SimpleZoneIW5",
zoneFileName.c_str(),
};
LinkerArgs args;
@@ -54,9 +54,19 @@ namespace
auto zone = std::move(*maybeZone);
REQUIRE(zone->m_game_id == GameId::IW5);
REQUIRE(zone->m_variant_id == GameVariantId::IW5_PC32);
REQUIRE(zone->m_variant_id == expectedGameVariantId);
REQUIRE(zone->m_name == "SimpleZoneIW5");
REQUIRE(zone->m_pools.GetTotalAssetCount() == 1);
REQUIRE(zone->m_pools.GetAsset<IW5::AssetRawFile>("SimpleZone.txt"));
}
TEST_CASE("Simple Zone(IW5|pc32)", "[iw5][pc32][system][simple]")
{
PerformTest("SimpleZoneIW5_32", GameVariantId::IW5_PC32);
}
TEST_CASE("Simple Zone(IW5|pc64)", "[iw5][pc64][system][simple]")
{
PerformTest("SimpleZoneIW5_64", GameVariantId::IW5_PC64);
}
} // namespace