mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-06-10 23:08:05 -05:00
Add IW3 zone writing
This commit is contained in:
@ -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;
|
||||
|
Reference in New Issue
Block a user