mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-05-10 06:24:57 +00:00
Add IW3 zone writing
This commit is contained in:
parent
e6a10fb992
commit
687d1185a3
@ -1,5 +1,9 @@
|
||||
#include "ZoneCreatorIW3.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "ObjLoading.h"
|
||||
#include "AssetLoading/AssetLoadingContext.h"
|
||||
#include "Game/IW3/GameIW3.h"
|
||||
#include "Game/IW3/GameAssetPoolIW3.h"
|
||||
|
||||
@ -18,6 +22,33 @@ void ZoneCreator::AddAssetTypeName(asset_type_t assetType, std::string name)
|
||||
m_asset_types_by_name.emplace(std::make_pair(std::move(name), assetType));
|
||||
}
|
||||
|
||||
std::vector<Gdt*> ZoneCreator::CreateGdtList(ZoneCreationContext& context)
|
||||
{
|
||||
std::vector<Gdt*> gdtList;
|
||||
gdtList.reserve(context.m_gdt_files.size());
|
||||
for (const auto& gdt : context.m_gdt_files)
|
||||
gdtList.push_back(gdt.get());
|
||||
|
||||
return gdtList;
|
||||
}
|
||||
|
||||
bool ZoneCreator::CreateIgnoredAssetMap(ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const
|
||||
{
|
||||
for (const auto& ignoreEntry : context.m_ignored_assets)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(ignoreEntry.m_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << ignoreEntry.m_type << "\" for ignore \"" << ignoreEntry.m_name << "\"" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ignoredAssetMap[ignoreEntry.m_name] = foundAssetTypeEntry->second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZoneCreator::CreateZoneAssetPools(Zone* zone) const
|
||||
{
|
||||
zone->m_pools = std::make_unique<GameAssetPoolIW3>(zone, zone->m_priority);
|
||||
@ -34,10 +65,32 @@ bool ZoneCreator::SupportsGame(const std::string& gameName) const
|
||||
std::unique_ptr<Zone> ZoneCreator::CreateZoneForDefinition(ZoneCreationContext& context) const
|
||||
{
|
||||
auto zone = std::make_unique<Zone>(context.m_zone_name, 0, &g_GameIW3);
|
||||
zone->m_pools = std::make_unique<GameAssetPoolIW3>(zone.get(), zone->m_priority);
|
||||
CreateZoneAssetPools(zone.get());
|
||||
|
||||
for (auto assetType = 0; assetType < ASSET_TYPE_COUNT; assetType++)
|
||||
zone->m_pools->InitPoolDynamic(assetType);
|
||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||
{
|
||||
if (!assetEntry.m_is_reference)
|
||||
continue;
|
||||
|
||||
context.m_ignored_assets.emplace_back(assetEntry.m_asset_type, assetEntry.m_asset_name);
|
||||
}
|
||||
|
||||
const auto assetLoadingContext = std::make_unique<AssetLoadingContext>(zone.get(), context.m_asset_search_path, CreateGdtList(context));
|
||||
if (!CreateIgnoredAssetMap(context, assetLoadingContext->m_ignored_asset_map))
|
||||
return nullptr;
|
||||
|
||||
for (const auto& assetEntry : context.m_definition->m_assets)
|
||||
{
|
||||
const auto foundAssetTypeEntry = m_asset_types_by_name.find(assetEntry.m_asset_type);
|
||||
if (foundAssetTypeEntry == m_asset_types_by_name.end())
|
||||
{
|
||||
std::cout << "Unknown asset type \"" << assetEntry.m_asset_type << "\"" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!ObjLoading::LoadAssetForZone(assetLoadingContext.get(), foundAssetTypeEntry->second, assetEntry.m_asset_name))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return zone;
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ namespace IW3
|
||||
std::unordered_map<std::string, asset_type_t> m_asset_types_by_name;
|
||||
|
||||
void AddAssetTypeName(asset_type_t assetType, std::string name);
|
||||
static std::vector<Gdt*> CreateGdtList(ZoneCreationContext& context);
|
||||
bool CreateIgnoredAssetMap(ZoneCreationContext& context, std::unordered_map<std::string, asset_type_t>& ignoredAssetMap) const;
|
||||
void CreateZoneAssetPools(Zone* zone) const;
|
||||
|
||||
public:
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "ObjContainer/IWD/IWD.h"
|
||||
#include "LinkerArgs.h"
|
||||
#include "ZoneWriting.h"
|
||||
#include "Game/IW3/ZoneCreatorIW3.h"
|
||||
#include "ZoneCreation/ZoneCreationContext.h"
|
||||
#include "ZoneCreation/IZoneCreator.h"
|
||||
#include "Game/IW4/ZoneCreatorIW4.h"
|
||||
@ -30,6 +31,7 @@ namespace fs = std::filesystem;
|
||||
|
||||
const IZoneCreator* const ZONE_CREATORS[]
|
||||
{
|
||||
new IW3::ZoneCreator(),
|
||||
new IW4::ZoneCreator(),
|
||||
new T6::ZoneCreator()
|
||||
};
|
||||
|
@ -84,13 +84,13 @@ void ZoneDefinitionOutputStream::WriteEntry(const std::string& entryKey, const s
|
||||
{
|
||||
m_stream << entryKey << ",";
|
||||
|
||||
if(entryValue.find('"') != std::string::npos
|
||||
if (entryValue.find('"') != std::string::npos
|
||||
|| entryValue.find("//") != std::string::npos)
|
||||
{
|
||||
m_stream << '"';
|
||||
for(const auto& c : entryValue)
|
||||
for (const auto& c : entryValue)
|
||||
{
|
||||
switch(c)
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
m_stream << "\\\"";
|
||||
@ -107,6 +107,10 @@ void ZoneDefinitionOutputStream::WriteEntry(const std::string& entryKey, const s
|
||||
}
|
||||
m_stream << '"';
|
||||
}
|
||||
else if (entryValue.empty())
|
||||
{
|
||||
m_stream << R"("")";
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stream << entryValue;
|
||||
|
@ -85,12 +85,6 @@ public:
|
||||
|
||||
SetupBlock(zoneLoader);
|
||||
|
||||
// Skip unknown 1 byte field that the game ignores as well
|
||||
// zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(1));
|
||||
|
||||
// Skip timestamp
|
||||
// zoneLoader->AddLoadingStep(std::make_unique<StepSkipBytes>(8));
|
||||
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepAddProcessor>(std::make_unique<ProcessorInflate>(ZoneConstants::AUTHED_CHUNK_SIZE)));
|
||||
|
||||
// Start of the XFile struct
|
||||
|
@ -0,0 +1,91 @@
|
||||
#include "ZoneWriterFactoryIW3.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "ContentWriterIW3.h"
|
||||
#include "Game/IW3/IW3.h"
|
||||
#include "Game/IW3/GameIW3.h"
|
||||
#include "Game/IW3/ZoneConstantsIW3.h"
|
||||
#include "Writing/Processor/OutputProcessorDeflate.h"
|
||||
#include "Writing/Steps/StepAddOutputProcessor.h"
|
||||
#include "Writing/Steps/StepWriteXBlockSizes.h"
|
||||
#include "Writing/Steps/StepWriteZoneContentToFile.h"
|
||||
#include "Writing/Steps/StepWriteZoneContentToMemory.h"
|
||||
#include "Writing/Steps/StepWriteZoneHeader.h"
|
||||
#include "Writing/Steps/StepWriteZoneSizes.h"
|
||||
|
||||
using namespace IW3;
|
||||
|
||||
class ZoneWriterFactory::Impl
|
||||
{
|
||||
Zone* m_zone;
|
||||
std::unique_ptr<ZoneWriter> m_writer;
|
||||
|
||||
public:
|
||||
explicit Impl(Zone* zone)
|
||||
: m_zone(zone),
|
||||
m_writer(std::make_unique<ZoneWriter>())
|
||||
{
|
||||
}
|
||||
|
||||
void SetupBlocks() const
|
||||
{
|
||||
#define XBLOCK_DEF(name, type) std::make_unique<XBlock>(STR(name), name, type)
|
||||
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_TEMP, XBlock::Type::BLOCK_TYPE_TEMP));
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_RUNTIME, XBlock::Type::BLOCK_TYPE_RUNTIME));
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_LARGE_RUNTIME, XBlock::Type::BLOCK_TYPE_RUNTIME));
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_PHYSICAL_RUNTIME, XBlock::Type::BLOCK_TYPE_RUNTIME));
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_VIRTUAL, XBlock::Type::BLOCK_TYPE_NORMAL));
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_LARGE, XBlock::Type::BLOCK_TYPE_NORMAL));
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_PHYSICAL, XBlock::Type::BLOCK_TYPE_NORMAL));
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_VERTEX, XBlock::Type::BLOCK_TYPE_NORMAL));
|
||||
m_writer->AddXBlock(XBLOCK_DEF(IW3::XFILE_BLOCK_INDEX, XBlock::Type::BLOCK_TYPE_NORMAL));
|
||||
|
||||
#undef XBLOCK_DEF
|
||||
}
|
||||
|
||||
static ZoneHeader CreateHeaderForParams()
|
||||
{
|
||||
ZoneHeader header{};
|
||||
header.m_version = ZoneConstants::ZONE_VERSION;
|
||||
memcpy(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, sizeof(ZoneHeader::m_magic));
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
std::unique_ptr<ZoneWriter> CreateWriter()
|
||||
{
|
||||
SetupBlocks();
|
||||
|
||||
auto contentInMemory = std::make_unique<StepWriteZoneContentToMemory>(std::make_unique<ContentWriter>(), m_zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK);
|
||||
auto* contentInMemoryPtr = contentInMemory.get();
|
||||
m_writer->AddWritingStep(std::move(contentInMemory));
|
||||
|
||||
// Write zone header
|
||||
m_writer->AddWritingStep(std::make_unique<StepWriteZoneHeader>(CreateHeaderForParams()));
|
||||
|
||||
m_writer->AddWritingStep(std::make_unique<StepAddOutputProcessor>(std::make_unique<OutputProcessorDeflate>()));
|
||||
|
||||
// Start of the XFile struct
|
||||
m_writer->AddWritingStep(std::make_unique<StepWriteZoneSizes>(contentInMemoryPtr));
|
||||
m_writer->AddWritingStep(std::make_unique<StepWriteXBlockSizes>(m_zone));
|
||||
|
||||
// Start of the zone content
|
||||
m_writer->AddWritingStep(std::make_unique<StepWriteZoneContentToFile>(contentInMemoryPtr));
|
||||
|
||||
// Return the fully setup zoneloader
|
||||
return std::move(m_writer);
|
||||
}
|
||||
};
|
||||
|
||||
bool ZoneWriterFactory::SupportsZone(Zone* zone) const
|
||||
{
|
||||
return zone->m_game == &g_GameIW3;
|
||||
}
|
||||
|
||||
std::unique_ptr<ZoneWriter> ZoneWriterFactory::CreateWriter(Zone* zone) const
|
||||
{
|
||||
Impl impl(zone);
|
||||
return impl.CreateWriter();
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Writing/IZoneWriterFactory.h"
|
||||
|
||||
namespace IW3
|
||||
{
|
||||
class ZoneWriterFactory final : public IZoneWriterFactory
|
||||
{
|
||||
class Impl;
|
||||
|
||||
public:
|
||||
_NODISCARD bool SupportsZone(Zone* zone) const override;
|
||||
_NODISCARD std::unique_ptr<ZoneWriter> CreateWriter(Zone* zone) const override;
|
||||
};
|
||||
}
|
138
src/ZoneWriting/Writing/Processor/OutputProcessorDeflate.cpp
Normal file
138
src/ZoneWriting/Writing/Processor/OutputProcessorDeflate.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "OutputProcessorDeflate.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Writing/WritingException.h"
|
||||
|
||||
class OutputProcessorDeflate::Impl
|
||||
{
|
||||
z_stream m_stream{};
|
||||
OutputProcessorDeflate* m_base;
|
||||
|
||||
std::unique_ptr<uint8_t[]> m_buffer;
|
||||
size_t m_buffer_size;
|
||||
|
||||
public:
|
||||
Impl(OutputProcessorDeflate* baseClass, const size_t bufferSize)
|
||||
: m_buffer(std::make_unique<uint8_t[]>(bufferSize)),
|
||||
m_buffer_size(bufferSize)
|
||||
{
|
||||
m_base = baseClass;
|
||||
|
||||
m_stream.zalloc = Z_NULL;
|
||||
m_stream.zfree = Z_NULL;
|
||||
m_stream.opaque = Z_NULL;
|
||||
m_stream.avail_in = 0;
|
||||
m_stream.next_in = Z_NULL;
|
||||
m_stream.next_out = m_buffer.get();
|
||||
m_stream.avail_out = m_buffer_size;
|
||||
|
||||
const int ret = deflateInit(&m_stream, Z_DEFAULT_COMPRESSION);
|
||||
|
||||
if (ret != Z_OK)
|
||||
{
|
||||
throw std::runtime_error("Initializing deflate failed");
|
||||
}
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
deflateEnd(&m_stream);
|
||||
}
|
||||
|
||||
Impl(const Impl& other) = delete;
|
||||
Impl(Impl&& other) noexcept = default;
|
||||
Impl& operator=(const Impl& other) = delete;
|
||||
Impl& operator=(Impl&& other) noexcept = default;
|
||||
|
||||
void Write(const void* buffer, const size_t length)
|
||||
{
|
||||
m_stream.next_in = static_cast<const Bytef*>(buffer);
|
||||
m_stream.avail_in = length;
|
||||
|
||||
while (m_stream.avail_in > 0)
|
||||
{
|
||||
if (m_stream.avail_out == 0)
|
||||
{
|
||||
m_base->m_base_stream->Write(m_buffer.get(), m_buffer_size);
|
||||
m_stream.next_out = m_buffer.get();
|
||||
m_stream.avail_out = m_buffer_size;
|
||||
}
|
||||
|
||||
const auto ret = deflate(&m_stream, Z_NO_FLUSH);
|
||||
if (ret != Z_OK)
|
||||
throw WritingException("Failed to deflate memory of zone.");
|
||||
}
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
m_stream.avail_in = 0;
|
||||
m_stream.next_in = Z_NULL;
|
||||
while(true)
|
||||
{
|
||||
if (m_stream.avail_out < m_buffer_size)
|
||||
{
|
||||
m_base->m_base_stream->Write(m_buffer.get(), m_buffer_size - m_stream.avail_out);
|
||||
m_stream.next_out = m_buffer.get();
|
||||
m_stream.avail_out = m_buffer_size;
|
||||
}
|
||||
|
||||
const auto ret = deflate(&m_stream, Z_FINISH);
|
||||
if(ret == Z_OK)
|
||||
continue;
|
||||
|
||||
if (ret != Z_STREAM_END)
|
||||
throw WritingException("Failed to flush deflate memory of zone.");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_stream.avail_out < m_buffer_size)
|
||||
{
|
||||
m_base->m_base_stream->Write(m_buffer.get(), m_buffer_size - m_stream.avail_out);
|
||||
m_stream.next_out = m_buffer.get();
|
||||
m_stream.avail_out = m_buffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD int64_t Pos() const
|
||||
{
|
||||
return m_base->m_base_stream->Pos();
|
||||
}
|
||||
};
|
||||
|
||||
OutputProcessorDeflate::OutputProcessorDeflate()
|
||||
: m_impl(new Impl(this, DEFAULT_BUFFER_SIZE))
|
||||
{
|
||||
}
|
||||
|
||||
OutputProcessorDeflate::OutputProcessorDeflate(const size_t bufferSize)
|
||||
: m_impl(new Impl(this, bufferSize))
|
||||
{
|
||||
}
|
||||
|
||||
OutputProcessorDeflate::~OutputProcessorDeflate()
|
||||
{
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
|
||||
void OutputProcessorDeflate::Write(const void* buffer, const size_t length)
|
||||
{
|
||||
m_impl->Write(buffer, length);
|
||||
}
|
||||
|
||||
void OutputProcessorDeflate::Flush()
|
||||
{
|
||||
m_impl->Flush();
|
||||
}
|
||||
|
||||
int64_t OutputProcessorDeflate::Pos()
|
||||
{
|
||||
return m_impl->Pos();
|
||||
}
|
26
src/ZoneWriting/Writing/Processor/OutputProcessorDeflate.h
Normal file
26
src/ZoneWriting/Writing/Processor/OutputProcessorDeflate.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include "Writing/OutputStreamProcessor.h"
|
||||
|
||||
class OutputProcessorDeflate final : public OutputStreamProcessor
|
||||
{
|
||||
class Impl;
|
||||
Impl* m_impl;
|
||||
|
||||
static constexpr size_t DEFAULT_BUFFER_SIZE = 0x40000;
|
||||
|
||||
public:
|
||||
OutputProcessorDeflate();
|
||||
OutputProcessorDeflate(size_t bufferSize);
|
||||
~OutputProcessorDeflate() override;
|
||||
OutputProcessorDeflate(const OutputProcessorDeflate& other) = delete;
|
||||
OutputProcessorDeflate(OutputProcessorDeflate&& other) noexcept = default;
|
||||
OutputProcessorDeflate& operator=(const OutputProcessorDeflate& other) = delete;
|
||||
OutputProcessorDeflate& operator=(OutputProcessorDeflate&& other) noexcept = default;
|
||||
|
||||
void Write(const void* buffer, size_t length) override;
|
||||
void Flush() override;
|
||||
int64_t Pos() override;
|
||||
};
|
@ -1,11 +1,13 @@
|
||||
#include "ZoneWriting.h"
|
||||
|
||||
#include "Game/IW3/ZoneWriterFactoryIW3.h"
|
||||
#include "Game/IW4/ZoneWriterFactoryIW4.h"
|
||||
#include "Game/T6/ZoneWriterFactoryT6.h"
|
||||
#include "Writing/IZoneWriterFactory.h"
|
||||
|
||||
IZoneWriterFactory* ZoneWriterFactories[]
|
||||
{
|
||||
new IW3::ZoneWriterFactory(),
|
||||
new IW4::ZoneWriterFactory(),
|
||||
new T6::ZoneWriterFactory()
|
||||
};
|
||||
@ -15,7 +17,7 @@ bool ZoneWriting::WriteZone(std::ostream& stream, Zone* zone)
|
||||
std::unique_ptr<ZoneWriter> zoneWriter;
|
||||
for (auto* factory : ZoneWriterFactories)
|
||||
{
|
||||
if(factory->SupportsZone(zone))
|
||||
if (factory->SupportsZone(zone))
|
||||
{
|
||||
zoneWriter = factory->CreateWriter(zone);
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user