maint: remove components I will never use

This commit is contained in:
Diavolo 2023-06-18 14:59:37 +02:00
parent 7c05b151b7
commit 2ae991ccbf
No known key found for this signature in database
GPG Key ID: FA77F074E98D98A5
100 changed files with 42 additions and 10710 deletions

3
.gitmodules vendored
View File

@ -41,6 +41,3 @@
[submodule "deps/rapidjson"]
path = deps/rapidjson
url = https://github.com/Tencent/rapidjson.git
[submodule "deps/iw4-open-formats"]
path = deps/iw4-open-formats
url = https://github.com/diamante0018/iw4-open-formats.git

@ -1 +0,0 @@
Subproject commit 5e17794ed16351d3f77b72ff1ff8c52621e7b51d

View File

@ -1,44 +0,0 @@
iw4_open_formats = {
source = path.join(dependencies.basePath, "iw4-open-formats"),
}
function iw4_open_formats.import()
links "iw4-open-formats"
iw4_open_formats.includes()
end
function iw4_open_formats.includes()
includedirs {
path.join(iw4_open_formats.source, "include")
}
end
function iw4_open_formats.project()
project "iw4-open-formats"
language "C++"
iw4_open_formats.includes()
pchheader "std_include.hpp"
pchsource (path.join(iw4_open_formats.source, "src/iw4-of/std_include.cpp"))
files {
path.join(iw4_open_formats.source, "src/iw4-of/**.hpp"),
path.join(iw4_open_formats.source, "src/iw4-of/**.cpp"),
}
includedirs {
path.join(iw4_open_formats.source, "src/iw4-of"),
path.join(iw4_open_formats.source, "include"),
}
libtomcrypt.includes()
libtommath.includes()
rapidjson.includes()
zlib.includes()
kind "StaticLib"
end
table.insert(dependencies, iw4_open_formats)

View File

@ -28,7 +28,6 @@
#include "Modules/Gamepad.hpp"
#include "Modules/IPCPipe.hpp"
#include "Modules/Lean.hpp"
#include "Modules/MapDump.hpp"
#include "Modules/MapRotation.hpp"
#include "Modules/Materials.hpp"
#include "Modules/ModList.hpp"
@ -107,7 +106,6 @@ namespace Components
Register(new Network());
Register(new Logger());
Register(new UIScript());
Register(new ZoneBuilder());
Register(new ArenaLength());
Register(new AssetHandler());
@ -137,7 +135,6 @@ namespace Components
Register(new Gamepad());
Register(new Lean());
Register(new Localization());
Register(new MapDump());
Register(new MapRotation());
Register(new Maps());
Register(new Materials());

View File

@ -69,7 +69,6 @@ namespace Components
#include "Modules/Logger.hpp"
#include "Modules/Singleton.hpp"
#include "Modules/UIScript.hpp"
#include "Modules/ZoneBuilder.hpp"
#include "Modules/AssetHandler.hpp"
#include "Modules/Dedicated.hpp"

View File

@ -2,44 +2,10 @@
#include "FastFiles.hpp"
#include "Weapon.hpp"
#include "AssetInterfaces/IFont_s.hpp"
#include "AssetInterfaces/IWeapon.hpp"
#include "AssetInterfaces/IXModel.hpp"
#include "AssetInterfaces/IFxWorld.hpp"
#include "AssetInterfaces/IMapEnts.hpp"
#include "AssetInterfaces/IRawFile.hpp"
#include "AssetInterfaces/IComWorld.hpp"
#include "AssetInterfaces/IGfxImage.hpp"
#include "AssetInterfaces/IGfxWorld.hpp"
#include "AssetInterfaces/IMaterial.hpp"
#include "AssetInterfaces/ISndCurve.hpp"
#include "AssetInterfaces/IMenuList.hpp"
#include "AssetInterfaces/IclipMap_t.hpp"
#include "AssetInterfaces/ImenuDef_t.hpp"
#include "AssetInterfaces/ITracerDef.hpp"
#include "AssetInterfaces/IPhysPreset.hpp"
#include "AssetInterfaces/IXAnimParts.hpp"
#include "AssetInterfaces/IFxEffectDef.hpp"
#include "AssetInterfaces/IGameWorldMp.hpp"
#include "AssetInterfaces/IGameWorldSp.hpp"
#include "AssetInterfaces/IGfxLightDef.hpp"
#include "AssetInterfaces/ILoadedSound.hpp"
#include "AssetInterfaces/IPhysCollmap.hpp"
#include "AssetInterfaces/IStringTable.hpp"
#include "AssetInterfaces/IXModelSurfs.hpp"
#include "AssetInterfaces/ILocalizeEntry.hpp"
#include "AssetInterfaces/Isnd_alias_list_t.hpp"
#include "AssetInterfaces/IMaterialPixelShader.hpp"
#include "AssetInterfaces/IMaterialTechniqueSet.hpp"
#include "AssetInterfaces/IMaterialVertexShader.hpp"
#include "AssetInterfaces/IStructuredDataDefSet.hpp"
#include "AssetInterfaces/IMaterialVertexDeclaration.hpp"
namespace Components
{
thread_local int AssetHandler::BypassState = 0;
bool AssetHandler::ShouldSearchTempAssets = false;
std::map<Game::XAssetType, AssetHandler::IAsset*> AssetHandler::AssetInterfaces;
std::map<Game::XAssetType, Utils::Slot<AssetHandler::Callback>> AssetHandler::TypeCallbacks;
Utils::Signal<AssetHandler::RestrictCallback> AssetHandler::RestrictSignal;
@ -49,28 +15,6 @@ namespace Components
std::map<std::string, Game::XAssetHeader> AssetHandler::TemporaryAssets[Game::ASSET_TYPE_COUNT];
void AssetHandler::RegisterInterface(IAsset* iAsset)
{
if (!iAsset) return;
if (iAsset->getType() == Game::XAssetType::ASSET_TYPE_INVALID)
{
delete iAsset;
return;
}
if (AssetHandler::AssetInterfaces.contains(iAsset->getType()))
{
Logger::Print("Duplicate asset interface: {}\n", Game::DB_GetXAssetTypeName(iAsset->getType()));
delete AssetHandler::AssetInterfaces[iAsset->getType()];
}
else
{
Logger::Print("Asset interface registered: {}\n", Game::DB_GetXAssetTypeName(iAsset->getType()));
}
AssetHandler::AssetInterfaces[iAsset->getType()] = iAsset;
}
void AssetHandler::ClearTemporaryAssets()
{
for (int i = 0; i < Game::ASSET_TYPE_COUNT; ++i)
@ -379,68 +323,6 @@ namespace Components
offset->pointer = *static_cast<void**>(pointer);
}
void AssetHandler::ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder)
{
if (AssetHandler::AssetInterfaces.contains(asset.type))
{
AssetHandler::AssetInterfaces[asset.type]->save(asset.header, builder);
}
else
{
Logger::Error(Game::ERR_FATAL, "No interface for type '{}'!", Game::DB_GetXAssetTypeName(asset.type));
}
}
void AssetHandler::ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder)
{
if (AssetHandler::AssetInterfaces.contains(asset.type))
{
AssetHandler::AssetInterfaces[asset.type]->mark(asset.header, builder);
}
else
{
Logger::Error(Game::ERR_FATAL, "No interface for type '{}'!", Game::DB_GetXAssetTypeName(asset.type));
}
}
Game::XAssetHeader AssetHandler::FindAssetForZone(Game::XAssetType type, const std::string& filename, ZoneBuilder::Zone* builder, bool isSubAsset)
{
ZoneBuilder::Zone::AssetRecursionMarker _(builder);
Game::XAssetHeader header = { nullptr };
if (type >= Game::ASSET_TYPE_COUNT) return header;
auto tempPool = &AssetHandler::TemporaryAssets[type];
auto entry = tempPool->find(filename);
if (entry != tempPool->end())
{
return { entry->second };
}
if (AssetHandler::AssetInterfaces.contains(type))
{
AssetHandler::AssetInterfaces[type]->load(&header, filename, builder);
if (header.data)
{
Components::AssetHandler::StoreTemporaryAsset(type, header);
}
}
if (!header.data && isSubAsset)
{
header = ZoneBuilder::GetEmptyAssetIfCommon(type, filename, builder);
}
if (!header.data)
{
header = Game::DB_FindXAssetHeader(type, filename.data());
if (header.data) Components::AssetHandler::StoreTemporaryAsset(type, header); // Might increase efficiency...
}
return header;
}
Game::XAssetHeader AssetHandler::FindOriginalAsset(Game::XAssetType type, const char* filename)
{
AssetHandler::SetBypassState(true);
@ -484,7 +366,7 @@ namespace Components
{
AssertSize(Game::XAssetEntry, 16);
size_t size = (ZoneBuilder::IsEnabled() ? 1183968 : 789312);
constexpr std::size_t size = 789312;
Game::XAssetEntry* entryPool = Utils::Memory::GetAllocator()->allocateArray<Game::XAssetEntry>(size);
// Apply new size
@ -553,7 +435,7 @@ namespace Components
Utils::Hook(0x5BB6EC, AssetHandler::StoreEmptyAssetStub, HOOK_CALL).install()->quick();
// Intercept missing asset messages
if (!ZoneBuilder::IsEnabled()) Utils::Hook(0x5BB3F2, AssetHandler::MissingAssetError, HOOK_CALL).install()->quick();
Utils::Hook(0x5BB3F2, AssetHandler::MissingAssetError, HOOK_CALL).install()->quick();
// Log missing empty assets
Scheduler::Loop([]
@ -578,77 +460,27 @@ namespace Components
});
Game::ReallocateAssetPool(Game::ASSET_TYPE_GAMEWORLD_SP, 1);
Game::ReallocateAssetPool(Game::ASSET_TYPE_IMAGE, ZoneBuilder::IsEnabled() ? 14336 * 2 : 7168);
Game::ReallocateAssetPool(Game::ASSET_TYPE_IMAGE, 7168);
Game::ReallocateAssetPool(Game::ASSET_TYPE_LOADED_SOUND, 2700 * 2);
Game::ReallocateAssetPool(Game::ASSET_TYPE_FX, 1200 * 2);
Game::ReallocateAssetPool(Game::ASSET_TYPE_LOCALIZE_ENTRY, 14000);
Game::ReallocateAssetPool(Game::ASSET_TYPE_XANIMPARTS, 8192 * 2);
Game::ReallocateAssetPool(Game::ASSET_TYPE_XMODEL, 5125 * 2);
Game::ReallocateAssetPool(Game::ASSET_TYPE_PHYSPRESET, 128);
Game::ReallocateAssetPool(Game::ASSET_TYPE_PIXELSHADER, ZoneBuilder::IsEnabled() ? 0x4000 : 10000);
Game::ReallocateAssetPool(Game::ASSET_TYPE_VERTEXSHADER, ZoneBuilder::IsEnabled() ? 0x2000 : 3072);
Game::ReallocateAssetPool(Game::ASSET_TYPE_PIXELSHADER, 10000);
Game::ReallocateAssetPool(Game::ASSET_TYPE_VERTEXSHADER, 3072);
Game::ReallocateAssetPool(Game::ASSET_TYPE_MATERIAL, 8192 * 2);
Game::ReallocateAssetPool(Game::ASSET_TYPE_VERTEXDECL, ZoneBuilder::IsEnabled() ? 0x400 : 196);
Game::ReallocateAssetPool(Game::ASSET_TYPE_VERTEXDECL, 196);
Game::ReallocateAssetPool(Game::ASSET_TYPE_WEAPON, WEAPON_LIMIT);
Game::ReallocateAssetPool(Game::ASSET_TYPE_STRINGTABLE, 800);
Game::ReallocateAssetPool(Game::ASSET_TYPE_IMPACT_FX, 8);
// Register asset interfaces
if (ZoneBuilder::IsEnabled())
{
Game::ReallocateAssetPool(Game::ASSET_TYPE_MAP_ENTS, 10);
Game::ReallocateAssetPool(Game::ASSET_TYPE_XMODEL_SURFS, 8192 * 2);
Game::ReallocateAssetPool(Game::ASSET_TYPE_TECHNIQUE_SET, 0x2000);
Game::ReallocateAssetPool(Game::ASSET_TYPE_FONT, 32);
Game::ReallocateAssetPool(Game::ASSET_TYPE_RAWFILE, 2048);
Game::ReallocateAssetPool(Game::ASSET_TYPE_LEADERBOARD, 500);
AssetHandler::RegisterInterface(new Assets::IFont_s());
AssetHandler::RegisterInterface(new Assets::IWeapon());
AssetHandler::RegisterInterface(new Assets::IXModel());
AssetHandler::RegisterInterface(new Assets::IFxWorld());
AssetHandler::RegisterInterface(new Assets::IMapEnts());
AssetHandler::RegisterInterface(new Assets::IRawFile());
AssetHandler::RegisterInterface(new Assets::IComWorld());
AssetHandler::RegisterInterface(new Assets::IGfxImage());
AssetHandler::RegisterInterface(new Assets::IGfxWorld());
AssetHandler::RegisterInterface(new Assets::ISndCurve());
AssetHandler::RegisterInterface(new Assets::IMaterial());
AssetHandler::RegisterInterface(new Assets::IMenuList());
AssetHandler::RegisterInterface(new Assets::IclipMap_t());
AssetHandler::RegisterInterface(new Assets::ImenuDef_t());
AssetHandler::RegisterInterface(new Assets::ITracerDef());
AssetHandler::RegisterInterface(new Assets::IPhysPreset());
AssetHandler::RegisterInterface(new Assets::IXAnimParts());
AssetHandler::RegisterInterface(new Assets::IFxEffectDef());
AssetHandler::RegisterInterface(new Assets::IGameWorldMp());
AssetHandler::RegisterInterface(new Assets::IGameWorldSp());
AssetHandler::RegisterInterface(new Assets::IGfxLightDef());
AssetHandler::RegisterInterface(new Assets::ILoadedSound());
AssetHandler::RegisterInterface(new Assets::IPhysCollmap());
AssetHandler::RegisterInterface(new Assets::IStringTable());
AssetHandler::RegisterInterface(new Assets::IXModelSurfs());
AssetHandler::RegisterInterface(new Assets::ILocalizeEntry());
AssetHandler::RegisterInterface(new Assets::Isnd_alias_list_t());
AssetHandler::RegisterInterface(new Assets::IMaterialPixelShader());
AssetHandler::RegisterInterface(new Assets::IMaterialTechniqueSet());
AssetHandler::RegisterInterface(new Assets::IMaterialVertexShader());
AssetHandler::RegisterInterface(new Assets::IStructuredDataDefSet());
AssetHandler::RegisterInterface(new Assets::IMaterialVertexDeclaration());
}
}
AssetHandler::~AssetHandler()
{
AssetHandler::ClearTemporaryAssets();
for (auto i = AssetHandler::AssetInterfaces.begin(); i != AssetHandler::AssetInterfaces.end(); ++i)
{
delete i->second;
}
AssetHandler::Relocations.clear();
AssetHandler::AssetInterfaces.clear();
AssetHandler::RestrictSignal.clear();
AssetHandler::TypeCallbacks.clear();
}

View File

@ -5,17 +5,6 @@ namespace Components
class AssetHandler : public Component
{
public:
class IAsset
{
public:
virtual ~IAsset() {}
virtual Game::XAssetType getType() { return Game::XAssetType::ASSET_TYPE_INVALID; }
virtual void mark(Game::XAssetHeader /*header*/, ZoneBuilder::Zone* /*builder*/) {}
virtual void save(Game::XAssetHeader /*header*/, ZoneBuilder::Zone* /*builder*/) {}
virtual void dump(Game::XAssetHeader /*header*/) {}
virtual void load(Game::XAssetHeader* /*header*/, const std::string& /*name*/, ZoneBuilder::Zone* /*builder*/) {}
};
typedef Game::XAssetHeader(Callback)(Game::XAssetType type, const std::string& name);
typedef void(RestrictCallback)(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name, bool* restrict);
@ -28,11 +17,7 @@ namespace Components
static void ClearRelocations();
static void Relocate(void* start, void* to, DWORD size = 4);
static void ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder);
static void ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder);
static Game::XAssetHeader FindOriginalAsset(Game::XAssetType type, const char* filename);
static Game::XAssetHeader FindAssetForZone(Game::XAssetType type, const std::string& filename, ZoneBuilder::Zone* builder, bool isSubAsset = true);
static void ClearTemporaryAssets();
static void StoreTemporaryAsset(Game::XAssetType type, Game::XAssetHeader asset);
@ -49,7 +34,6 @@ namespace Components
static std::map<std::string, Game::XAssetHeader> TemporaryAssets[Game::XAssetType::ASSET_TYPE_COUNT];
static std::map<Game::XAssetType, IAsset*> AssetInterfaces;
static std::map<Game::XAssetType, Utils::Slot<Callback>> TypeCallbacks;
static Utils::Signal<RestrictCallback> RestrictSignal;
@ -57,8 +41,6 @@ namespace Components
static std::vector<std::pair<Game::XAssetType, std::string>> EmptyAssets;
static void RegisterInterface(IAsset* iAsset);
static Game::XAssetHeader FindAsset(Game::XAssetType type, const char* filename);
static Game::XAssetHeader FindTemporaryAsset(Game::XAssetType type, const char* filename);
static bool IsAssetEligible(Game::XAssetType type, Game::XAssetHeader* asset);

View File

@ -1,71 +0,0 @@
#include <STDInclude.hpp>
#include "IComWorld.hpp"
#define IW4X_COMMAP_VERSION 0
namespace Assets
{
void IComWorld::load(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder)
{
header->comWorld = builder->getIW4OfApi()->read<Game::ComWorld>(Game::XAssetType::ASSET_TYPE_COMWORLD, _name);
}
void IComWorld::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::ComWorld* asset = header.comWorld;
if (asset->primaryLights)
{
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
{
if (asset->primaryLights[i].defName)
{
builder->loadAssetByName(Game::XAssetType::ASSET_TYPE_LIGHT_DEF, asset->primaryLights[i].defName, false);
}
}
}
}
void IComWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::ComWorld, 16);
Utils::Stream* buffer = builder->getBuffer();
Game::ComWorld* asset = header.comWorld;
Game::ComWorld* dest = buffer->dest<Game::ComWorld>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->primaryLights)
{
AssertSize(Game::ComPrimaryLight, 68);
buffer->align(Utils::Stream::ALIGN_4);
Game::ComPrimaryLight* destLights = buffer->dest<Game::ComPrimaryLight>();
buffer->saveArray(asset->primaryLights, asset->primaryLightCount);
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
{
Game::ComPrimaryLight* destLight = &destLights[i];
Game::ComPrimaryLight* light = &asset->primaryLights[i];
if (light->defName)
{
buffer->saveString(light->defName);
Utils::Stream::ClearPointer(&destLight->defName);
}
}
Utils::Stream::ClearPointer(&dest->primaryLights);
}
buffer->popBlock();
}
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace Assets
{
class IComWorld : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_COMWORLD; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,291 +0,0 @@
#include <STDInclude.hpp>
#include "IFont_s.hpp"
#define STB_TRUETYPE_IMPLEMENTATION
#include <stb_truetype.hpp>
namespace Assets
{
namespace
{
int PackFonts(const uint8_t* data, std::vector<uint16_t>& charset, Game::Glyph* glyphs, float pixel_height, unsigned char* pixels, int pw, int ph, int yOffset)
{
stbtt_fontinfo f;
f.userdata = NULL;
if (!stbtt_InitFont(&f, data, 0))
return -1;
std::memset(pixels, 0, pw * ph);
int x = 1, y = 1, bottom_y = 1;
float scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
int i = 0;
for (auto& ch : charset)
{
int advance, lsb, x0, y0, x1, y1, gw, gh;
int g = stbtt_FindGlyphIndex(&f, ch);
stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1, &y1);
gw = x1 - x0;
gh = y1 - y0;
if (x + gw + 1 >= pw)
{
// Advance to next row
y = bottom_y;
x = 1;
}
if (y + gh + 1 >= ph)
{
// Check if we have ran out of the room
return -i;
}
stbtt_MakeGlyphBitmap(&f, pixels + x + y * pw, gw, gh, pw, scale, scale, g);
auto& glyph = glyphs[i++];
glyph.letter = ch;
glyph.s0 = x / static_cast<float>(pw);
glyph.s1 = (x + gw) / static_cast<float>(pw);
glyph.t0 = y / static_cast<float>(ph);
glyph.t1 = (y + gh) / static_cast<float>(ph);
glyph.pixelWidth = static_cast<char>(gw);
glyph.pixelHeight = static_cast<char>(gh);
glyph.x0 = static_cast<char>(x0);
glyph.y0 = static_cast<char>(y0 + yOffset);
glyph.dx = static_cast<char>(std::roundf(scale * advance));
// Advance to next col
x = x + gw + 1;
// Expand bottom of current row if current glyph is bigger
if (y + gh + 1 > bottom_y)
{
bottom_y = y + gh + 1;
}
}
return bottom_y;
}
}
void IFont_s::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
const auto* asset = header.font;
if (asset->material)
{
builder->loadAsset(Game::ASSET_TYPE_MATERIAL, asset->material);
}
if (asset->glowMaterial)
{
builder->loadAsset(Game::ASSET_TYPE_MATERIAL, asset->glowMaterial);
}
}
void IFont_s::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
Components::FileSystem::File fontDefFile(std::format("{}.json", name));
Components::FileSystem::File fontFile(std::format("{}.ttf", name));
if (!fontDefFile.exists() || !fontFile.exists())
{
return;
}
nlohmann::json fontDef;
try
{
fontDef = nlohmann::json::parse(fontDefFile.getBuffer());
}
catch (const nlohmann::json::parse_error& ex)
{
Components::Logger::Error(Game::ERR_FATAL, "JSON Parse Error: {}. Font {} is invalid\n", ex.what(), name);
return;
}
auto w = fontDef["textureWidth"].get<int>();
auto h = fontDef["textureHeight"].get<int>();
auto size = fontDef["size"].get<int>();
auto yOffset = fontDef["yOffset"].get<int>();
auto* pixels = builder->getAllocator()->allocateArray<uint8_t>(w * h);
// Setup assets
const auto* texName = builder->getAllocator()->duplicateString(Utils::String::VA("if_%s", name.data() + 6 /* skip "fonts/" */));
const auto* fontName = builder->getAllocator()->duplicateString(name);
const auto* glowMaterialName = builder->getAllocator()->duplicateString(Utils::String::VA("%s_glow", name.data()));
auto* image = builder->getAllocator()->allocate<Game::GfxImage>();
std::memcpy(image, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_IMAGE, "gamefonts_pc").image, sizeof(Game::GfxImage));
image->name = texName;
auto* material = builder->getAllocator()->allocate<Game::Material>();
std::memcpy(material, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc").material, sizeof(Game::Material));
auto textureTable = builder->getAllocator()->allocate<Game::MaterialTextureDef>();
std::memcpy(textureTable, material->textureTable, sizeof(Game::MaterialTextureDef));
material->textureTable = textureTable;
material->textureTable->u.image = image;
material->info.name = fontName;
auto* glowMaterial = builder->getAllocator()->allocate<Game::Material>();
std::memcpy(glowMaterial, Game::DB_FindXAssetHeader(Game::ASSET_TYPE_MATERIAL, "fonts/gamefonts_pc_glow").material, sizeof(Game::Material));
glowMaterial->textureTable = material->textureTable;
glowMaterial->info.name = glowMaterialName;
std::vector<std::uint16_t> charset;
if (fontDef["charset"].is_array())
{
nlohmann::json::array_t charsetArray = fontDef["charset"];
for (auto& ch : charsetArray)
{
charset.push_back(static_cast<std::uint16_t>(ch.get<int>()));
}
// order matters
std::ranges::sort(charset);
for (std::uint16_t i = 32; i < 128; i++)
{
if (std::ranges::find(charset, i) == charset.end())
{
Components::Logger::Error(Game::ERR_FATAL, "Font {} missing codepoint {}", name.data(), i);
}
}
}
else
{
for (std::uint16_t i = 32; i < 128; i++)
{
charset.push_back(i);
}
}
auto* font = builder->getAllocator()->allocate<Game::Font_s>();
font->fontName = fontName;
font->pixelHeight = size;
font->material = material;
font->glowMaterial = glowMaterial;
font->glyphCount = static_cast<int>(charset.size());
font->glyphs = builder->getAllocator()->allocateArray<Game::Glyph>(charset.size());
// Generate glyph data
int result = PackFonts(reinterpret_cast<const uint8_t*>(fontFile.getBuffer().data()), charset, font->glyphs, static_cast<float>(size), pixels, w, h, yOffset);
if (result == -1)
{
Components::Logger::Error(Game::ERR_FATAL, "Truetype font {} is broken", name);
}
else if (result < 0)
{
Components::Logger::Error(Game::ERR_FATAL, "Texture size of font {} is not enough", name);
}
else if(h - result > size)
{
Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Texture of font {} have too much left over space: {}\n", name, h - result);
}
header->font = font;
// Save generated materials
Game::XAssetHeader tmpHeader;
tmpHeader.image = image;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_IMAGE, tmpHeader);
tmpHeader.material = material;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_MATERIAL, tmpHeader);
tmpHeader.material = glowMaterial;
Components::AssetHandler::StoreTemporaryAsset(Game::ASSET_TYPE_MATERIAL, tmpHeader);
// Save generated image
Utils::IO::CreateDir("userraw\\images");
int fileSize = w * h * 4;
int iwiHeaderSize = static_cast<int>(sizeof(Game::GfxImageFileHeader));
Game::GfxImageFileHeader iwiHeader =
{
{ 'I', 'W', 'i' },
/* version */
8,
/* flags */
2,
/* format */
Game::IMG_FORMAT_BITMAP_RGBA,
0,
/* dimensions(x, y, z) */
{ static_cast<short>(w), static_cast<short>(h), 1 },
/* fileSizeForPicmip (mipSize in bytes + sizeof(GfxImageFileHeader)) */
{ fileSize + iwiHeaderSize, fileSize, fileSize, fileSize }
};
std::string outIwi;
outIwi.resize(fileSize + sizeof(Game::GfxImageFileHeader));
std::memcpy(outIwi.data(), &iwiHeader, sizeof(Game::GfxImageFileHeader));
// Generate RGBA data
auto* rgbaPixels = outIwi.data() + sizeof(Game::GfxImageFileHeader);
for (auto i = 0; i < w * h * 4; i += 4)
{
rgbaPixels[i + 0] = static_cast<char>(255);
rgbaPixels[i + 1] = static_cast<char>(255);
rgbaPixels[i + 2] = static_cast<char>(255);
rgbaPixels[i + 3] = static_cast<char>(pixels[i / 4]);
}
Utils::IO::WriteFile(std::format("userraw\\images\\{}.iwi", texName), outIwi);
}
void IFont_s::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::Font_s, 24);
AssertSize(Game::Glyph, 24);
auto* buffer = builder->getBuffer();
auto* asset = header.font;
auto* dest = buffer->dest<Game::Font_s>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->fontName)
{
buffer->saveString(asset->fontName);
Utils::Stream::ClearPointer(&dest->fontName);
}
dest->material = builder->saveSubAsset(Game::ASSET_TYPE_MATERIAL, asset->material).material;
dest->glowMaterial = builder->saveSubAsset(Game::ASSET_TYPE_MATERIAL, asset->glowMaterial).material;
if (asset->glyphs)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glyphs, asset->glyphCount);
Utils::Stream::ClearPointer(&dest->glyphs);
}
buffer->popBlock();
}
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace Assets
{
class IFont_s : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FONT; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,456 +0,0 @@
#include <STDInclude.hpp>
#include "IFxEffectDef.hpp"
namespace Assets
{
void IFxEffectDef::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
if (!header->data) this->loadEfx(header, name, builder); // Check if we have an editor fx
if (!header->data) this->loadFromIW4OF(header, name, builder); // Check if we need to import a new one into the game
if (!header->data /*&& !builder->isPrimaryAsset()*/) this->loadNative(header, name, builder); // Check if there is a native one
assert(header->data);
}
void IFxEffectDef::loadFromIW4OF(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->fx = builder->getIW4OfApi()->read<Game::FxEffectDef>(Game::XAssetType::ASSET_TYPE_FX, name);
}
void IFxEffectDef::loadEfx(Game::XAssetHeader* /*header*/, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
#ifdef DEBUG
Components::FileSystem::File rawFx(Utils::String::VA("fx/%s.efx", name.data()));
if (rawFx.exists())
{
const char* session = rawFx.getBuffer().data();
Game::Com_BeginParseSession("fx");
Game::Com_SetSpaceDelimited(0);
Game::Com_SetParseNegativeNumbers(1);
const char* format = Game::Com_Parse(&session);
if (format != "iwfx"s)
{
Game::Com_EndParseSession();
Components::Logger::Error(Game::ERR_FATAL, "Effect needs to be updated from the legacy format.\n");
}
int version = atoi(Game::Com_Parse(&session));
if (version > 2)
{
Game::Com_EndParseSession();
Components::Logger::Error(Game::ERR_FATAL, "Version {} is too high. I can only handle up to 2.\n", version);
}
Utils::Memory::Allocator allocator;
Game::FxEditorEffectDef* efx = allocator.allocate<Game::FxEditorEffectDef>();
ZeroMemory(efx, sizeof(efx));
for (efx->elemCount = 0; ; ++efx->elemCount)
{
const char* value = Game::Com_Parse(&session);
if (!value) break;
if (*value != '{')
{
Components::Logger::Error(Game::ERR_FATAL, "Expected '{' to start a new segment, found '{}' instead.\n", value);
}
if (efx->elemCount >= ARRAYSIZE(efx->elems))
{
Components::Logger::Error(Game::ERR_FATAL, "Cannot have more than {} segments.\n", ARRAYSIZE(efx->elems));
}
Game::FxEditorElemDef* element = &efx->elems[efx->elemCount];
// TODO: Initialize some stuff here
while (true)
{
std::string newValue = Game::Com_Parse(&session);
if (newValue[0] != '}') break;
for (int i = 0; i < FX_ELEM_FIELD_COUNT; ++i)
{
if (Game::s_elemFields[i].keyName == std::string(newValue))
{
// TODO: Allow loading assets from raw!
if (Game::s_elemFields[i].handler(&session, element)) break;
Components::Logger::Error(Game::ERR_FATAL, "Failed to parse element {}!\n", newValue);
}
}
if (!Game::Com_MatchToken(&session, ";", 1))
{
Components::Logger::Error(Game::ERR_FATAL, "Expected token ';'\n");
}
}
}
Game::Com_EndParseSession();
// TODO: Convert editor fx to real fx
}
#else
(void)name;
#endif
}
void IFxEffectDef::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->fx = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).fx;
}
void IFxEffectDef::markFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder)
{
switch (elemType)
{
case 7:
{
if (visuals->model)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, visuals->model);
}
break;
}
case 8:
case 9:
break;
case 0xA:
{
if (visuals->soundName)
{
// Double "find call" but we have to because otherwise we'd crash on missing asset
// Sometimes Fx reference by name a sound that does not exist. IW oversight ?
// Never happens on iw3 but often happens on iw5, especially DLC maps.
if (Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_SOUND, visuals->soundName, builder, false).data)
{
builder->loadAssetByName(Game::XAssetType::ASSET_TYPE_SOUND, visuals->soundName, false);
}
}
break;
}
case 0xC:
{
if (visuals->effectDef.handle)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, visuals->effectDef.handle, false);
}
break;
}
default:
{
if (visuals->material)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, visuals->material);
}
break;
}
}
}
void IFxEffectDef::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::FxEffectDef* asset = header.fx;
for (int i = 0; i < (asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot); ++i)
{
Game::FxElemDef* elemDef = &asset->elemDefs[i];
{
if (elemDef->elemType == 11)
{
if (elemDef->visuals.markArray)
{
for (char j = 0; j < elemDef->visualCount; ++j)
{
if (elemDef->visuals.markArray[j].materials[0])
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, elemDef->visuals.markArray[j].materials[0]);
}
if (elemDef->visuals.markArray[j].materials[1])
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, elemDef->visuals.markArray[j].materials[1]);
}
}
}
}
else if (elemDef->visualCount > 1)
{
if (elemDef->visuals.array)
{
for (char j = 0; j < elemDef->visualCount; ++j)
{
this->markFxElemVisuals(&elemDef->visuals.array[j], elemDef->elemType, builder);
}
}
}
else
{
this->markFxElemVisuals(&elemDef->visuals.instance, elemDef->elemType, builder);
}
}
if (elemDef->effectOnImpact.handle)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, elemDef->effectOnImpact.handle, false);
}
if (elemDef->effectOnDeath.handle)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, elemDef->effectOnDeath.handle, false);
}
if (elemDef->effectEmitted.handle)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, elemDef->effectEmitted.handle, false);
}
}
}
void IFxEffectDef::saveFxElemVisuals(Game::FxElemVisuals* visuals, Game::FxElemVisuals* destVisuals, char elemType, Components::ZoneBuilder::Zone* builder)
{
Utils::Stream* buffer = builder->getBuffer();
switch (elemType)
{
case Game::FX_ELEM_TYPE_MODEL:
{
if (visuals->model)
{
destVisuals->model = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, visuals->model).model;
}
break;
}
case Game::FX_ELEM_TYPE_OMNI_LIGHT:
case Game::FX_ELEM_TYPE_SPOT_LIGHT:
break;
case Game::FX_ELEM_TYPE_SOUND:
{
if (visuals->soundName)
{
buffer->saveString(visuals->soundName);
Utils::Stream::ClearPointer(&destVisuals->soundName);
}
break;
}
case Game::FX_ELEM_TYPE_RUNNER:
{
if (visuals->effectDef.handle)
{
buffer->saveString(visuals->effectDef.handle->name);
Utils::Stream::ClearPointer(&destVisuals->effectDef.handle);
}
break;
}
default:
{
if (visuals->material)
{
destVisuals->material = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, visuals->material).material;
}
break;
}
}
}
void IFxEffectDef::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::FxEffectDef, 32);
Utils::Stream* buffer = builder->getBuffer();
Game::FxEffectDef* asset = header.fx;
Game::FxEffectDef* dest = buffer->dest<Game::FxEffectDef>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->elemDefs)
{
AssertSize(Game::FxElemDef, 252);
buffer->align(Utils::Stream::ALIGN_4);
Game::FxElemDef* destElemDefs = buffer->dest<Game::FxElemDef>();
buffer->saveArray(asset->elemDefs, asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot);
for (int i = 0; i < (asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot); ++i)
{
Game::FxElemDef* destElemDef = &destElemDefs[i];
Game::FxElemDef* elemDef = &asset->elemDefs[i];
if (elemDef->velSamples)
{
AssertSize(Game::FxElemVelStateSample, 96);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(elemDef->velSamples, elemDef->velIntervalCount + 1);
Utils::Stream::ClearPointer(&destElemDef->velSamples);
}
if (elemDef->visSamples)
{
AssertSize(Game::FxElemVisStateSample, 48);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(elemDef->visSamples, elemDef->visStateIntervalCount + 1);
Utils::Stream::ClearPointer(&destElemDef->visSamples);
}
// Save_FxElemDefVisuals
{
if (elemDef->elemType == Game::FX_ELEM_TYPE_DECAL)
{
if (elemDef->visuals.markArray)
{
AssertSize(Game::FxElemMarkVisuals, 8);
buffer->align(Utils::Stream::ALIGN_4);
Game::FxElemMarkVisuals* destMarkArray = buffer->dest<Game::FxElemMarkVisuals>();
buffer->saveArray(elemDef->visuals.markArray, elemDef->visualCount);
for (auto j = 0; j < elemDef->visualCount; ++j)
{
if (elemDef->visuals.markArray[j].materials[0])
{
destMarkArray[j].materials[0] = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, elemDef->visuals.markArray[j].materials[0]).material;
}
if (elemDef->visuals.markArray[j].materials[1])
{
destMarkArray[j].materials[1] = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, elemDef->visuals.markArray[j].materials[1]).material;
}
}
Utils::Stream::ClearPointer(&destElemDef->visuals.markArray);
}
}
else if (elemDef->visualCount > 1)
{
if (elemDef->visuals.array)
{
AssertSize(Game::FxElemVisuals, 4);
buffer->align(Utils::Stream::ALIGN_4);
Game::FxElemVisuals* destVisuals = buffer->dest<Game::FxElemVisuals>();
buffer->saveArray(elemDef->visuals.array, elemDef->visualCount);
for (char j = 0; j < elemDef->visualCount; ++j)
{
this->saveFxElemVisuals(&elemDef->visuals.array[j], &destVisuals[j], elemDef->elemType, builder);
}
Utils::Stream::ClearPointer(&destElemDef->visuals.array);
}
}
else
{
this->saveFxElemVisuals(&elemDef->visuals.instance, &destElemDef->visuals.instance, elemDef->elemType, builder);
}
}
if (elemDef->effectOnImpact.handle)
{
buffer->saveString(elemDef->effectOnImpact.handle->name);
Utils::Stream::ClearPointer(&destElemDef->effectOnImpact.handle);
}
if (elemDef->effectOnDeath.handle)
{
buffer->saveString(elemDef->effectOnDeath.handle->name);
Utils::Stream::ClearPointer(&destElemDef->effectOnDeath.handle);
}
if (elemDef->effectEmitted.handle)
{
buffer->saveString(elemDef->effectEmitted.handle->name);
Utils::Stream::ClearPointer(&destElemDef->effectEmitted.handle);
}
// Save_FxElemExtendedDefPtr
{
AssertSize(Game::FxElemExtendedDefPtr, 4);
if (elemDef->elemType == Game::FX_ELEM_TYPE_TRAIL)
{
// Save_FxTrailDef
{
if (elemDef->extended.trailDef)
{
AssertSize(Game::FxTrailDef, 36);
buffer->align(Utils::Stream::ALIGN_4);
Game::FxTrailDef* trailDef = elemDef->extended.trailDef;
Game::FxTrailDef* destTrailDef = buffer->dest<Game::FxTrailDef>();
buffer->save(trailDef);
if (trailDef->verts)
{
AssertSize(Game::FxTrailVertex, 20);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(trailDef->verts, trailDef->vertCount);
Utils::Stream::ClearPointer(&destTrailDef->verts);
}
if (trailDef->inds)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(trailDef->inds, trailDef->indCount);
Utils::Stream::ClearPointer(&destTrailDef->inds);
}
Utils::Stream::ClearPointer(&destElemDef->extended.trailDef);
}
}
}
else if (elemDef->elemType == Game::FX_ELEM_TYPE_SPARK_FOUNTAIN)
{
if (elemDef->extended.sparkFountainDef)
{
AssertSize(Game::FxSparkFountainDef, 52);
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(elemDef->extended.sparkFountainDef);
Utils::Stream::ClearPointer(&destElemDef->extended.sparkFountainDef);
}
}
else
{
if (elemDef->extended.unknownDef)
{
buffer->save(reinterpret_cast<char*>(elemDef->extended.unknownDef));
Utils::Stream::ClearPointer(&destElemDef->extended.unknownDef);
}
}
}
}
Utils::Stream::ClearPointer(&dest->elemDefs);
}
buffer->popBlock();
}
}

View File

@ -1,22 +0,0 @@
#pragma once
namespace Assets
{
class IFxEffectDef : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FX; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private:
void markFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder);
void saveFxElemVisuals(Game::FxElemVisuals* visuals, Game::FxElemVisuals* destVisuals, char elemType, Components::ZoneBuilder::Zone* builder);
void loadEfx(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadFromIW4OF(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,218 +0,0 @@
#include <STDInclude.hpp>
#include "IFxWorld.hpp"
namespace Assets
{
void IFxWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::FxWorld, 116);
Utils::Stream* buffer = builder->getBuffer();
SaveLogEnter("FxWorld");
Game::FxWorld* asset = header.fxWorld;
Game::FxWorld* dest = buffer->dest<Game::FxWorld>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
// saveFxGlassSystem
{
AssertSize(Game::FxGlassSystem, 112);
if (asset->glassSys.defs)
{
AssertSize(Game::FxGlassDef, 36);
buffer->align(Utils::Stream::ALIGN_4);
Game::FxGlassDef* glassDefTable = buffer->dest<Game::FxGlassDef>();
buffer->saveArray(asset->glassSys.defs, asset->glassSys.defCount);
for (unsigned int i = 0; i < asset->glassSys.defCount; ++i)
{
Game::FxGlassDef* glassDef = &asset->glassSys.defs[i];
Game::FxGlassDef* destGlassDef = &glassDefTable[i];
if (glassDef->physPreset)
{
destGlassDef->physPreset = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, glassDef->physPreset).physPreset;
}
if (glassDef->material)
{
destGlassDef->material = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, glassDef->material).material;
}
if (glassDef->materialShattered)
{
destGlassDef->materialShattered = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, glassDef->materialShattered).material;
}
}
Utils::Stream::ClearPointer(&dest->glassSys.defs);
}
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
if (asset->glassSys.piecePlaces)
{
AssertSize(Game::FxGlassPiecePlace, 32);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.piecePlaces, asset->glassSys.pieceLimit);
Utils::Stream::ClearPointer(&dest->glassSys.piecePlaces);
}
if (asset->glassSys.pieceStates)
{
AssertSize(Game::FxGlassPieceState, 32);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.pieceStates, asset->glassSys.pieceLimit);
Utils::Stream::ClearPointer(&dest->glassSys.pieceStates);
}
if (asset->glassSys.pieceDynamics)
{
AssertSize(Game::FxGlassPieceDynamics, 36);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.pieceDynamics, asset->glassSys.pieceLimit);
Utils::Stream::ClearPointer(&dest->glassSys.pieceDynamics);
}
if (asset->glassSys.geoData)
{
AssertSize(Game::FxGlassGeometryData, 4);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.geoData, asset->glassSys.geoDataLimit);
Utils::Stream::ClearPointer(&dest->glassSys.geoData);
}
if (asset->glassSys.isInUse)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.isInUse, asset->glassSys.pieceWordCount);
Utils::Stream::ClearPointer(&dest->glassSys.isInUse);
}
if (asset->glassSys.cellBits)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.cellBits, asset->glassSys.pieceWordCount * asset->glassSys.cellCount);
Utils::Stream::ClearPointer(&dest->glassSys.cellBits);
}
if (asset->glassSys.visData)
{
buffer->align(Utils::Stream::ALIGN_16);
buffer->save(asset->glassSys.visData, 1, (asset->glassSys.pieceLimit + 15) & 0xFFFFFFF0);
Utils::Stream::ClearPointer(&dest->glassSys.visData);
}
if (asset->glassSys.linkOrg)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.linkOrg, asset->glassSys.pieceLimit);
Utils::Stream::ClearPointer(&dest->glassSys.linkOrg);
}
if (asset->glassSys.halfThickness)
{
buffer->align(Utils::Stream::ALIGN_16);
buffer->save(asset->glassSys.halfThickness, 1, ((4 * asset->glassSys.pieceLimit) + 12) & 0xFFFFFFF0);
Utils::Stream::ClearPointer(&dest->glassSys.halfThickness);
}
buffer->popBlock();
if (asset->glassSys.lightingHandles)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->glassSys.lightingHandles, asset->glassSys.initPieceCount);
Utils::Stream::ClearPointer(&dest->glassSys.lightingHandles);
}
if (asset->glassSys.initPieceStates)
{
AssertSize(Game::FxGlassInitPieceState, 52);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.initPieceStates, asset->glassSys.initPieceCount);
Utils::Stream::ClearPointer(&dest->glassSys.initPieceStates);
}
if (asset->glassSys.initGeoData)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->glassSys.initGeoData, asset->glassSys.initGeoDataCount);
Utils::Stream::ClearPointer(&dest->glassSys.initGeoData);
}
}
SaveLogExit();
buffer->popBlock();
}
void IFxWorld::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::FxWorld* asset = header.fxWorld;
if (asset->glassSys.defs)
{
for (unsigned int i = 0; i < asset->glassSys.defCount; ++i)
{
if (asset->glassSys.defs[i].physPreset)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->glassSys.defs[i].physPreset);
}
if (asset->glassSys.defs[i].material)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->glassSys.defs[i].material);
}
if (asset->glassSys.defs[i].materialShattered)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->glassSys.defs[i].materialShattered);
}
}
}
}
void IFxWorld::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
if (!header->fxWorld) loadFromDisk(header, name, builder);
if (!header->fxWorld) generate(header, name, builder);
assert(header->fxWorld);
}
void IFxWorld::loadFromDisk(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder)
{
header->fxWorld = builder->getIW4OfApi()->read<Game::FxWorld>(Game::XAssetType::ASSET_TYPE_FXWORLD, _name);
}
void IFxWorld::generate(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
Game::FxWorld* map = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FXWORLD, name.data()).fxWorld;
if (map) return;
// Generate
map = builder->getAllocator()->allocate<Game::FxWorld>();
map->name = builder->getAllocator()->duplicateString(name);
// No glass for you!
ZeroMemory(&map->glassSys, sizeof(map->glassSys));
map->glassSys.firstFreePiece = 0xFFFF; // That's how rust has it (no glass)
header->fxWorld = map;
}
}

View File

@ -1,16 +0,0 @@
#pragma once
namespace Assets
{
class IFxWorld : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FXWORLD; };
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void generate(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,85 +0,0 @@
#include <STDInclude.hpp>
#include "IGameWorldMp.hpp"
#define IW4X_GAMEWORLD_VERSION 1
namespace Assets
{
void IGameWorldMp::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GameWorldMp, 8);
Utils::Stream* buffer = builder->getBuffer();
Game::GameWorldMp* asset = header.gameWorldMp;
Game::GameWorldMp* dest = buffer->dest<Game::GameWorldMp>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->g_glassData)
{
buffer->align(Utils::Stream::ALIGN_4);
// Save_G_GlassData
{
AssertSize(Game::G_GlassData, 128);
Game::G_GlassData* destGlass = buffer->dest<Game::G_GlassData>();
buffer->save(asset->g_glassData);
if (asset->g_glassData->glassPieces)
{
AssertSize(Game::G_GlassPiece, 12);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->g_glassData->glassPieces, asset->g_glassData->pieceCount);
Utils::Stream::ClearPointer(&destGlass->glassPieces);
}
if (asset->g_glassData->glassNames)
{
AssertSize(Game::G_GlassName, 12);
buffer->align(Utils::Stream::ALIGN_4);
Game::G_GlassName* destGlassNames = buffer->dest<Game::G_GlassName>();
buffer->saveArray(asset->g_glassData->glassNames, asset->g_glassData->glassNameCount);
for (unsigned int i = 0; i < asset->g_glassData->glassNameCount; ++i)
{
Game::G_GlassName* destGlassName = &destGlassNames[i];
Game::G_GlassName* glassName = &asset->g_glassData->glassNames[i];
if (glassName->nameStr)
{
buffer->saveString(glassName->nameStr);
Utils::Stream::ClearPointer(&destGlassName->nameStr);
}
if (glassName->pieceIndices)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(glassName->pieceIndices, glassName->pieceCount);
Utils::Stream::ClearPointer(&destGlassName->pieceIndices);
}
}
Utils::Stream::ClearPointer(&destGlass->glassNames);
}
}
Utils::Stream::ClearPointer(&dest->g_glassData);
}
buffer->popBlock();
}
void IGameWorldMp::load(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder)
{
header->gameWorldMp = builder->getIW4OfApi()->read<Game::GameWorldMp>(Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP, _name);
}
}

View File

@ -1,13 +0,0 @@
#pragma once
namespace Assets
{
class IGameWorldMp : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,348 +0,0 @@
#include <STDInclude.hpp>
#include "IGameWorldSp.hpp"
namespace Assets
{
void IGameWorldSp::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::GameWorldSp* asset = header.gameWorldSp;
if (asset->path.nodes)
{
for (unsigned int i = 0; i < asset->path.nodeCount; ++i)
{
Game::pathnode_t* node = &asset->path.nodes[i];
for (char j = 0; j < 5; ++j)
{
builder->addScriptString((&node->constant.targetname)[j]);
}
}
}
}
void IGameWorldSp::savepathnode_tree_info_t(Game::pathnode_tree_t* nodeTree, Game::pathnode_tree_t* destNodeTree, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::pathnode_tree_info_t, 8);
Utils::Stream* buffer = builder->getBuffer();
if (nodeTree->axis < 0)
{
AssertSize(Game::pathnode_tree_nodes_t, 8);
if (nodeTree->u.s.nodes)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(nodeTree->u.s.nodes, nodeTree->u.s.nodeCount);
Utils::Stream::ClearPointer(&destNodeTree->u.s.nodes);
}
}
else
{
for (int i = 0; i < 2; ++i)
{
Game::pathnode_tree_t** destChildNodeTreePtr = &destNodeTree->u.child[i];
Game::pathnode_tree_t** childNodeTreePtr = &nodeTree->u.child[i];
if (*childNodeTreePtr)
{
if (builder->hasPointer(*childNodeTreePtr))
{
*destChildNodeTreePtr = builder->getPointer(*childNodeTreePtr);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(*childNodeTreePtr);
Game::pathnode_tree_t* destChildNodeTree = buffer->dest<Game::pathnode_tree_t>();
buffer->save(*childNodeTreePtr);
this->savepathnode_tree_info_t(*childNodeTreePtr, destChildNodeTree, builder);
Utils::Stream::ClearPointer(destChildNodeTreePtr);
}
}
}
}
}
void IGameWorldSp::saveVehicleTrackSegment_ptrArray(Game::VehicleTrackSegment** trackSegmentPtrs, int count, Components::ZoneBuilder::Zone* builder)
{
Utils::Stream* buffer = builder->getBuffer();
if (!trackSegmentPtrs) return;
Game::VehicleTrackSegment** destTrackSegmentPtrs = buffer->dest<Game::VehicleTrackSegment*>();
buffer->saveArray(trackSegmentPtrs, count);
for (int i = 0; i < count; ++i)
{
Game::VehicleTrackSegment** destTrackSegmentPtr = &destTrackSegmentPtrs[i];
Game::VehicleTrackSegment** trackSegmentPtr = &trackSegmentPtrs[i];
if (*trackSegmentPtr)
{
if (builder->hasPointer(*trackSegmentPtr))
{
*destTrackSegmentPtr = builder->getPointer(*trackSegmentPtr);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(*trackSegmentPtr);
Game::VehicleTrackSegment* destTrackSegment = buffer->dest<Game::VehicleTrackSegment>();
buffer->save(*trackSegmentPtr);
this->saveVehicleTrackSegment(*trackSegmentPtr, destTrackSegment, builder);
Utils::Stream::ClearPointer(destTrackSegmentPtr);
}
}
}
}
void IGameWorldSp::saveVehicleTrackSegment(Game::VehicleTrackSegment* trackSegment, Game::VehicleTrackSegment* destTrackSegment, Components::ZoneBuilder::Zone* builder)
{
Utils::Stream* buffer = builder->getBuffer();
if (trackSegment->targetName)
{
buffer->saveString(trackSegment->targetName);
Utils::Stream::ClearPointer(&destTrackSegment->targetName);
}
if (trackSegment->sectors)
{
AssertSize(Game::VehicleTrackSector, 60);
buffer->align(Utils::Stream::ALIGN_4);
Game::VehicleTrackSector* destTrackSectors = buffer->dest<Game::VehicleTrackSector>();
buffer->saveArray(trackSegment->sectors, trackSegment->sectorCount);
for (unsigned int i = 0; i < trackSegment->sectorCount; ++i)
{
Game::VehicleTrackSector* destTrackSector = &destTrackSectors[i];
Game::VehicleTrackSector* trackSector = &trackSegment->sectors[i];
if (trackSector->obstacles)
{
AssertSize(Game::VehicleTrackObstacle, 12);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(trackSector->obstacles, trackSector->obstacleCount);
Utils::Stream::ClearPointer(&destTrackSector->obstacles);
}
}
}
if (trackSegment->nextBranches)
{
buffer->align(Utils::Stream::ALIGN_4);
this->saveVehicleTrackSegment_ptrArray(trackSegment->nextBranches, trackSegment->nextBranchesCount, builder);
Utils::Stream::ClearPointer(&destTrackSegment->nextBranches);
}
if (trackSegment->prevBranches)
{
buffer->align(Utils::Stream::ALIGN_4);
this->saveVehicleTrackSegment_ptrArray(trackSegment->prevBranches, trackSegment->prevBranchesCount, builder);
Utils::Stream::ClearPointer(&destTrackSegment->prevBranches);
}
}
void IGameWorldSp::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GameWorldSp, 0x38);
Utils::Stream* buffer = builder->getBuffer();
auto* asset = header.gameWorldSp;
auto* dest = buffer->dest<Game::GameWorldSp>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
// Save_PathData
{
AssertSize(Game::PathData, 40);
if (asset->path.nodes)
{
AssertSize(Game::pathnode_t, 136);
buffer->align(Utils::Stream::ALIGN_4);
Game::pathnode_t* destNodes = buffer->dest<Game::pathnode_t>();
buffer->saveArray(asset->path.nodes, asset->path.nodeCount);
for (unsigned int i = 0; i < asset->path.nodeCount; ++i)
{
Game::pathnode_t* destNode = &destNodes[i];
Game::pathnode_t* node = &asset->path.nodes[i];
AssertSize(Game::pathnode_constant_t, 64);
for (char j = 0; j < 5; ++j)
{
builder->mapScriptString((&node->constant.targetname)[j]);
}
if (node->constant.Links)
{
AssertSize(Game::pathlink_s, 12);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(node->constant.Links, node->constant.totalLinkCount);
Utils::Stream::ClearPointer(&destNode->constant.Links);
}
}
Utils::Stream::ClearPointer(&dest->path.nodes);
}
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
if (asset->path.basenodes)
{
AssertSize(Game::pathbasenode_t, 16);
buffer->align(Utils::Stream::ALIGN_16);
buffer->saveArray(asset->path.basenodes, asset->path.nodeCount);
Utils::Stream::ClearPointer(&dest->path.basenodes);
}
buffer->popBlock();
if (asset->path.chainNodeForNode)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->path.chainNodeForNode, asset->path.nodeCount);
Utils::Stream::ClearPointer(&dest->path.chainNodeForNode);
}
if (asset->path.nodeForChainNode)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->path.nodeForChainNode, asset->path.nodeCount);
Utils::Stream::ClearPointer(&dest->path.nodeForChainNode);
}
if (asset->path.pathVis)
{
buffer->saveArray(asset->path.pathVis, asset->path.visBytes);
Utils::Stream::ClearPointer(&dest->path.pathVis);
}
if (asset->path.nodeTree)
{
AssertSize(Game::pathnode_tree_t, 16);
buffer->align(Utils::Stream::ALIGN_4);
Game::pathnode_tree_t* destNodeTrees = buffer->dest<Game::pathnode_tree_t>();
buffer->saveArray(asset->path.nodeTree, asset->path.nodeTreeCount);
for (int i = 0; i < asset->path.nodeTreeCount; ++i)
{
Game::pathnode_tree_t* destNodeTree = &destNodeTrees[i];
Game::pathnode_tree_t* nodeTree = &asset->path.nodeTree[i];
this->savepathnode_tree_info_t(nodeTree, destNodeTree, builder);
}
Utils::Stream::ClearPointer(&dest->path.nodeTree);
}
}
// Save_VehicleTrack
{
AssertSize(Game::VehicleTrack, 8);
if (asset->vehicleTrack.segments)
{
if (builder->hasPointer(asset->vehicleTrack.segments))
{
dest->vehicleTrack.segments = builder->getPointer(asset->vehicleTrack.segments);
}
else
{
AssertSize(Game::VehicleTrackSegment, 44);
buffer->align(Utils::Stream::ALIGN_4);
Game::VehicleTrackSegment* destTrackSegments = buffer->dest<Game::VehicleTrackSegment>();
for (unsigned int i = 0; i < asset->vehicleTrack.segmentCount; ++i)
{
builder->storePointer(&asset->vehicleTrack.segments[i]);
buffer->save(&asset->vehicleTrack.segments[i]);
}
for (unsigned int i = 0; i < asset->vehicleTrack.segmentCount; ++i)
{
Game::VehicleTrackSegment* destTrackSegment = &destTrackSegments[i];
Game::VehicleTrackSegment* trackSegment = &asset->vehicleTrack.segments[i];
this->saveVehicleTrackSegment(trackSegment, destTrackSegment, builder);
}
Utils::Stream::ClearPointer(&dest->vehicleTrack.segments);
}
}
}
if (asset->g_glassData)
{
// Save_G_GlassData
{
AssertSize(Game::G_GlassData, 128);
buffer->align(Utils::Stream::ALIGN_4);
Game::G_GlassData* destGlass = buffer->dest<Game::G_GlassData>();
buffer->save(asset->g_glassData);
if (asset->g_glassData->glassPieces)
{
AssertSize(Game::G_GlassPiece, 12);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->g_glassData->glassPieces, asset->g_glassData->pieceCount);
Utils::Stream::ClearPointer(&destGlass->glassPieces);
}
if (asset->g_glassData->glassNames)
{
AssertSize(Game::G_GlassName, 12);
buffer->align(Utils::Stream::ALIGN_4);
Game::G_GlassName* destGlassNames = buffer->dest<Game::G_GlassName>();
buffer->saveArray(asset->g_glassData->glassNames, asset->g_glassData->glassNameCount);
for (unsigned int i = 0; i < asset->g_glassData->glassNameCount; ++i)
{
Game::G_GlassName* destGlassName = &destGlassNames[i];
Game::G_GlassName* glassName = &asset->g_glassData->glassNames[i];
if (glassName->nameStr)
{
buffer->saveString(glassName->nameStr);
Utils::Stream::ClearPointer(&destGlassName->nameStr);
}
if (glassName->pieceIndices)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(glassName->pieceIndices, glassName->pieceCount);
Utils::Stream::ClearPointer(&destGlassName->pieceIndices);
}
}
Utils::Stream::ClearPointer(&destGlass->glassNames);
}
}
Utils::Stream::ClearPointer(&dest->g_glassData);
}
buffer->popBlock();
}
}

View File

@ -1,18 +0,0 @@
#pragma once
namespace Assets
{
class IGameWorldSp : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private:
void savepathnode_tree_info_t(Game::pathnode_tree_t* nodeTree, Game::pathnode_tree_t* destNodeTree, Components::ZoneBuilder::Zone* builder);
void saveVehicleTrackSegment(Game::VehicleTrackSegment* trackSegment, Game::VehicleTrackSegment* destTrackSegment, Components::ZoneBuilder::Zone* builder);
void saveVehicleTrackSegment_ptrArray(Game::VehicleTrackSegment** trackSegmentPtrs, int count, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,50 +0,0 @@
#include <STDInclude.hpp>
#include "IGfxImage.hpp"
namespace Assets
{
void IGfxImage::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->image = builder->getIW4OfApi()->read<Game::GfxImage>(Game::XAssetType::ASSET_TYPE_IMAGE, name);
}
void IGfxImage::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GfxImage, 32);
Utils::Stream* buffer = builder->getBuffer();
Game::GfxImage* asset = header.image;
Game::GfxImage* dest = buffer->dest<Game::GfxImage>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
buffer->pushBlock(Game::XFILE_BLOCK_TEMP);
if (asset->texture.loadDef)
{
buffer->align(Utils::Stream::ALIGN_4);
Game::GfxImageLoadDef* destTexture = buffer->dest<Game::GfxImageLoadDef>();
buffer->save(asset->texture.loadDef, 16, 1);
builder->incrementExternalSize(asset->texture.loadDef->resourceSize);
if (destTexture->resourceSize > 0)
{
buffer->save(asset->texture.loadDef->data, asset->texture.loadDef->resourceSize);
}
Utils::Stream::ClearPointer(&dest->texture.loadDef);
}
buffer->popBlock();
buffer->popBlock();
}
}

View File

@ -1,13 +0,0 @@
#pragma once
namespace Assets
{
class IGfxImage : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_IMAGE; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,46 +0,0 @@
#include <STDInclude.hpp>
#include "IGfxLightDef.hpp"
namespace Assets
{
void IGfxLightDef::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->lightDef = builder->getIW4OfApi()->read<Game::GfxLightDef>(Game::XAssetType::ASSET_TYPE_LIGHT_DEF, name);
}
void IGfxLightDef::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::GfxLightDef* asset = header.lightDef;
if (asset->attenuation.image)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->attenuation.image);
}
}
void IGfxLightDef::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GfxLightDef, 16);
AssertSize(Game::GfxLightImage, 8);
Utils::Stream* buffer = builder->getBuffer();
Game::GfxLightDef* asset = header.lightDef;
Game::GfxLightDef* dest = buffer->dest<Game::GfxLightDef>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->attenuation.image)
{
dest->attenuation.image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->attenuation.image).image;
}
buffer->popBlock();
}
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace Assets
{
class IGfxLightDef : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LIGHT_DEF; }
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,945 +0,0 @@
#include <STDInclude.hpp>
#include "IGfxWorld.hpp"
namespace Assets
{
void IGfxWorld::load(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder)
{
header->gfxWorld = builder->getIW4OfApi()->read<Game::GfxWorld>(Game::XAssetType::ASSET_TYPE_GFXWORLD, _name);
}
void IGfxWorld::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
auto* asset = header.gfxWorld;
if (asset->draw.reflectionProbes)
{
for (unsigned int i = 0; i < asset->draw.reflectionProbeCount; ++i)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->draw.reflectionProbes[i]);
}
}
if (asset->draw.lightmaps)
{
for (auto i = 0; i < asset->draw.lightmapCount; ++i)
{
if (asset->draw.lightmaps[i].primary)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->draw.lightmaps[i].primary);
}
if (asset->draw.lightmaps[i].secondary)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->draw.lightmaps[i].secondary);
}
}
}
if (asset->draw.lightmapOverridePrimary)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->draw.lightmapOverridePrimary);
}
if (asset->draw.lightmapOverrideSecondary)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->draw.lightmapOverrideSecondary);
}
if (asset->sun.spriteMaterial)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->sun.spriteMaterial);
}
if (asset->sun.flareMaterial)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->sun.flareMaterial);
}
if (asset->skies)
{
for (int i = 0; i < asset->skyCount; ++i)
{
if (asset->skies[i].skyImage)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->skies[i].skyImage);
}
}
}
if (asset->materialMemory)
{
for (int i = 0; i < asset->materialMemoryCount; ++i)
{
if (asset->materialMemory[i].material)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materialMemory[i].material);
}
}
}
if (asset->outdoorImage)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->outdoorImage);
}
if (asset->dpvs.surfaces)
{
for (unsigned int i = 0; i < asset->surfaceCount; ++i)
{
if (asset->dpvs.surfaces[i].material)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->dpvs.surfaces[i].material);
}
}
}
if (asset->dpvs.smodelDrawInsts)
{
for (unsigned int i = 0; i < asset->dpvs.smodelCount; ++i)
{
if (asset->dpvs.smodelDrawInsts[i].model)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->dpvs.smodelDrawInsts[i].model);
}
}
}
}
void IGfxWorld::saveGfxWorldDpvsPlanes(Game::GfxWorld* world, Game::GfxWorldDpvsPlanes* asset, Game::GfxWorldDpvsPlanes* dest, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GfxWorldDpvsPlanes, 16);
Utils::Stream* buffer = builder->getBuffer();
SaveLogEnter("GfxWorldDpvsPlanes");
if (asset->planes)
{
if (builder->hasPointer(asset->planes))
{
dest->planes = builder->getPointer(asset->planes);
}
else
{
AssertSize(Game::cplane_s, 20);
buffer->align(Utils::Stream::ALIGN_4);
for (int i = 0; i < world->planeCount; ++i)
{
builder->storePointer(&asset->planes[i]);
buffer->save(&asset->planes[i]);
}
Utils::Stream::ClearPointer(&dest->planes);
}
}
if (asset->nodes)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->nodes, world->nodeCount);
Utils::Stream::ClearPointer(&dest->nodes);
}
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
if (asset->sceneEntCellBits)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->sceneEntCellBits, 1, asset->cellCount << 11);
Utils::Stream::ClearPointer(&dest->sceneEntCellBits);
}
buffer->popBlock();
SaveLogExit();
}
void IGfxWorld::saveGfxWorldDraw(Game::GfxWorldDraw* asset, Game::GfxWorldDraw* dest, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GfxWorldDraw, 72);
SaveLogEnter("GfxWorldDraw");
Utils::Stream* buffer = builder->getBuffer();
if (asset->reflectionProbes)
{
buffer->align(Utils::Stream::ALIGN_4);
auto** imageDest = buffer->dest<Game::GfxImage*>();
buffer->saveArray(asset->reflectionProbes, asset->reflectionProbeCount);
for (unsigned int i = 0; i < asset->reflectionProbeCount; ++i)
{
if (asset->reflectionProbes[i])
{
imageDest[i] = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->reflectionProbes[i]).image;
}
}
Utils::Stream::ClearPointer(&dest->reflectionProbes);
}
if (asset->reflectionProbeOrigins)
{
AssertSize(Game::GfxReflectionProbe, 12);
SaveLogEnter("GfxReflectionProbe");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->reflectionProbeOrigins, asset->reflectionProbeCount);
Utils::Stream::ClearPointer(&dest->reflectionProbeOrigins);
SaveLogExit();
}
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
if (asset->reflectionProbeTextures)
{
AssertSize(Game::GfxTexture, 4);
SaveLogEnter("GfxRawTexture");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->reflectionProbeTextures, asset->reflectionProbeCount);
Utils::Stream::ClearPointer(&dest->reflectionProbeTextures);
SaveLogExit();
}
buffer->popBlock();
if (asset->lightmaps)
{
AssertSize(Game::GfxLightmapArray, 8);
SaveLogEnter("GfxLightmapArray");
buffer->align(Utils::Stream::ALIGN_4);
auto* lightmapArrayDestTable = buffer->dest<Game::GfxLightmapArray>();
buffer->saveArray(asset->lightmaps, asset->lightmapCount);
for (int i = 0; i < asset->lightmapCount; ++i)
{
auto* lightmapArrayDest = &lightmapArrayDestTable[i];
auto* lightmapArray = &asset->lightmaps[i];
if (lightmapArray->primary)
{
lightmapArrayDest->primary = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, lightmapArray->primary).image;
}
if (lightmapArray->secondary)
{
lightmapArrayDest->secondary = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, lightmapArray->secondary).image;
}
}
Utils::Stream::ClearPointer(&dest->lightmaps);
SaveLogExit();
}
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
if (asset->lightmapPrimaryTextures)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->lightmapPrimaryTextures, asset->lightmapCount);
Utils::Stream::ClearPointer(&dest->lightmapPrimaryTextures);
}
if (asset->lightmapSecondaryTextures)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->lightmapSecondaryTextures, asset->lightmapCount);
Utils::Stream::ClearPointer(&dest->lightmapSecondaryTextures);
}
buffer->popBlock();
if (asset->lightmapOverridePrimary)
{
dest->lightmapOverridePrimary = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->lightmapOverridePrimary).image;
}
if (asset->lightmapOverrideSecondary)
{
dest->lightmapOverrideSecondary = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->lightmapOverrideSecondary).image;
}
// saveGfxWorldVertexData
{
if (asset->vd.vertices)
{
AssertSize(Game::GfxWorldVertex, 44);
SaveLogEnter("GfxWorldVertex");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->vd.vertices, asset->vertexCount);
Utils::Stream::ClearPointer(&dest->vd.vertices);
SaveLogExit();
}
}
// saveGfxWorldVertexLayerData
{
if (asset->vld.data)
{
// no align for char
buffer->saveArray(asset->vld.data, asset->vertexLayerDataSize);
Utils::Stream::ClearPointer(&dest->vld.data);
}
}
if (asset->indices)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->indices, asset->indexCount);
Utils::Stream::ClearPointer(&dest->indices);
}
SaveLogExit();
}
void IGfxWorld::saveGfxLightGrid(Game::GfxLightGrid* asset, Game::GfxLightGrid* dest, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GfxLightGrid, 56);
Utils::Stream* buffer = builder->getBuffer();
SaveLogEnter("GfxLightGrid");
if (asset->rowDataStart)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->rowDataStart, (asset->maxs[asset->rowAxis] - asset->mins[asset->rowAxis]) + 1);
Utils::Stream::ClearPointer(&dest->rowDataStart);
}
if (asset->rawRowData)
{
// no align for char
buffer->saveArray(asset->rawRowData, asset->rawRowDataSize);
Utils::Stream::ClearPointer(&dest->rawRowData);
}
if (asset->entries)
{
AssertSize(Game::GfxLightGridEntry, 4);
SaveLogEnter("GfxLightGridEntry");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->entries, asset->entryCount);
Utils::Stream::ClearPointer(&dest->entries);
SaveLogExit();
}
if (asset->colors)
{
AssertSize(Game::GfxLightGridColors, 168);
SaveLogEnter("GfxLightGridColors");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->colors, asset->colorCount);
Utils::Stream::ClearPointer(&dest->colors);
SaveLogExit();
}
SaveLogExit();
}
void IGfxWorld::savesunflare_t(Game::sunflare_t* asset, Game::sunflare_t* dest, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::sunflare_t, 96);
SaveLogEnter("sunflare_t");
if (asset->spriteMaterial)
{
dest->spriteMaterial = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->spriteMaterial).material;
}
if (asset->flareMaterial)
{
dest->flareMaterial = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->flareMaterial).material;
}
SaveLogExit();
}
void IGfxWorld::saveGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Game::GfxWorldDpvsStatic* dest, int /*planeCount*/, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GfxWorldDpvsStatic, 108);
Utils::Stream* buffer = builder->getBuffer();
SaveLogEnter("GfxWorldDpvsStatic");
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
for (int i = 0; i < 3; ++i)
{
if (asset->smodelVisData[i])
{
buffer->saveArray(asset->smodelVisData[i], asset->smodelCount);
Utils::Stream::ClearPointer(&dest->smodelVisData[i]);
}
}
for (int i = 0; i < 3; ++i)
{
if (asset->surfaceVisData[i])
{
buffer->saveArray(asset->surfaceVisData[i], asset->staticSurfaceCount);
Utils::Stream::ClearPointer(&dest->surfaceVisData[i]);
}
}
buffer->popBlock();
if (asset->sortedSurfIndex)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->sortedSurfIndex, asset->staticSurfaceCount + asset->staticSurfaceCountNoDecal);
Utils::Stream::ClearPointer(&dest->sortedSurfIndex);
}
if (asset->smodelInsts)
{
AssertSize(Game::GfxStaticModelInst, 36);
SaveLogEnter("GfxStaticModelInst");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->smodelInsts, asset->smodelCount);
Utils::Stream::ClearPointer(&dest->smodelInsts);
SaveLogExit();
}
if (asset->surfaces)
{
AssertSize(Game::GfxSurface, 24);
SaveLogEnter("GfxSurface");
buffer->align(Utils::Stream::ALIGN_4);
auto* destSurfaceTable = buffer->dest<Game::GfxSurface>();
buffer->saveArray(asset->surfaces, world->surfaceCount);
for (unsigned int i = 0; i < world->surfaceCount; ++i)
{
auto* surface = &asset->surfaces[i];
auto* destSurface = &destSurfaceTable[i];
if (surface->material)
{
destSurface->material = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, surface->material).material;
}
}
Utils::Stream::ClearPointer(&dest->surfaces);
SaveLogExit();
}
if (asset->surfacesBounds)
{
AssertSize(Game::GfxSurfaceBounds, 24);
SaveLogEnter("GfxSurfaceBounds");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->surfacesBounds, world->surfaceCount);
Utils::Stream::ClearPointer(&dest->surfacesBounds);
SaveLogExit();
}
if (asset->smodelDrawInsts)
{
AssertSize(Game::GfxStaticModelDrawInst, 76);
SaveLogEnter("GfxStaticModelDrawInst");
buffer->align(Utils::Stream::ALIGN_4);
auto* destModelTable = buffer->dest<Game::GfxStaticModelDrawInst>();
buffer->saveArray(asset->smodelDrawInsts, asset->smodelCount);
for (unsigned int i = 0; i < asset->smodelCount; ++i)
{
auto* model = &asset->smodelDrawInsts[i];
auto* destModel = &destModelTable[i];
if (model->model)
{
destModel->model = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, model->model).model;
}
}
Utils::Stream::ClearPointer(&dest->smodelDrawInsts);
SaveLogExit();
}
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
if (asset->surfaceMaterials)
{
AssertSize(Game::GfxDrawSurf, 8);
SaveLogEnter("GfxDrawSurf");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->surfaceMaterials, world->surfaceCount);
Utils::Stream::ClearPointer(&dest->surfaceMaterials);
SaveLogExit();
}
if (asset->surfaceCastsSunShadow)
{
AssertSize(Game::GfxDrawSurf, 8);
SaveLogEnter("GfxDrawSurf");
buffer->align(Utils::Stream::ALIGN_128);
buffer->save(asset->surfaceCastsSunShadow, 4, asset->surfaceVisDataCount);
Utils::Stream::ClearPointer(&dest->surfaceCastsSunShadow);
SaveLogExit();
}
buffer->popBlock();
SaveLogExit();
}
void IGfxWorld::saveGfxWorldDpvsDynamic(Game::GfxWorldDpvsDynamic* asset, Game::GfxWorldDpvsDynamic* dest, int cellCount, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GfxWorldDpvsDynamic, 48);
Utils::Stream* buffer = builder->getBuffer();
SaveLogEnter("GfxWorldDpvsDynamic");
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
if (asset->dynEntCellBits[0])
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->dynEntCellBits[0], 4, asset->dynEntClientWordCount[0] * cellCount);
Utils::Stream::ClearPointer(&dest->dynEntCellBits[0]);
}
if (asset->dynEntCellBits[1])
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->dynEntCellBits[1], 4, asset->dynEntClientWordCount[1] * cellCount);
Utils::Stream::ClearPointer(&dest->dynEntCellBits[1]);
}
// this covers [0][0], [1][0], [0][1], [1][1], [0][2], [1][2]
for (char i = 0; i < 3; ++i)
{
for (char j = 0; j < 2; ++j)
{
if (asset->dynEntVisData[j][i])
{
buffer->align(Utils::Stream::ALIGN_16);
buffer->save(asset->dynEntVisData[j][i], 32, asset->dynEntClientWordCount[j]);
Utils::Stream::ClearPointer(&dest->dynEntVisData[j][i]);
}
}
}
buffer->popBlock();
SaveLogExit();
}
void IGfxWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::GfxWorld, 628);
Utils::Stream* buffer = builder->getBuffer();
SaveLogEnter("GfxWorld");
auto* asset = header.gfxWorld;
auto* dest = buffer->dest<Game::GfxWorld>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->baseName)
{
buffer->saveString(asset->baseName);
Utils::Stream::ClearPointer(&dest->baseName);
}
//buffer->setPointerAssertion(true);
if (asset->skies)
{
AssertSize(Game::GfxSky, 16);
SaveLogEnter("GfxSky");
buffer->align(Utils::Stream::ALIGN_4);
auto* destSkyTable = buffer->dest<Game::GfxSky>();
buffer->saveArray(asset->skies, asset->skyCount);
for (int i = 0; i < asset->skyCount; ++i)
{
auto* destSky = &destSkyTable[i];
auto* sky = &asset->skies[i];
if (sky->skyStartSurfs)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(sky->skyStartSurfs, sky->skySurfCount);
Utils::Stream::ClearPointer(&destSky->skyStartSurfs);
}
if (sky->skyImage)
{
destSky->skyImage = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, sky->skyImage).image;
}
}
Utils::Stream::ClearPointer(&dest->skies);
SaveLogExit();
}
this->saveGfxWorldDpvsPlanes(asset, &asset->dpvsPlanes, &dest->dpvsPlanes, builder);
int cellCount = asset->dpvsPlanes.cellCount;
if (asset->aabbTreeCounts)
{
AssertSize(Game::GfxCellTreeCount, 4);
SaveLogEnter("GfxCellTreeCount");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->aabbTreeCounts, cellCount);
Utils::Stream::ClearPointer(&dest->aabbTreeCounts);
SaveLogExit();
}
if (asset->aabbTrees)
{
AssertSize(Game::GfxCellTree, 4);
SaveLogEnter("GfxCellTree");
buffer->align(Utils::Stream::ALIGN_128);
auto* destCellTreeTable = buffer->dest<Game::GfxCellTree>();
buffer->saveArray(asset->aabbTrees, cellCount);
for (int i = 0; i < cellCount; ++i)
{
auto* destCellTree = &destCellTreeTable[i];
auto* cellTree = &asset->aabbTrees[i];
if (cellTree->aabbTree)
{
AssertSize(Game::GfxAabbTree, 44);
SaveLogEnter("GfxAabbTree");
buffer->align(Utils::Stream::ALIGN_4);
auto* destAabbTreeTable = buffer->dest<Game::GfxAabbTree>();
buffer->saveArray(cellTree->aabbTree, asset->aabbTreeCounts[i].aabbTreeCount);
// ok this one is based on some assumptions because the actual count is this
// *(int *)((char *)&varGfxWorld->aabbTreeCounts->aabbTreeCount + (((char *)varGfxCellTree - (char *)varGfxWorld->aabbTrees) & 0xFFFFFFFC))
// which makes no sense
// what DOES make sense is using the count from the structure
for (int j = 0; j < asset->aabbTreeCounts[i].aabbTreeCount; ++j)
{
auto* destAabbTree = &destAabbTreeTable[j];
auto* aabbTree = &cellTree->aabbTree[j];
if (aabbTree->smodelIndexes)
{
if (builder->hasPointer(aabbTree->smodelIndexes))
{
destAabbTree->smodelIndexes = builder->getPointer(aabbTree->smodelIndexes);
}
else
{
buffer->align(Utils::Stream::ALIGN_2);
for (unsigned short k = 0; k < aabbTree->smodelIndexCount; ++k)
{
builder->storePointer(&aabbTree->smodelIndexes[k]);
buffer->save(&aabbTree->smodelIndexes[k]);
}
Utils::Stream::ClearPointer(&destAabbTree->smodelIndexes);
}
}
}
Utils::Stream::ClearPointer(&destCellTree->aabbTree);
SaveLogExit();
}
}
Utils::Stream::ClearPointer(&dest->aabbTrees);
SaveLogExit();
}
if (asset->cells)
{
AssertSize(Game::GfxCell, 40);
SaveLogEnter("GfxCell");
buffer->align(Utils::Stream::ALIGN_4);
auto* destCellTable = buffer->dest<Game::GfxCell>();
buffer->saveArray(asset->cells, cellCount);
for (int i = 0; i < cellCount; ++i)
{
auto* destCell = &destCellTable[i];
auto* cell = &asset->cells[i];
if (cell->portals)
{
AssertSize(Game::GfxPortal, 60);
SaveLogEnter("GfxPortal");
buffer->align(Utils::Stream::ALIGN_4);
auto* destPortalTable = buffer->dest<Game::GfxPortal>();
buffer->saveArray(cell->portals, cell->portalCount);
for (int j = 0; j < cell->portalCount; ++j)
{
auto* destPortal = &destPortalTable[j];
auto* portal = &cell->portals[j];
if (portal->vertices)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(portal->vertices, portal->vertexCount);
Utils::Stream::ClearPointer(&destPortal->vertices);
}
}
Utils::Stream::ClearPointer(&destCell->portals);
SaveLogExit();
}
if (cell->reflectionProbes)
{
// no align for char
buffer->saveArray(cell->reflectionProbes, cell->reflectionProbeCount);
Utils::Stream::ClearPointer(&destCell->reflectionProbes);
}
}
Utils::Stream::ClearPointer(&dest->cells);
SaveLogExit();
}
this->saveGfxWorldDraw(&asset->draw, &dest->draw, builder);
this->saveGfxLightGrid(&asset->lightGrid, &dest->lightGrid, builder);
if (asset->models)
{
AssertSize(Game::GfxBrushModel, 60);
SaveLogEnter("GfxBrushModel");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->models, asset->modelCount);
Utils::Stream::ClearPointer(&dest->models);
SaveLogExit();
}
if (asset->materialMemory)
{
AssertSize(Game::MaterialMemory, 8);
SaveLogEnter("MaterialMemory");
buffer->align(Utils::Stream::ALIGN_4);
auto* destMaterialMemoryTable = buffer->dest<Game::MaterialMemory>();
buffer->saveArray(asset->materialMemory, asset->materialMemoryCount);
for (int i = 0; i < asset->materialMemoryCount; ++i)
{
auto* destMaterialMemory = &destMaterialMemoryTable[i];
auto* materialMemory = &asset->materialMemory[i];
if (materialMemory->material)
{
destMaterialMemory->material = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, materialMemory->material).material;
}
}
Utils::Stream::ClearPointer(&dest->materialMemory);
SaveLogExit();
}
this->savesunflare_t(&asset->sun, &dest->sun, builder);
if (asset->outdoorImage)
{
dest->outdoorImage = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->outdoorImage).image;
}
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
if (asset->cellCasterBits)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->cellCasterBits, 4, cellCount * ((cellCount + 31) >> 5));
Utils::Stream::ClearPointer(&dest->cellCasterBits);
}
if (asset->cellHasSunLitSurfsBits)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->cellHasSunLitSurfsBits, 4, ((cellCount + 31) >> 5));
Utils::Stream::ClearPointer(&dest->cellHasSunLitSurfsBits);
}
if (asset->sceneDynModel)
{
AssertSize(Game::GfxSceneDynModel, 6);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->sceneDynModel, asset->dpvsDyn.dynEntClientCount[0]);
Utils::Stream::ClearPointer(&dest->sceneDynModel);
}
if (asset->sceneDynBrush)
{
AssertSize(Game::GfxSceneDynBrush, 4);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->sceneDynBrush, asset->dpvsDyn.dynEntClientCount[1]);
Utils::Stream::ClearPointer(&dest->sceneDynBrush);
}
if (asset->primaryLightEntityShadowVis)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->primaryLightEntityShadowVis, 1, (asset->primaryLightCount + 0x1FFFF - asset->lastSunPrimaryLightIndex) << 15);
Utils::Stream::ClearPointer(&dest->primaryLightEntityShadowVis);
}
if (asset->primaryLightDynEntShadowVis[0])
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->primaryLightDynEntShadowVis[0], asset->dpvsDyn.dynEntClientCount[0] * (asset->primaryLightCount - 1 - asset->lastSunPrimaryLightIndex));
Utils::Stream::ClearPointer(&dest->primaryLightDynEntShadowVis[0]);
}
if (asset->primaryLightDynEntShadowVis[1])
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->primaryLightDynEntShadowVis[1], asset->dpvsDyn.dynEntClientCount[1] * (asset->primaryLightCount - 1 - asset->lastSunPrimaryLightIndex));
Utils::Stream::ClearPointer(&dest->primaryLightDynEntShadowVis[1]);
}
if (asset->nonSunPrimaryLightForModelDynEnt)
{
// no align cause char
buffer->saveArray(asset->nonSunPrimaryLightForModelDynEnt, asset->dpvsDyn.dynEntClientCount[0]);
Utils::Stream::ClearPointer(&dest->nonSunPrimaryLightForModelDynEnt);
}
buffer->popBlock();
if (asset->shadowGeom)
{
AssertSize(Game::GfxShadowGeometry, 12);
SaveLogEnter("GfxShadowGeometry");
buffer->align(Utils::Stream::ALIGN_4);
auto* destShadowGeometryTable = buffer->dest<Game::GfxShadowGeometry>();
buffer->saveArray(asset->shadowGeom, asset->primaryLightCount);
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
{
auto* destShadowGeometry = &destShadowGeometryTable[i];
auto* shadowGeometry = &asset->shadowGeom[i];
if (shadowGeometry->sortedSurfIndex)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(shadowGeometry->sortedSurfIndex, shadowGeometry->surfaceCount);
Utils::Stream::ClearPointer(&destShadowGeometry->sortedSurfIndex);
}
if (shadowGeometry->smodelIndex)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(shadowGeometry->smodelIndex, shadowGeometry->smodelCount);
Utils::Stream::ClearPointer(&destShadowGeometry->smodelIndex);
}
}
Utils::Stream::ClearPointer(&dest->shadowGeom);
SaveLogExit();
}
if (asset->lightRegion)
{
AssertSize(Game::GfxLightRegion, 8);
SaveLogEnter("GfxLightRegion");
buffer->align(Utils::Stream::ALIGN_4);
auto* destLightRegionTable = buffer->dest<Game::GfxLightRegion>();
buffer->saveArray(asset->lightRegion, asset->primaryLightCount);
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
{
auto* destLightRegion = &destLightRegionTable[i];
auto* lightRegion = &asset->lightRegion[i];
if (lightRegion->hulls)
{
AssertSize(Game::GfxLightRegionHull, 80);
SaveLogEnter("GfxLightRegionHull");
buffer->align(Utils::Stream::ALIGN_4);
auto* destLightRegionHullTable = buffer->dest<Game::GfxLightRegionHull>();
buffer->saveArray(lightRegion->hulls, lightRegion->hullCount);
for (unsigned int j = 0; j < lightRegion->hullCount; ++j)
{
auto* destLightRegionHull = &destLightRegionHullTable[j];
auto* lightRegionHull = &lightRegion->hulls[j];
if (lightRegionHull->axis)
{
AssertSize(Game::GfxLightRegionAxis, 20);
SaveLogEnter("GfxLightRegionAxis");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(lightRegionHull->axis, lightRegionHull->axisCount);
Utils::Stream::ClearPointer(&destLightRegionHull->axis);
SaveLogExit();
}
}
Utils::Stream::ClearPointer(&destLightRegion->hulls);
SaveLogExit();
}
}
Utils::Stream::ClearPointer(&dest->lightRegion);
SaveLogExit();
}
this->saveGfxWorldDpvsStatic(asset, &asset->dpvs, &dest->dpvs, asset->dpvsPlanes.cellCount, builder);
this->saveGfxWorldDpvsDynamic(&asset->dpvsDyn, &dest->dpvsDyn, asset->dpvsPlanes.cellCount, builder);
if (asset->heroOnlyLights)
{
AssertSize(Game::GfxHeroOnlyLight, 56);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->heroOnlyLights, asset->heroOnlyLightCount);
Utils::Stream::ClearPointer(&dest->heroOnlyLights);
}
buffer->popBlock();
SaveLogExit();
}
}

View File

@ -1,22 +0,0 @@
#pragma once
namespace Assets
{
class IGfxWorld : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GFXWORLD; };
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private:
void saveGfxWorldDpvsPlanes(Game::GfxWorld* world, Game::GfxWorldDpvsPlanes* asset, Game::GfxWorldDpvsPlanes* dest, Components::ZoneBuilder::Zone* builder);
void saveGfxWorldDraw(Game::GfxWorldDraw* asset, Game::GfxWorldDraw* dest, Components::ZoneBuilder::Zone* builder);
void saveGfxLightGrid(Game::GfxLightGrid* asset, Game::GfxLightGrid* dest, Components::ZoneBuilder::Zone* builder);
void savesunflare_t(Game::sunflare_t* asset, Game::sunflare_t* dest, Components::ZoneBuilder::Zone* builder);
void saveGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Game::GfxWorldDpvsStatic* dest, int planeCount, Components::ZoneBuilder::Zone* builder);
void saveGfxWorldDpvsDynamic(Game::GfxWorldDpvsDynamic* asset, Game::GfxWorldDpvsDynamic* dest, int cellCount, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,42 +0,0 @@
#include <STDInclude.hpp>
#include "ILoadedSound.hpp"
namespace Assets
{
void ILoadedSound::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->loadSnd = builder->getIW4OfApi()->read<Game::LoadedSound>(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, name);
}
void ILoadedSound::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::LoadedSound, 44);
auto* buffer = builder->getBuffer();
auto* asset = header.loadSnd;
auto* dest = buffer->dest<Game::LoadedSound>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
{
buffer->pushBlock(Game::XFILE_BLOCK_TEMP);
if (asset->sound.data)
{
buffer->saveArray(asset->sound.data, asset->sound.info.data_len);
Utils::Stream::ClearPointer(&dest->sound.data);
}
buffer->popBlock();
}
buffer->popBlock();
}
}

View File

@ -1,13 +0,0 @@
#pragma once
namespace Assets
{
class ILoadedSound : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LOADED_SOUND; };
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,131 +0,0 @@
#include <STDInclude.hpp>
#include "ILocalizeEntry.hpp"
namespace Assets
{
void ILocalizeEntry::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
const auto path = "localizedstrings/" + name;
Components::FileSystem::File rawFile(path);
if (!rawFile.exists())
{
return;
}
Components::Logger::Debug("Parsing localized string \"{}\"...", path);
auto* asset = builder->getAllocator()->allocate<Game::LocalizeEntry>();
if (!asset)
{
return;
}
asset->name = builder->getAllocator()->duplicateString(name);
asset->value = builder->getAllocator()->duplicateString(rawFile.getBuffer());
header->localize = asset;
}
void ILocalizeEntry::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::LocalizeEntry, 8);
auto* buffer = builder->getBuffer();
auto* asset = header.localize;
auto* dest = buffer->dest<Game::LocalizeEntry>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->value)
{
buffer->saveString(asset->value);
Utils::Stream::ClearPointer(&dest->value);
}
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
buffer->popBlock();
}
void ILocalizeEntry::ParseLocalizedStringsFile(Components::ZoneBuilder::Zone* builder, const std::string& name, const std::string& filename)
{
std::vector<Game::LocalizeEntry*> assets;
const auto _0 = gsl::finally([]
{
Components::Localization::ParseOutput(nullptr);
Components::Localization::PrefixOverride = {};
});
Components::Localization::PrefixOverride = Utils::String::ToUpper(name) + "_";
Components::Localization::ParseOutput([&assets](Game::LocalizeEntry* asset)
{
assets.push_back(asset);
});
const auto* psLoadedFile = Game::SE_Load(filename.data(), false);
if (psLoadedFile)
{
Game::Com_PrintError(Game::CON_CHANNEL_SYSTEM, "^1Localization ERROR: %s\n", psLoadedFile);
return;
}
auto type = Game::DB_GetXAssetNameType("localize");
for (const auto& entry : assets)
{
builder->addRawAsset(type, entry);
}
}
void ILocalizeEntry::ParseLocalizedStringsJSON(Components::ZoneBuilder::Zone* builder, Components::FileSystem::File& file)
{
nlohmann::json localize;
try
{
Components::Logger::Debug("Parsing localized string \"{}\"...", file.getName());
localize = nlohmann::json::parse(file.getBuffer());
}
catch (const std::exception& ex)
{
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}\n", ex.what());
return;
}
if (!localize.is_object())
{
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Localized strings json file '{}' should be an object!", file.getName());
return;
}
std::vector<Game::LocalizeEntry*> assets;
try
{
for (const auto& [key, value] : localize.items())
{
const auto valueStr = value.get<std::string>();
auto* entry = builder->getAllocator()->allocate<Game::LocalizeEntry>();
entry->name = builder->getAllocator()->duplicateString(key);
entry->value = builder->getAllocator()->duplicateString(valueStr);
assets.emplace_back(entry);
}
}
catch (const std::exception& ex)
{
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}: Localized strings json file '{}' contains invalid data!", ex.what(), file.getName());
}
auto type = Game::DB_GetXAssetNameType("localize");
for (const auto& entry : assets)
{
builder->addRawAsset(type, entry);
}
}
}

View File

@ -1,16 +0,0 @@
#pragma once
namespace Assets
{
class ILocalizeEntry : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY; }
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
static void ParseLocalizedStringsFile(Components::ZoneBuilder::Zone* builder, const std::string& name, const std::string& filename);
static void ParseLocalizedStringsJSON(Components::ZoneBuilder::Zone* builder, Components::FileSystem::File& file);
};
}

View File

@ -1,98 +0,0 @@
#include <STDInclude.hpp>
#include "IMapEnts.hpp"
namespace Assets
{
void IMapEnts::load(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder)
{
header->mapEnts = builder->getIW4OfApi()->read<Game::MapEnts>(Game::XAssetType::ASSET_TYPE_MAP_ENTS, _name);
}
void IMapEnts::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Utils::Entities memEnts(header.mapEnts->entityString, header.mapEnts->numEntityChars);
for (auto& model : memEnts.getModels())
{
builder->loadAssetByName(Game::XAssetType::ASSET_TYPE_XMODEL, model, false);
}
}
void IMapEnts::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::MapEnts, 44);
Utils::Stream* buffer = builder->getBuffer();
Game::MapEnts* asset = header.mapEnts;
Game::MapEnts* dest = buffer->dest<Game::MapEnts>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->entityString)
{
buffer->save(asset->entityString, asset->numEntityChars);
Utils::Stream::ClearPointer(&dest->entityString);
}
AssertSize(Game::MapTriggers, 24);
if (asset->trigger.models)
{
AssertSize(Game::TriggerModel, 8);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->trigger.models, asset->trigger.count);
Utils::Stream::ClearPointer(&dest->trigger.models);
}
if (asset->trigger.hulls)
{
AssertSize(Game::TriggerHull, 32);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->trigger.hulls, asset->trigger.hullCount);
Utils::Stream::ClearPointer(&dest->trigger.hulls);
}
if (asset->trigger.slabs)
{
AssertSize(Game::TriggerSlab, 20);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->trigger.slabs, asset->trigger.slabCount);
Utils::Stream::ClearPointer(&dest->trigger.slabs);
}
if (asset->stages)
{
AssertSize(Game::Stage, 20);
buffer->align(Utils::Stream::ALIGN_4);
Game::Stage* destStages = buffer->dest<Game::Stage>();
buffer->saveArray(asset->stages, asset->stageCount);
for (char i = 0; i < asset->stageCount; ++i)
{
Game::Stage* destStage = &destStages[i];
Game::Stage* stage = &asset->stages[i];
if (stage->name)
{
buffer->saveString(stage->name);
Utils::Stream::ClearPointer(&destStage->name);
}
}
Utils::Stream::ClearPointer(&dest->stages);
}
buffer->popBlock();
}
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace Assets
{
class IMapEnts : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MAP_ENTS; }
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,178 +0,0 @@
#include <STDInclude.hpp>
#include "IMaterial.hpp"
namespace Assets
{
void IMaterial::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
if (!header->data) this->loadFromDisk(header, name, builder); // Check if we want to load a material from disk
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
assert(header->data);
}
void IMaterial::loadFromDisk(Game::XAssetHeader* header, const std::string& name, [[maybe_unused]] Components::ZoneBuilder::Zone* builder)
{
header->material = builder->getIW4OfApi()->read<Game::Material>(Game::XAssetType::ASSET_TYPE_MATERIAL, name);
}
void IMaterial::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->material = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).material;
}
void IMaterial::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::Material* asset = header.material;
if (asset->techniqueSet)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, asset->techniqueSet);
}
if (asset->textureTable)
{
for (char i = 0; i < asset->textureCount; ++i)
{
if (asset->textureTable[i].u.image)
{
if (asset->textureTable[i].semantic == Game::TextureSemantic::TS_WATER_MAP)
{
if (asset->textureTable[i].u.water->image)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].u.water->image);
}
}
else
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].u.image);
}
}
}
}
}
void IMaterial::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::Material, 96);
Utils::Stream* buffer = builder->getBuffer();
Game::Material* asset = header.material;
Game::Material* dest = buffer->dest<Game::Material>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->info.name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->info.name));
Utils::Stream::ClearPointer(&dest->info.name);
}
if (asset->techniqueSet)
{
dest->techniqueSet = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, asset->techniqueSet).techniqueSet;
}
if (asset->textureTable)
{
AssertSize(Game::MaterialTextureDef, 12);
// Pointer/Offset insertion is untested, but it worked in T6, so I think it's fine
if (builder->hasPointer(asset->textureTable))
{
dest->textureTable = builder->getPointer(asset->textureTable);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->textureTable);
auto* destTextureTable = buffer->dest<Game::MaterialTextureDef>();
buffer->saveArray(asset->textureTable, asset->textureCount);
for (std::uint8_t i = 0; i < asset->textureCount; ++i)
{
auto* destTextureDef = &destTextureTable[i];
auto* textureDef = &asset->textureTable[i];
if (textureDef->semantic == Game::TextureSemantic::TS_WATER_MAP)
{
AssertSize(Game::water_t, 68);
Game::water_t* destWater = buffer->dest<Game::water_t>();
Game::water_t* water = textureDef->u.water;
if (water)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(water);
Utils::Stream::ClearPointer(&destTextureDef->u.water);
// Save_water_t
if (water->H0)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(water->H0, 8, water->M * water->N);
Utils::Stream::ClearPointer(&destWater->H0);
}
if (water->wTerm)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(water->wTerm, 4, water->M * water->N);
Utils::Stream::ClearPointer(&destWater->wTerm);
}
if (water->image)
{
destWater->image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, water->image).image;
}
}
}
else if (textureDef->u.image)
{
destTextureDef->u.image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, textureDef->u.image).image;
}
}
Utils::Stream::ClearPointer(&dest->textureTable);
}
}
if (asset->constantTable)
{
AssertSize(Game::MaterialConstantDef, 32);
if (builder->hasPointer(asset->constantTable))
{
dest->constantTable = builder->getPointer(asset->constantTable);
}
else
{
buffer->align(Utils::Stream::ALIGN_16);
builder->storePointer(asset->constantTable);
buffer->saveArray(asset->constantTable, asset->constantCount);
Utils::Stream::ClearPointer(&dest->constantTable);
}
}
if (asset->stateBitsTable)
{
if (builder->hasPointer(asset->stateBitsTable))
{
dest->stateBitsTable = builder->getPointer(asset->stateBitsTable);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->stateBitsTable);
buffer->save(asset->stateBitsTable, 8, asset->stateBitsCount);
Utils::Stream::ClearPointer(&dest->stateBitsTable);
}
}
buffer->popBlock();
}
}

View File

@ -1,16 +0,0 @@
#pragma once
namespace Assets
{
class IMaterial : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MATERIAL; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,49 +0,0 @@
#include <STDInclude.hpp>
#include "IMaterialPixelShader.hpp"
namespace Assets
{
void IMaterialPixelShader::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
}
void IMaterialPixelShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->pixelShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).pixelShader;
}
void IMaterialPixelShader::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->pixelShader = builder->getIW4OfApi()->read<Game::MaterialPixelShader>(Game::XAssetType::ASSET_TYPE_PIXELSHADER, name);
}
void IMaterialPixelShader::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::MaterialPixelShader, 16);
Utils::Stream* buffer = builder->getBuffer();
Game::MaterialPixelShader* asset = header.pixelShader;
Game::MaterialPixelShader* dest = buffer->dest<Game::MaterialPixelShader>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->prog.loadDef.program)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->prog.loadDef.program, asset->prog.loadDef.programSize);
Utils::Stream::ClearPointer(&dest->prog.loadDef.program);
}
buffer->popBlock();
}
}

View File

@ -1,16 +0,0 @@
#pragma once
namespace Assets
{
class IMaterialPixelShader : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PIXELSHADER; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,198 +0,0 @@
#include <STDInclude.hpp>
#include "IMaterialTechniqueSet.hpp"
#define IW4X_TECHSET_VERSION 1
namespace Assets
{
void IMaterialTechniqueSet::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
if (!header->data) this->loadFromDisk(header, name, builder); // Check if we need to import a new one into the game
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
if (!header->data)
{
AssertUnreachable;
}
}
void IMaterialTechniqueSet::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->techniqueSet = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).techniqueSet;
}
void IMaterialTechniqueSet::loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->techniqueSet = builder->getIW4OfApi()->read<Game::MaterialTechniqueSet>(Game::ASSET_TYPE_TECHNIQUE_SET, name);
auto ptr = header->techniqueSet;
if (ptr)
{
while (ptr->remappedTechniqueSet && ptr->remappedTechniqueSet != ptr)
{
ptr = ptr->remappedTechniqueSet;
builder->loadAsset(Game::ASSET_TYPE_TECHNIQUE_SET, ptr, false);
for (size_t i = 0; i < Game::TECHNIQUE_COUNT; i++)
{
const auto technique = ptr->techniques[i];
if (technique)
{
for (size_t j = 0; j < technique->passCount; j++)
{
const auto pass = &technique->passArray[j];
builder->loadAsset(Game::ASSET_TYPE_VERTEXDECL, pass->vertexDecl, true);
builder->loadAsset(Game::ASSET_TYPE_PIXELSHADER, pass->pixelShader, true);
builder->loadAsset(Game::ASSET_TYPE_VERTEXSHADER, pass->vertexShader, true);
}
}
}
}
}
}
void IMaterialTechniqueSet::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::MaterialTechniqueSet* asset = header.techniqueSet;
for (int i = 0; i < ARRAYSIZE(Game::MaterialTechniqueSet::techniques); ++i)
{
Game::MaterialTechnique* technique = asset->techniques[i];
if (!technique) continue;
for (short j = 0; j < technique->passCount; ++j)
{
Game::MaterialPass* pass = &technique->passArray[j];
if (pass->vertexDecl)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_VERTEXDECL, pass->vertexDecl);
}
if (pass->vertexShader)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, pass->vertexShader);
}
if (pass->pixelShader)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PIXELSHADER, pass->pixelShader);
}
}
}
}
void IMaterialTechniqueSet::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::MaterialTechniqueSet, 204);
Utils::Stream* buffer = builder->getBuffer();
Game::MaterialTechniqueSet* asset = header.techniqueSet;
Game::MaterialTechniqueSet* dest = buffer->dest<Game::MaterialTechniqueSet>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
// Save_MaterialTechniquePtrArray
static_assert(ARRAYSIZE(Game::MaterialTechniqueSet::techniques) == 48, "Techniques array invalid!");
for (int i = 0; i < ARRAYSIZE(Game::MaterialTechniqueSet::techniques); ++i)
{
Game::MaterialTechnique* technique = asset->techniques[i];
if (technique)
{
if (builder->hasPointer(technique))
{
dest->techniques[i] = builder->getPointer(technique);
}
else
{
// Size-check is obsolete, as the structure is dynamic
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(technique);
Game::MaterialTechnique* destTechnique = buffer->dest<Game::MaterialTechnique>();
buffer->save(technique, 8);
// Save_MaterialPassArray
Game::MaterialPass* destPasses = buffer->dest<Game::MaterialPass>();
buffer->saveArray(technique->passArray, technique->passCount);
for (short j = 0; j < technique->passCount; ++j)
{
AssertSize(Game::MaterialPass, 20);
Game::MaterialPass* destPass = &destPasses[j];
Game::MaterialPass* pass = &technique->passArray[j];
if (pass->vertexDecl)
{
destPass->vertexDecl = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_VERTEXDECL, pass->vertexDecl).vertexDecl;
}
if (pass->vertexShader)
{
destPass->vertexShader = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, pass->vertexShader).vertexShader;
}
if (pass->pixelShader)
{
destPass->pixelShader = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PIXELSHADER, pass->pixelShader).pixelShader;
}
if (pass->args)
{
buffer->align(Utils::Stream::ALIGN_4);
Game::MaterialShaderArgument* destArgs = buffer->dest<Game::MaterialShaderArgument>();
buffer->saveArray(pass->args, pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount);
for (int k = 0; k < pass->perPrimArgCount + pass->perObjArgCount + pass->stableArgCount; ++k)
{
Game::MaterialShaderArgument* arg = &pass->args[k];
Game::MaterialShaderArgument* destArg = &destArgs[k];
if (arg->type == 1 || arg->type == 7)
{
if (builder->hasPointer(arg->u.literalConst))
{
destArg->u.literalConst = builder->getPointer(arg->u.literalConst);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(arg->u.literalConst);
buffer->saveArray(arg->u.literalConst, 4);
Utils::Stream::ClearPointer(&destArg->u.literalConst);
}
}
}
Utils::Stream::ClearPointer(&destPass->args);
}
}
if (technique->name)
{
buffer->saveString(technique->name);
Utils::Stream::ClearPointer(&destTechnique->name);
}
Utils::Stream::ClearPointer(&dest->techniques[i]);
}
}
}
buffer->popBlock();
}
}

View File

@ -1,19 +0,0 @@
#pragma once
namespace Assets
{
class IMaterialTechniqueSet : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadTechniqueFromDisk(Game::MaterialTechnique** tech, const std::string& name, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,45 +0,0 @@
#include <STDInclude.hpp>
#include "IMaterialVertexDeclaration.hpp"
#define IW4X_TECHSET_VERSION 1
namespace Assets
{
void IMaterialVertexDeclaration::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
}
void IMaterialVertexDeclaration::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->vertexDecl = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexDecl;
}
void IMaterialVertexDeclaration::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->vertexDecl = builder->getIW4OfApi()->read<Game::MaterialVertexDeclaration>(Game::XAssetType::ASSET_TYPE_VERTEXDECL, name);
}
void IMaterialVertexDeclaration::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::MaterialVertexDeclaration, 100);
Utils::Stream* buffer = builder->getBuffer();
Game::MaterialVertexDeclaration* asset = header.vertexDecl;
Game::MaterialVertexDeclaration* dest = buffer->dest<Game::MaterialVertexDeclaration>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
AssertSize(Game::MaterialVertexStreamRouting, 92);
buffer->popBlock();
}
}

View File

@ -1,16 +0,0 @@
#pragma once
namespace Assets
{
class IMaterialVertexDeclaration : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_VERTEXDECL; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,50 +0,0 @@
#include <STDInclude.hpp>
#include "IMaterialVertexShader.hpp"
#define GFX_RENDERER_SHADER_SM3 0
namespace Assets
{
void IMaterialVertexShader::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
}
void IMaterialVertexShader::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
header->vertexShader = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).vertexShader;
}
void IMaterialVertexShader::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->vertexShader = builder->getIW4OfApi()->read<Game::MaterialVertexShader>(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, name);
}
void IMaterialVertexShader::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::MaterialVertexShader, 16);
Utils::Stream* buffer = builder->getBuffer();
Game::MaterialVertexShader* asset = header.vertexShader;
Game::MaterialVertexShader* dest = buffer->dest<Game::MaterialVertexShader>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->prog.loadDef.program)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->prog.loadDef.program, asset->prog.loadDef.programSize);
Utils::Stream::ClearPointer(&dest->prog.loadDef.program);
}
buffer->popBlock();
}
}

View File

@ -1,16 +0,0 @@
#pragma once
namespace Assets
{
class IMaterialVertexShader : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_VERTEXSHADER; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,81 +0,0 @@
#include <STDInclude.hpp>
#include "IMenuList.hpp"
namespace Assets
{
void IMenuList::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
Utils::Memory::Allocator* allocator = builder->getAllocator();
// actually gets the whole list
auto menus = Components::Menus::LoadMenu(name);
if (menus.empty()) return;
// Allocate new menu list
auto* newList = allocator->allocate<Game::MenuList>();
if (!newList) return;
newList->menus = allocator->allocateArray<Game::menuDef_t*>(menus.size());
if (!newList->menus)
{
allocator->free(newList);
return;
}
newList->name = allocator->duplicateString(name);
newList->menuCount = menus.size();
// Copy new menus
for (unsigned int i = 0; i < menus.size(); ++i)
{
newList->menus[i] = menus[i].second;
}
header->menuList = newList;
}
void IMenuList::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
auto* asset = header.menuList;
for (int i = 0; i < asset->menuCount; ++i)
{
if (asset->menus[i])
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MENU, asset->menus[i]);
}
}
}
void IMenuList::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::MenuList, 12);
Utils::Stream* buffer = builder->getBuffer();
Game::MenuList* asset = header.menuList;
auto* dest = buffer->dest<Game::MenuList>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->menus)
{
buffer->align(Utils::Stream::ALIGN_4);
auto** destMenus = buffer->dest<Game::menuDef_t*>();
buffer->saveArray(asset->menus, asset->menuCount);
for (int i = 0; i < asset->menuCount; ++i)
{
destMenus[i] = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MENU, asset->menus[i]).menu;
}
}
buffer->popBlock();
}
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace Assets
{
class IMenuList : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MENULIST; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,136 +0,0 @@
#include <STDInclude.hpp>
#include "IPhysCollmap.hpp"
namespace Assets
{
void IPhysCollmap::saveBrushWrapper(Components::ZoneBuilder::Zone* builder, Game::BrushWrapper* brush)
{
AssertSize(Game::BrushWrapper, 68);
Utils::Stream* buffer = builder->getBuffer();
Game::BrushWrapper* destBrush = buffer->dest<Game::BrushWrapper>();
buffer->save(brush);
// Save_cbrushWrapper_t
{
AssertSize(Game::cbrush_t, 36);
if (brush->brush.sides)
{
AssertSize(Game::cbrushside_t, 8);
buffer->align(Utils::Stream::ALIGN_4);
Game::cbrushside_t* destBrushSide = buffer->dest<Game::cbrushside_t>();
buffer->saveArray(brush->brush.sides, brush->brush.numsides);
// Save_cbrushside_tArray
for (unsigned short i = 0; i < brush->brush.numsides; ++i)
{
Game::cbrushside_t* destSide = &destBrushSide[i];
Game::cbrushside_t* side = &brush->brush.sides[i];
if (side->plane)
{
if (builder->hasPointer(side->plane))
{
destSide->plane = builder->getPointer(side->plane);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(side->plane);
buffer->save(side->plane, sizeof(Game::cplane_s));
Utils::Stream::ClearPointer(&destSide->plane);
}
}
}
Utils::Stream::ClearPointer(&destBrush->brush.sides);
}
if (brush->brush.baseAdjacentSide)
{
buffer->save(brush->brush.baseAdjacentSide, brush->totalEdgeCount);
Utils::Stream::ClearPointer(&destBrush->brush.baseAdjacentSide);
}
}
if (brush->planes)
{
AssertSize(Game::cplane_s, 20);
if (builder->hasPointer(brush->planes))
{
Components::Logger::Print("Loading cplane pointer before the array has been written. Not sure if this is correct!\n");
destBrush->planes = builder->getPointer(brush->planes);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
for (unsigned short j = 0; j < brush->brush.numsides; ++j)
{
builder->storePointer(&brush->planes[j]);
buffer->save(&brush->planes[j]);
}
Utils::Stream::ClearPointer(&destBrush->planes);
}
}
}
void IPhysCollmap::savePhysGeomInfoArray(Components::ZoneBuilder::Zone* builder, Game::PhysGeomInfo* geoms, unsigned int count)
{
AssertSize(Game::PhysGeomInfo, 68);
Utils::Stream* buffer = builder->getBuffer();
Game::PhysGeomInfo* destGeoms = buffer->dest<Game::PhysGeomInfo>();
buffer->saveArray(geoms, count);
for (unsigned int i = 0; i < count; ++i)
{
Game::PhysGeomInfo* destGeom = &destGeoms[i];
Game::PhysGeomInfo* geom = &geoms[i];
if (geom->brushWrapper)
{
buffer->align(Utils::Stream::ALIGN_4);
this->saveBrushWrapper(builder, geom->brushWrapper);
Utils::Stream::ClearPointer(&destGeom->brushWrapper);
}
}
}
void IPhysCollmap::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::XModel, 304);
Utils::Stream* buffer = builder->getBuffer();
Game::PhysCollmap* asset = header.physCollmap;
Game::PhysCollmap* dest = buffer->dest<Game::PhysCollmap>();
buffer->save(asset, sizeof(Game::PhysCollmap));
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->geoms)
{
buffer->align(Utils::Stream::ALIGN_4);
this->savePhysGeomInfoArray(builder, asset->geoms, asset->count);
Utils::Stream::ClearPointer(&dest->geoms);
}
buffer->popBlock();
}
}

View File

@ -1,16 +0,0 @@
#pragma once
namespace Assets
{
class IPhysCollmap : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private:
void savePhysGeomInfoArray(Components::ZoneBuilder::Zone* builder, Game::PhysGeomInfo* geoms, unsigned int count);
void saveBrushWrapper(Components::ZoneBuilder::Zone* builder, Game::BrushWrapper* brush);
};
}

View File

@ -1,41 +0,0 @@
#include <STDInclude.hpp>
#include "IPhysPreset.hpp"
namespace Assets
{
void IPhysPreset::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::PhysPreset, 44);
auto* buffer = builder->getBuffer();
auto* asset = header.physPreset;
auto* dest = buffer->dest<Game::PhysPreset>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->sndAliasPrefix)
{
buffer->saveString(asset->sndAliasPrefix);
Utils::Stream::ClearPointer(&dest->sndAliasPrefix);
}
buffer->popBlock();
}
void IPhysPreset::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
loadFromDisk(header, name, builder);
}
void IPhysPreset::loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->physPreset = builder->getIW4OfApi()->read<Game::PhysPreset>(Game::XAssetType::ASSET_TYPE_PHYSPRESET, name);
}
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace Assets
{
class IPhysPreset : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PHYSPRESET; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,46 +0,0 @@
#include <STDInclude.hpp>
#include "IRawFile.hpp"
#include <Utils/Compression.hpp>
namespace Assets
{
void IRawFile::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->rawfile = builder->getIW4OfApi()->read<Game::RawFile>(Game::XAssetType::ASSET_TYPE_RAWFILE, name);
}
void IRawFile::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::RawFile, 16);
auto* buffer = builder->getBuffer();
auto* asset = header.rawfile;
auto* dest = buffer->dest<Game::RawFile>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->buffer)
{
if (asset->compressedLen)
{
buffer->save(asset->buffer, asset->compressedLen);
}
else
{
buffer->save(asset->buffer, asset->len + 1);
}
Utils::Stream::ClearPointer(&dest->buffer);
}
buffer->popBlock();
}
}

View File

@ -1,13 +0,0 @@
#pragma once
namespace Assets
{
class IRawFile : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_RAWFILE; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,35 +0,0 @@
#include <STDInclude.hpp>
#include "ISndCurve.hpp"
namespace Assets
{
void ISndCurve::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::SndCurve, 136);
auto* buffer = builder->getBuffer();
auto* asset = header.sndCurve;
auto* dest = buffer->dest<Game::SndCurve>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->filename)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->filename));
Utils::Stream::ClearPointer(&dest->filename);
}
buffer->popBlock();
}
void ISndCurve::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->sndCurve = builder->getIW4OfApi()->read<Game::SndCurve>(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, name);
if (!header->sndCurve)
{
header->sndCurve = Components::AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, name.data()).sndCurve;
}
}
}

View File

@ -1,13 +0,0 @@
#pragma once
namespace Assets
{
class ISndCurve : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_SOUND_CURVE; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,52 +0,0 @@
#include <STDInclude.hpp>
#include "IStringTable.hpp"
namespace Assets
{
void IStringTable::saveStringTableCellArray(Components::ZoneBuilder::Zone* builder, Game::StringTableCell* values, int count)
{
AssertSize(Game::StringTableCell, 8);
Utils::Stream* buffer = builder->getBuffer();
Game::StringTableCell* destValues = buffer->dest<Game::StringTableCell>();
buffer->saveArray(destValues, count);
for (int i = 0; i < count; ++i)
{
Game::StringTableCell* destValue = &destValues[i];
Game::StringTableCell* value = &values[i];
buffer->saveString(value->string);
Utils::Stream::ClearPointer(&destValue->string);
}
}
void IStringTable::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::StringTable, 16);
Utils::Stream* buffer = builder->getBuffer();
Game::StringTable* asset = header.stringTable;
Game::StringTable* dest = buffer->dest<Game::StringTable>();
buffer->save(asset, sizeof(Game::StringTable));
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->values)
{
buffer->align(Utils::Stream::ALIGN_4);
this->saveStringTableCellArray(builder, asset->values, asset->columnCount * asset->rowCount);
Utils::Stream::ClearPointer(&dest->values);
}
buffer->popBlock();
}
}

View File

@ -1,15 +0,0 @@
#pragma once
namespace Assets
{
class IStringTable : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_STRINGTABLE; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private:
static void saveStringTableCellArray(Components::ZoneBuilder::Zone* builder, Game::StringTableCell* values, int count);
};
}

View File

@ -1,152 +0,0 @@
#include <STDInclude.hpp>
#include "IStructuredDataDefSet.hpp"
namespace Assets
{
void IStructuredDataDefSet::saveStructuredDataEnumArray(Game::StructuredDataEnum* enums, int numEnums, Components::ZoneBuilder::Zone* builder)
{
Utils::Stream* buffer = builder->getBuffer();
Game::StructuredDataEnum* destEnums = buffer->dest<Game::StructuredDataEnum>();
buffer->saveArray(enums, numEnums);
for (int i = 0; i < numEnums; ++i)
{
Game::StructuredDataEnum* destEnum = &destEnums[i];
Game::StructuredDataEnum* enum_ = &enums[i];
if (enum_->entries)
{
AssertSize(Game::StructuredDataEnumEntry, 8);
buffer->align(Utils::Stream::ALIGN_4);
Game::StructuredDataEnumEntry* destIndices = buffer->dest<Game::StructuredDataEnumEntry>();
buffer->saveArray(enum_->entries, enum_->entryCount);
for (int j = 0; j < enum_->entryCount; ++j)
{
Game::StructuredDataEnumEntry* destIndex = &destIndices[j];
Game::StructuredDataEnumEntry* index = &enum_->entries[j];
if (index->string)
{
buffer->saveString(index->string);
Utils::Stream::ClearPointer(&destIndex->string);
}
}
Utils::Stream::ClearPointer(&destEnum->entries);
}
}
}
void IStructuredDataDefSet::saveStructuredDataStructArray(Game::StructuredDataStruct* structs, int numStructs, Components::ZoneBuilder::Zone* builder)
{
Utils::Stream* buffer = builder->getBuffer();
Game::StructuredDataStruct* destStructs = buffer->dest<Game::StructuredDataStruct>();
buffer->saveArray(structs, numStructs);
for (int i = 0; i < numStructs; ++i)
{
Game::StructuredDataStruct* destStruct = &destStructs[i];
Game::StructuredDataStruct* struct_ = &structs[i];
if (struct_->properties)
{
AssertSize(Game::StructuredDataStructProperty, 16);
buffer->align(Utils::Stream::ALIGN_4);
Game::StructuredDataStructProperty* destProperties = buffer->dest<Game::StructuredDataStructProperty>();
buffer->saveArray(struct_->properties, struct_->propertyCount);
for (int j = 0; j < struct_->propertyCount; ++j)
{
Game::StructuredDataStructProperty* destProperty = &destProperties[j];
Game::StructuredDataStructProperty* property = &struct_->properties[j];
if (property->name)
{
buffer->saveString(property->name);
Utils::Stream::ClearPointer(&destProperty->name);
}
}
Utils::Stream::ClearPointer(&destStruct->properties);
}
}
}
void IStructuredDataDefSet::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::StructuredDataDefSet, 12);
Utils::Stream* buffer = builder->getBuffer();
Game::StructuredDataDefSet* asset = header.structuredDataDefSet;
Game::StructuredDataDefSet* dest = buffer->dest<Game::StructuredDataDefSet>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->defs)
{
AssertSize(Game::StructuredDataDef, 52);
buffer->align(Utils::Stream::ALIGN_4);
Game::StructuredDataDef* destDataArray = buffer->dest<Game::StructuredDataDef>();
buffer->saveArray(asset->defs, asset->defCount);
for (unsigned int i = 0; i < asset->defCount; ++i)
{
Game::StructuredDataDef* destData = &destDataArray[i];
Game::StructuredDataDef* data = &asset->defs[i];
if (data->enums)
{
AssertSize(Game::StructuredDataEnum, 12);
buffer->align(Utils::Stream::ALIGN_4);
this->saveStructuredDataEnumArray(data->enums, data->enumCount, builder);
Utils::Stream::ClearPointer(&destData->enums);
}
if (data->structs)
{
AssertSize(Game::StructuredDataStruct, 16);
buffer->align(Utils::Stream::ALIGN_4);
this->saveStructuredDataStructArray(data->structs, data->structCount, builder);
Utils::Stream::ClearPointer(&destData->structs);
}
if (data->indexedArrays)
{
AssertSize(Game::StructuredDataIndexedArray, 16);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(data->indexedArrays, data->indexedArrayCount);
Utils::Stream::ClearPointer(&destData->indexedArrays);
}
if (data->enumedArrays)
{
AssertSize(Game::StructuredDataEnumedArray, 16);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(data->enumedArrays, data->enumedArrayCount);
Utils::Stream::ClearPointer(&destData->enumedArrays);
}
}
Utils::Stream::ClearPointer(&dest->defs);
}
buffer->popBlock();
}
}

View File

@ -1,15 +0,0 @@
#pragma once
namespace Assets
{
class IStructuredDataDefSet : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_STRUCTURED_DATA_DEF; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
static void saveStructuredDataEnumArray(Game::StructuredDataEnum* enums, int numEnums, Components::ZoneBuilder::Zone* builder);
static void saveStructuredDataStructArray(Game::StructuredDataStruct* structs, int numStructs, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,45 +0,0 @@
#include <STDInclude.hpp>
#include "ITracerDef.hpp"
namespace Assets
{
void ITracerDef::load(Game::XAssetHeader* /*header*/, const std::string& /*name*/, Components::ZoneBuilder::Zone* /*builder*/)
{
// don't load from filesystem right now
}
void ITracerDef::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::TracerDef* asset = header.tracerDef;
if (asset->material)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->material);
}
}
void ITracerDef::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::TracerDef, 0x70);
Utils::Stream* buffer = builder->getBuffer();
Game::TracerDef* asset = header.tracerDef;
Game::TracerDef* dest = buffer->dest<Game::TracerDef>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->material)
{
dest->material = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->material).material;
}
buffer->popBlock();
}
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace Assets
{
class ITracerDef : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_TRACER; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,785 +0,0 @@
#include <STDInclude.hpp>
#include "IWeapon.hpp"
namespace Assets
{
void IWeapon::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
// Try loading raw weapon
if (Components::FileSystem::File(std::format("weapons/mp/{}", name)))
{
// let the function see temporary assets when calling DB_FindXAssetHeader during the loading function
// otherwise it fails to link things properly
Components::AssetHandler::ExposeTemporaryAssets(true);
header->data = Game::BG_LoadWeaponDef_LoadObj(name.data());
Components::AssetHandler::ExposeTemporaryAssets(false);
}
}
void IWeapon::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::WeaponCompleteDef* asset = header.weapon;
// convert all script strings
if (asset->hideTags)
{
for (char i = 0; i < 32; ++i)
{
if (asset->hideTags[i] == NULL) break; // no more strings
builder->addScriptString(asset->hideTags[i]);
}
}
if (asset->weapDef->notetrackSoundMapKeys)
{
for (char i = 0; i < 16; ++i)
{
if (asset->weapDef->notetrackSoundMapKeys[i] == NULL) break; // no more strings
builder->addScriptString(asset->weapDef->notetrackSoundMapKeys[i]);
}
}
if (asset->weapDef->notetrackSoundMapValues)
{
for (char i = 0; i < 16; ++i)
{
if (asset->weapDef->notetrackSoundMapValues[i] == NULL) break; // no more strings
builder->addScriptString(asset->weapDef->notetrackSoundMapValues[i]);
}
}
if (asset->weapDef->notetrackRumbleMapKeys)
{
for (char i = 0; i < 16; ++i)
{
if (asset->weapDef->notetrackRumbleMapKeys[i] == NULL) break; // no more strings
builder->addScriptString(asset->weapDef->notetrackRumbleMapKeys[i]);
}
}
if (asset->weapDef->notetrackRumbleMapValues)
{
for (char i = 0; i < 16; ++i)
{
if (asset->weapDef->notetrackRumbleMapValues[i] == NULL) break; // no more strings
builder->addScriptString(asset->weapDef->notetrackRumbleMapValues[i]);
}
}
// now load all sub-assets properly
if (asset->killIcon) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->killIcon);
if (asset->dpadIcon) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->dpadIcon);
if (asset->weapDef->reticleCenter) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->reticleCenter);
if (asset->weapDef->reticleSide) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->reticleSide);
if (asset->weapDef->hudIcon) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->hudIcon);
if (asset->weapDef->pickupIcon) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->pickupIcon);
if (asset->weapDef->ammoCounterIcon) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->ammoCounterIcon);
if (asset->weapDef->overlayMaterial) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->overlayMaterial);
if (asset->weapDef->overlayMaterialLowRes) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->overlayMaterialLowRes);
if (asset->weapDef->overlayMaterialEMP) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->overlayMaterialEMP);
if (asset->weapDef->overlayMaterialEMPLowRes) builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->weapDef->overlayMaterialEMPLowRes);
if (asset->weapDef->gunXModel)
{
for (int i = 0; i < 16; i++)
{
if (asset->weapDef->gunXModel[i]) builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->weapDef->gunXModel[i]);
}
}
if (asset->weapDef->handXModel) builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->weapDef->handXModel);
if (asset->weapDef->worldModel)
{
for (int i = 0; i < 16; i++)
{
if (asset->weapDef->worldModel[i]) builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->weapDef->worldModel[i]);
}
}
if (asset->weapDef->worldClipModel) builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->weapDef->worldClipModel);
if (asset->weapDef->rocketModel) builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->weapDef->rocketModel);
if (asset->weapDef->knifeModel) builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->weapDef->knifeModel);
if (asset->weapDef->worldKnifeModel) builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->weapDef->worldKnifeModel);
if (asset->weapDef->projectileModel) builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->weapDef->projectileModel);
if (asset->weapDef->physCollmap) builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP, asset->weapDef->physCollmap);
if (asset->weapDef->tracerType) builder->loadAsset(Game::XAssetType::ASSET_TYPE_TRACER, asset->weapDef->tracerType);
if (asset->weapDef->viewFlashEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->viewFlashEffect);
if (asset->weapDef->worldFlashEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->worldFlashEffect);
if (asset->weapDef->viewShellEjectEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->viewShellEjectEffect);
if (asset->weapDef->worldShellEjectEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->worldShellEjectEffect);
if (asset->weapDef->viewLastShotEjectEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->viewLastShotEjectEffect);
if (asset->weapDef->worldLastShotEjectEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->worldLastShotEjectEffect);
if (asset->weapDef->projExplosionEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->projExplosionEffect);
if (asset->weapDef->projDudEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->projDudEffect);
if (asset->weapDef->projTrailEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->projTrailEffect);
if (asset->weapDef->projBeaconEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->projBeaconEffect);
if (asset->weapDef->projIgnitionEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->projIgnitionEffect);
if (asset->weapDef->turretOverheatEffect) builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, asset->weapDef->turretOverheatEffect);
#define LoadWeapSound(sound) if (asset->weapDef->##sound##) builder->loadAsset(Game::XAssetType::ASSET_TYPE_SOUND, asset->weapDef->##sound##)
LoadWeapSound(pickupSound);
LoadWeapSound(pickupSoundPlayer);
LoadWeapSound(ammoPickupSound);
LoadWeapSound(ammoPickupSoundPlayer);
LoadWeapSound(projectileSound);
LoadWeapSound(pullbackSound);
LoadWeapSound(pullbackSoundPlayer);
LoadWeapSound(fireSound);
LoadWeapSound(fireSoundPlayer);
LoadWeapSound(fireSoundPlayerAkimbo);
LoadWeapSound(fireLoopSound);
LoadWeapSound(fireLoopSoundPlayer);
LoadWeapSound(fireStopSound);
LoadWeapSound(fireStopSoundPlayer);
LoadWeapSound(fireLastSound);
LoadWeapSound(fireLastSoundPlayer);
LoadWeapSound(emptyFireSound);
LoadWeapSound(emptyFireSoundPlayer);
LoadWeapSound(meleeSwipeSound);
LoadWeapSound(meleeSwipeSoundPlayer);
LoadWeapSound(meleeHitSound);
LoadWeapSound(meleeMissSound);
LoadWeapSound(rechamberSound);
LoadWeapSound(rechamberSoundPlayer);
LoadWeapSound(reloadSound);
LoadWeapSound(reloadSoundPlayer);
LoadWeapSound(reloadEmptySound);
LoadWeapSound(reloadEmptySoundPlayer);
LoadWeapSound(reloadStartSound);
LoadWeapSound(reloadStartSoundPlayer);
LoadWeapSound(reloadEndSound);
LoadWeapSound(reloadEndSoundPlayer);
LoadWeapSound(detonateSound);
LoadWeapSound(detonateSoundPlayer);
LoadWeapSound(nightVisionWearSound);
LoadWeapSound(nightVisionWearSoundPlayer);
LoadWeapSound(nightVisionRemoveSound);
LoadWeapSound(nightVisionRemoveSoundPlayer);
LoadWeapSound(altSwitchSound);
LoadWeapSound(altSwitchSoundPlayer);
LoadWeapSound(raiseSound);
LoadWeapSound(raiseSoundPlayer);
LoadWeapSound(firstRaiseSound);
LoadWeapSound(firstRaiseSoundPlayer);
LoadWeapSound(putawaySound);
LoadWeapSound(putawaySoundPlayer);
LoadWeapSound(scanSound);
if (asset->weapDef->bounceSound)
{
for (size_t i = 0; i < 31; i++)
{
LoadWeapSound(bounceSound[i]);
}
}
LoadWeapSound(projExplosionSound);
LoadWeapSound(projDudSound);
LoadWeapSound(projIgnitionSound);
LoadWeapSound(turretOverheatSound);
LoadWeapSound(turretBarrelSpinMaxSnd);
for (size_t i = 0; i < 4; i++)
{
LoadWeapSound(turretBarrelSpinUpSnd[i]);
LoadWeapSound(turretBarrelSpinDownSnd[i]);
}
LoadWeapSound(missileConeSoundAlias);
LoadWeapSound(missileConeSoundAliasAtBase);
}
void IWeapon::writeWeaponDef(Game::WeaponDef* def, Components::ZoneBuilder::Zone* builder, Utils::Stream* buffer)
{
AssertSize(Game::WeaponDef, 0x684);
Game::WeaponDef* dest = buffer->dest<Game::WeaponDef>();
buffer->save(def);
if (def->szOverlayName)
{
buffer->saveString(def->szOverlayName);
Utils::Stream::ClearPointer(&dest->szOverlayName);
}
if (def->gunXModel)
{
buffer->align(Utils::Stream::ALIGN_4);
Game::XModel** pointerTable = buffer->dest<Game::XModel*>();
buffer->saveMax(16 * sizeof(Game::XModel*));
for (int i = 0; i < 16; i++)
{
if (!def->gunXModel[i])
{
pointerTable[i] = NULL;
continue;
}
pointerTable[i] = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def->gunXModel[i]).model;
}
Utils::Stream::ClearPointer(&dest->gunXModel);
}
if (def->handXModel)
{
dest->handXModel = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def->handXModel).model;
}
if (def->szXAnimsRightHanded)
{
buffer->align(Utils::Stream::ALIGN_4);
int* poinerTable = buffer->dest<int>();
buffer->saveMax(37 * sizeof(char*)); // array of 37 string pointers
for (int i = 0; i < 37; i++)
{
if (!def->szXAnimsRightHanded[i]) {
poinerTable[i] = 0; // clear poiner if there isn't a string here
continue;
}
// save string if it is present
buffer->saveString(def->szXAnimsRightHanded[i]);
}
Utils::Stream::ClearPointer(&dest->szXAnimsRightHanded);
}
if (def->szXAnimsLeftHanded)
{
buffer->align(Utils::Stream::ALIGN_4);
int* poinerTable = buffer->dest<int>();
buffer->saveMax(37 * sizeof(char*)); // array of 37 string pointers
for (int i = 0; i < 37; i++)
{
if (!def->szXAnimsLeftHanded[i]) {
poinerTable[i] = 0; // clear poiner if there isn't a string here
continue;
}
// save string if it is present
buffer->saveString(def->szXAnimsLeftHanded[i]);
}
Utils::Stream::ClearPointer(&dest->szXAnimsLeftHanded);
}
if (def->szModeName)
{
buffer->saveString(def->szModeName);
Utils::Stream::ClearPointer(&dest->szModeName);
}
if (def->notetrackSoundMapKeys)
{
buffer->align(Utils::Stream::ALIGN_2);
unsigned short* scriptStringTable = buffer->dest<unsigned short>();
buffer->saveArray(def->notetrackSoundMapKeys, 16);
for (int i = 0; i < 16; i++) {
builder->mapScriptString(scriptStringTable[i]);
}
Utils::Stream::ClearPointer(&dest->notetrackSoundMapKeys);
}
if (def->notetrackSoundMapValues)
{
buffer->align(Utils::Stream::ALIGN_2);
unsigned short* scriptStringTable = buffer->dest<unsigned short>();
buffer->saveArray(def->notetrackSoundMapValues, 16);
for (int i = 0; i < 16; i++) {
builder->mapScriptString(scriptStringTable[i]);
}
Utils::Stream::ClearPointer(&dest->notetrackSoundMapValues);
}
if (def->notetrackRumbleMapKeys)
{
buffer->align(Utils::Stream::ALIGN_2);
unsigned short* scriptStringTable = buffer->dest<unsigned short>();
buffer->saveArray(def->notetrackRumbleMapKeys, 16);
for (int i = 0; i < 16; i++) {
builder->mapScriptString(scriptStringTable[i]);
}
Utils::Stream::ClearPointer(&dest->notetrackRumbleMapKeys);
}
if (def->notetrackRumbleMapValues)
{
buffer->align(Utils::Stream::ALIGN_2);
unsigned short* scriptStringTable = buffer->dest<unsigned short>();
buffer->saveArray(def->notetrackRumbleMapValues, 16);
for (int i = 0; i < 16; i++) {
builder->mapScriptString(scriptStringTable[i]);
}
Utils::Stream::ClearPointer(&dest->notetrackRumbleMapValues);
}
if (def->viewFlashEffect)
{
dest->viewFlashEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->viewFlashEffect).fx;
}
if (def->worldFlashEffect)
{
dest->worldFlashEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->worldFlashEffect).fx;
}
// This is compressed because I don't want to write the same piece of code 47 times
// TODO: verify that this is saving the aliases correctly because the old code looks wrong and this looks right but the old code worked so go figure
Game::snd_alias_list_t ** allSounds = &def->pickupSound;
Game::snd_alias_list_t ** allSoundsDest = &dest->pickupSound;
for (int i = 0; i < 47; i++) {
if (!allSounds[i]) continue;
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(allSounds[i]->aliasName);
Utils::Stream::ClearPointer(&allSoundsDest[i]);
}
if (def->bounceSound)
{
buffer->align(Utils::Stream::ALIGN_4);
int* ptrs = buffer->dest<int>();
buffer->saveMax(31 * sizeof(Game::snd_alias_list_t*));
for (int i = 0; i < 31; i++)
{
if (!def->bounceSound[i])
{
ptrs[i] = 0;
continue;
}
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->bounceSound[i]->aliasName);
}
Utils::Stream::ClearPointer(&dest->bounceSound);
}
if (def->viewShellEjectEffect)
{
dest->viewShellEjectEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->viewShellEjectEffect).fx;
}
if (def->worldShellEjectEffect)
{
dest->worldShellEjectEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->worldShellEjectEffect).fx;
}
if (def->viewLastShotEjectEffect)
{
dest->viewLastShotEjectEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->viewLastShotEjectEffect).fx;
}
if (def->worldLastShotEjectEffect)
{
dest->worldLastShotEjectEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->worldLastShotEjectEffect).fx;
}
if (def->reticleCenter)
{
dest->reticleCenter = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->reticleCenter).material;
}
if (def->reticleSide)
{
dest->reticleSide = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->reticleSide).material;
}
if (def->worldModel)
{
buffer->align(Utils::Stream::ALIGN_4);
Game::XModel** pointerTable = buffer->dest<Game::XModel*>();
buffer->saveMax(16 * sizeof(Game::XModel*));
for (int i = 0; i < 16; i++)
{
if (!def->worldModel[i])
{
pointerTable[i] = NULL;
continue;
}
pointerTable[i] = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def->worldModel[i]).model;
}
Utils::Stream::ClearPointer(&dest->worldModel);
}
if (def->worldClipModel)
{
dest->worldClipModel = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def->worldClipModel).model;
}
if (def->rocketModel)
{
dest->rocketModel = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def->rocketModel).model;
}
if (def->knifeModel)
{
dest->knifeModel = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def->knifeModel).model;
}
if (def->worldKnifeModel)
{
dest->worldKnifeModel = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def->worldKnifeModel).model;
}
if (def->hudIcon)
{
dest->hudIcon = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->hudIcon).material;
}
if (def->pickupIcon)
{
dest->pickupIcon = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->pickupIcon).material;
}
if (def->ammoCounterIcon)
{
dest->ammoCounterIcon = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->ammoCounterIcon).material;
}
if (def->szAmmoName)
{
buffer->saveString(def->szAmmoName);
Utils::Stream::ClearPointer(&dest->szAmmoName);
}
if (def->szClipName)
{
buffer->saveString(def->szClipName);
Utils::Stream::ClearPointer(&dest->szClipName);
}
if (def->szSharedAmmoCapName)
{
buffer->saveString(def->szSharedAmmoCapName);
Utils::Stream::ClearPointer(&dest->szSharedAmmoCapName);
}
if (def->overlayMaterial)
{
dest->overlayMaterial = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->overlayMaterial).material;
}
if (def->overlayMaterialLowRes)
{
dest->overlayMaterialLowRes = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->overlayMaterialLowRes).material;
}
if (def->overlayMaterialEMP)
{
dest->overlayMaterialEMP = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->overlayMaterialEMP).material;
}
if (def->overlayMaterialEMPLowRes)
{
dest->overlayMaterialEMPLowRes = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, def->overlayMaterialEMPLowRes).material;
}
if (def->physCollmap)
{
dest->physCollmap = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP, def->overlayMaterialEMPLowRes).physCollmap;
}
if (def->projectileModel)
{
dest->projectileModel = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def->projectileModel).model;
}
if (def->projExplosionEffect)
{
dest->projExplosionEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->projExplosionEffect).fx;
}
if (def->projDudEffect)
{
dest->projDudEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->projDudEffect).fx;
}
if (def->projExplosionSound)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->projExplosionSound->aliasName);
Utils::Stream::ClearPointer(&dest->projExplosionSound);
}
if (def->projDudSound)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->projDudSound->aliasName);
Utils::Stream::ClearPointer(&dest->projDudSound);
}
if (def->parallelBounce)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(def->parallelBounce, 31);
Utils::Stream::ClearPointer(&dest->parallelBounce);
}
if (def->perpendicularBounce)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(def->perpendicularBounce, 31);
Utils::Stream::ClearPointer(&dest->perpendicularBounce);
}
if (def->projTrailEffect)
{
dest->projTrailEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->projTrailEffect).fx;
}
if (def->projBeaconEffect)
{
dest->projBeaconEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->projBeaconEffect).fx;
}
if (def->projIgnitionEffect)
{
dest->projIgnitionEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->projIgnitionEffect).fx;
}
if (def->projIgnitionSound)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->projIgnitionSound->aliasName);
Utils::Stream::ClearPointer(&dest->projIgnitionSound);
}
if (def->accuracyGraphName[0])
{
buffer->saveString(def->accuracyGraphName[0]);
Utils::Stream::ClearPointer(&dest->accuracyGraphName[0]);
}
if (def->originalAccuracyGraphKnots[0])
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(def->originalAccuracyGraphKnots[0], def->originalAccuracyGraphKnotCount[0]);
Utils::Stream::ClearPointer(&dest->originalAccuracyGraphKnots[0]);
}
if (def->accuracyGraphName[1])
{
buffer->saveString(def->accuracyGraphName[1]);
Utils::Stream::ClearPointer(&dest->accuracyGraphName[1]);
}
if (def->originalAccuracyGraphKnots[1])
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(def->originalAccuracyGraphKnots[1], def->originalAccuracyGraphKnotCount[1]);
Utils::Stream::ClearPointer(&dest->originalAccuracyGraphKnots[1]);
}
if (def->szUseHintString)
{
buffer->saveString(def->szUseHintString);
Utils::Stream::ClearPointer(&dest->szUseHintString);
}
if (def->dropHintString)
{
buffer->saveString(def->dropHintString);
Utils::Stream::ClearPointer(&dest->dropHintString);
}
if (def->szScript)
{
buffer->saveString(def->szScript);
Utils::Stream::ClearPointer(&dest->szScript);
}
if (def->locationDamageMultipliers)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(def->locationDamageMultipliers, 20);
Utils::Stream::ClearPointer(&dest->locationDamageMultipliers);
}
if (def->fireRumble)
{
buffer->saveString(def->fireRumble);
Utils::Stream::ClearPointer(&dest->fireRumble);
}
if (def->meleeImpactRumble)
{
buffer->saveString(def->meleeImpactRumble);
Utils::Stream::ClearPointer(&dest->meleeImpactRumble);
}
if (def->tracerType)
{
dest->tracerType = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_TRACER, def->tracerType).tracerDef;
}
if (def->turretOverheatSound)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->turretOverheatSound->aliasName);
Utils::Stream::ClearPointer(&dest->turretOverheatSound);
}
if (def->turretOverheatEffect)
{
dest->turretOverheatEffect = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, def->turretOverheatEffect).fx;
}
if (def->turretBarrelSpinRumble)
{
buffer->saveString(def->turretBarrelSpinRumble);
Utils::Stream::ClearPointer(&dest->turretBarrelSpinRumble);
}
if (def->turretBarrelSpinMaxSnd)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->turretBarrelSpinMaxSnd->aliasName);
Utils::Stream::ClearPointer(&dest->turretBarrelSpinMaxSnd);
}
for (int i = 0; i < 4; i++) {
if (!def->turretBarrelSpinUpSnd[i]) continue;
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->turretBarrelSpinUpSnd[i]->aliasName);
Utils::Stream::ClearPointer(&dest->turretBarrelSpinUpSnd[i]);
}
for (int i = 0; i < 4; i++) {
if (!def->turretBarrelSpinDownSnd[i]) continue;
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->turretBarrelSpinDownSnd[i]->aliasName);
Utils::Stream::ClearPointer(&dest->turretBarrelSpinDownSnd[i]);
}
if (def->missileConeSoundAlias)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->missileConeSoundAlias->aliasName);
Utils::Stream::ClearPointer(&dest->missileConeSoundAlias);
}
if (def->missileConeSoundAliasAtBase)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
buffer->saveString(def->missileConeSoundAliasAtBase->aliasName);
Utils::Stream::ClearPointer(&dest->missileConeSoundAliasAtBase);
}
}
void IWeapon::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::WeaponCompleteDef, 0x74);
Utils::Stream* buffer = builder->getBuffer();
Game::WeaponCompleteDef* asset = header.weapon;
Game::WeaponCompleteDef* dest = buffer->dest<Game::WeaponCompleteDef>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->szInternalName)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->szInternalName));
Utils::Stream::ClearPointer(&dest->szInternalName);
}
if (asset->weapDef)
{
buffer->align(Utils::Stream::ALIGN_4);
IWeapon::writeWeaponDef(asset->weapDef, builder, buffer);
Utils::Stream::ClearPointer(&dest->weapDef);
}
if (asset->szDisplayName)
{
buffer->saveString(asset->szDisplayName);
Utils::Stream::ClearPointer(&dest->szDisplayName);
}
if (asset->hideTags)
{
buffer->align(Utils::Stream::ALIGN_2);
unsigned short* scriptStringTable = buffer->dest<unsigned short>();
buffer->saveArray(asset->hideTags, 32);
for (int i = 0; i < 32; i++) {
builder->mapScriptString(scriptStringTable[i]);
}
Utils::Stream::ClearPointer(&dest->hideTags);
}
if (asset->szXAnims)
{
buffer->align(Utils::Stream::ALIGN_4);
int* poinerTable = buffer->dest<int>();
buffer->saveMax(37 * sizeof(char*)); // array of 37 string pointers
for (int i = 0; i < 37; i++)
{
if (!asset->szXAnims[i]) {
poinerTable[i] = 0; // clear poiner if there isn't a string here
continue;
}
// save string if it is present
buffer->saveString(asset->szXAnims[i]);
}
Utils::Stream::ClearPointer(&dest->szXAnims);
}
if (asset->szAltWeaponName)
{
buffer->saveString(asset->szAltWeaponName);
Utils::Stream::ClearPointer(&dest->szAltWeaponName);
}
if (asset->killIcon)
{
dest->killIcon = builder->saveSubAsset(Game::ASSET_TYPE_MATERIAL, asset->killIcon).material;
}
if (asset->dpadIcon)
{
dest->dpadIcon = builder->saveSubAsset(Game::ASSET_TYPE_MATERIAL, asset->dpadIcon).material;
}
if (asset->accuracyGraphKnots[0])
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->accuracyGraphKnots[0], asset->accuracyGraphKnotCount[0]);
Utils::Stream::ClearPointer(&dest->accuracyGraphKnots[0]);
}
if (asset->accuracyGraphKnots[1])
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->accuracyGraphKnots[1], asset->accuracyGraphKnotCount[1]);
Utils::Stream::ClearPointer(&dest->accuracyGraphKnots[1]);
}
buffer->popBlock();
}
}

View File

@ -1,17 +0,0 @@
#pragma once
namespace Assets
{
class IWeapon : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_WEAPON; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private:
void writeWeaponDef(Game::WeaponDef* def, Components::ZoneBuilder::Zone* builder, Utils::Stream* buffer);
};
}

View File

@ -1,259 +0,0 @@
#include <STDInclude.hpp>
#include "IXAnimParts.hpp"
namespace Assets
{
void IXAnimParts::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->parts = builder->getIW4OfApi()->read<Game::XAnimParts>(Game::XAssetType::ASSET_TYPE_XANIMPARTS, name);
}
void IXAnimParts::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::XAnimParts* asset = header.parts;
if (asset->names)
{
for (char i = 0; i < asset->boneCount[Game::PART_TYPE_ALL]; ++i)
{
builder->addScriptString(asset->names[i]);
}
}
if (asset->notify)
{
for (char i = 0; i < asset->notifyCount; ++i)
{
builder->addScriptString(asset->notify[i].name);
}
}
}
void IXAnimParts::saveXAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::XAnimDeltaPart, 12);
Utils::Stream* buffer = builder->getBuffer();
Game::XAnimDeltaPart* destDelta = buffer->dest<Game::XAnimDeltaPart>();
buffer->save(delta);
if (delta->trans)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->trans, 4);
if (delta->trans->size)
{
buffer->save(&delta->trans->u.frames, 28);
if (framecount > 0xFF)
{
buffer->saveArray(delta->trans->u.frames.indices._2, delta->trans->size + 1);
}
else
{
buffer->saveArray(delta->trans->u.frames.indices._1, delta->trans->size + 1);
}
if (delta->trans->u.frames.frames._1)
{
if (delta->trans->smallTrans)
{
buffer->save(delta->trans->u.frames.frames._1, 3, delta->trans->size + 1);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->trans->u.frames.frames._1, 6, delta->trans->size + 1);
}
}
}
else
{
buffer->save(delta->trans->u.frame0, 12);
}
Utils::Stream::ClearPointer(&destDelta->trans);
}
if (delta->quat2)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->quat2, 4);
if (delta->quat2->size)
{
buffer->save(&delta->quat2->u.frames, 4);
if (framecount > 0xFF)
{
buffer->save(delta->quat2->u.frames.indices._1, 2, delta->quat2->size + 1);
}
else
{
buffer->save(delta->quat2->u.frames.indices._1, 1, delta->quat2->size + 1);
}
if (delta->quat2->u.frames.frames)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->quat2->u.frames.frames, 4, delta->quat2->size + 1);
}
}
else
{
buffer->save(delta->quat2->u.frame0, 4);
}
Utils::Stream::ClearPointer(&destDelta->quat2);
}
if (delta->quat)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->quat, 4);
if (delta->quat->size)
{
buffer->save(&delta->quat->u.frames, 4);
if (framecount > 0xFF)
{
buffer->save(delta->quat->u.frames.indices._1, 2, delta->quat->size + 1);
}
else
{
buffer->save(delta->quat->u.frames.indices._1, 1, delta->quat->size + 1);
}
if (delta->quat->u.frames.frames)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->quat->u.frames.frames, 4, delta->quat->size + 1);
}
}
else
{
buffer->save(delta->quat->u.frame0, 4);
}
Utils::Stream::ClearPointer(&destDelta->quat);
}
}
void IXAnimParts::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::XAnimParts, 88);
Utils::Stream* buffer = builder->getBuffer();
Game::XAnimParts* asset = header.parts;
Game::XAnimParts* dest = buffer->dest<Game::XAnimParts>();
buffer->save(asset, sizeof(Game::XAnimParts));
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->names)
{
buffer->align(Utils::Stream::ALIGN_2);
unsigned short* destTagnames = buffer->dest<unsigned short>();
buffer->saveArray(asset->names, asset->boneCount[Game::PART_TYPE_ALL]);
for (char i = 0; i < asset->boneCount[Game::PART_TYPE_ALL]; ++i)
{
builder->mapScriptString(destTagnames[i]);
}
Utils::Stream::ClearPointer(&dest->names);
}
if (asset->notify)
{
AssertSize(Game::XAnimNotifyInfo, 8);
buffer->align(Utils::Stream::ALIGN_4);
Game::XAnimNotifyInfo* destNotetracks = buffer->dest<Game::XAnimNotifyInfo>();
buffer->saveArray(asset->notify, asset->notifyCount);
for (char i = 0; i < asset->notifyCount; ++i)
{
builder->mapScriptString(destNotetracks[i].name);
}
Utils::Stream::ClearPointer(&dest->notify);
}
if (asset->deltaPart)
{
AssertSize(Game::XAnimDeltaPart, 12);
buffer->align(Utils::Stream::ALIGN_4);
this->saveXAnimDeltaPart(asset->deltaPart, asset->numframes, builder);
Utils::Stream::ClearPointer(&dest->deltaPart);
}
if (asset->dataByte)
{
buffer->saveArray(asset->dataByte, asset->dataByteCount);
Utils::Stream::ClearPointer(&dest->dataByte);
}
if (asset->dataShort)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->dataShort, asset->dataShortCount);
Utils::Stream::ClearPointer(&dest->dataShort);
}
if (asset->dataInt)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->dataInt, asset->dataIntCount);
Utils::Stream::ClearPointer(&dest->dataInt);
}
if (asset->randomDataShort)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->randomDataShort, asset->randomDataShortCount);
Utils::Stream::ClearPointer(&dest->randomDataShort);
}
if (asset->randomDataByte)
{
buffer->saveArray(asset->randomDataByte, asset->randomDataByteCount);
Utils::Stream::ClearPointer(&dest->randomDataByte);
}
if (asset->randomDataInt)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->randomDataInt, asset->randomDataIntCount);
Utils::Stream::ClearPointer(&dest->randomDataInt);
}
if (asset->indices.data)
{
if (asset->numframes > 0xFF)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->indices._2, asset->indexCount);
}
else
{
buffer->saveArray(asset->indices._1, asset->indexCount);
}
Utils::Stream::ClearPointer(&dest->indices.data);
}
buffer->popBlock();
}
}

View File

@ -1,17 +0,0 @@
#pragma once
namespace Assets
{
class IXAnimParts : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_XANIMPARTS; }
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
private:
void saveXAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,260 +0,0 @@
#include <STDInclude.hpp>
#include "IXModel.hpp"
namespace Assets
{
void IXModel::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->model = builder->getIW4OfApi()->read<Game::XModel>(Game::XAssetType::ASSET_TYPE_XMODEL, name);
if (header->model)
{
// ???
if (header->model->physCollmap)
{
Components::AssetHandler::StoreTemporaryAsset(Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP, { header->model->physCollmap });
}
if (header->model->physPreset)
{
Components::AssetHandler::StoreTemporaryAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, { header->model->physPreset });
}
for (size_t i = 0; i < header->model->numLods; i++)
{
const auto& info = header->model->lodInfo[i];
Components::AssetHandler::StoreTemporaryAsset(Game::XAssetType::ASSET_TYPE_XMODEL_SURFS, { info.modelSurfs });
}
}
}
void IXModel::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::XModel* asset = header.model;
if (asset->boneNames)
{
for (char i = 0; i < asset->numBones; ++i)
{
builder->addScriptString(asset->boneNames[i]);
}
}
if (asset->materialHandles)
{
for (unsigned char i = 0; i < asset->numsurfs; ++i)
{
if (asset->materialHandles[i])
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materialHandles[i]);
}
}
}
for (int i = 0; i < 4; ++i)
{
if (asset->lodInfo[i].modelSurfs)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL_SURFS, asset->lodInfo[i].modelSurfs);
}
}
if (asset->physPreset)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset);
}
if (asset->physCollmap)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP, asset->physCollmap);
}
}
void IXModel::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::XModel, 304);
Utils::Stream* buffer = builder->getBuffer();
Game::XModel* asset = header.model;
Game::XModel* dest = buffer->dest<Game::XModel>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->boneNames)
{
buffer->align(Utils::Stream::ALIGN_2);
unsigned short* destBoneNames = buffer->dest<unsigned short>();
buffer->saveArray(asset->boneNames, asset->numBones);
for (char i = 0; i < asset->numBones; ++i)
{
builder->mapScriptString(destBoneNames[i]);
}
Utils::Stream::ClearPointer(&dest->boneNames);
}
if (asset->parentList)
{
if (builder->hasPointer(asset->parentList))
{
dest->parentList = builder->getPointer(asset->parentList);
}
else
{
builder->storePointer(asset->parentList);
buffer->save(asset->parentList, asset->numBones - asset->numRootBones);
Utils::Stream::ClearPointer(&dest->parentList);
}
}
if (asset->quats)
{
if (builder->hasPointer(asset->quats))
{
dest->quats = builder->getPointer(asset->quats);
}
else
{
buffer->align(Utils::Stream::ALIGN_2);
builder->storePointer(asset->quats);
buffer->saveArray(asset->quats, (asset->numBones - asset->numRootBones) * 4);
Utils::Stream::ClearPointer(&dest->quats);
}
}
if (asset->trans)
{
if (builder->hasPointer(asset->trans))
{
dest->trans = builder->getPointer(asset->trans);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->trans);
buffer->saveArray(asset->trans, (asset->numBones - asset->numRootBones) * 3);
Utils::Stream::ClearPointer(&dest->trans);
}
}
if (asset->partClassification)
{
if (builder->hasPointer(asset->partClassification))
{
dest->partClassification = builder->getPointer(asset->partClassification);
}
else
{
builder->storePointer(asset->partClassification);
buffer->save(asset->partClassification, asset->numBones);
Utils::Stream::ClearPointer(&dest->partClassification);
}
}
if (asset->baseMat)
{
AssertSize(Game::DObjAnimMat, 32);
if (builder->hasPointer(asset->baseMat))
{
dest->baseMat = builder->getPointer(asset->baseMat);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->baseMat);
buffer->saveArray(asset->baseMat, asset->numBones);
Utils::Stream::ClearPointer(&dest->baseMat);
}
}
if (asset->materialHandles)
{
buffer->align(Utils::Stream::ALIGN_4);
Game::Material** destMaterials = buffer->dest<Game::Material*>();
buffer->saveArray(asset->materialHandles, asset->numsurfs);
for (unsigned char i = 0; i < asset->numsurfs; ++i)
{
if (asset->materialHandles[i])
{
destMaterials[i] = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->materialHandles[i]).material;
}
}
Utils::Stream::ClearPointer(&dest->materialHandles);
}
// Save_XModelLodInfoArray
{
AssertSize(Game::XModelLodInfo, 44);
for (int i = 0; i < 4; ++i)
{
if (asset->lodInfo[i].modelSurfs)
{
dest->lodInfo[i].modelSurfs = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL_SURFS, asset->lodInfo[i].modelSurfs).modelSurfs;
}
}
}
// Save_XModelCollSurfArray
if (asset->collSurfs)
{
AssertSize(Game::XModelCollSurf_s, 44);
buffer->align(Utils::Stream::ALIGN_4);
Game::XModelCollSurf_s* destColSurfs = buffer->dest<Game::XModelCollSurf_s>();
buffer->saveArray(asset->collSurfs, asset->numCollSurfs);
for (int i = 0; i < asset->numCollSurfs; ++i)
{
Game::XModelCollSurf_s* destCollSurf = &destColSurfs[i];
Game::XModelCollSurf_s* collSurf = &asset->collSurfs[i];
if (collSurf->collTris)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(collSurf->collTris, 48, collSurf->numCollTris);
Utils::Stream::ClearPointer(&destCollSurf->collTris);
}
}
Utils::Stream::ClearPointer(&dest->collSurfs);
}
if (asset->boneInfo)
{
AssertSize(Game::XBoneInfo, 28);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->boneInfo, asset->numBones);
Utils::Stream::ClearPointer(&dest->boneInfo);
}
if (asset->physPreset)
{
dest->physPreset = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->physPreset).physPreset;
}
if (asset->physCollmap)
{
dest->physCollmap = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP, asset->physCollmap).physCollmap;
}
buffer->popBlock();
}
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace Assets
{
class IXModel : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::ASSET_TYPE_XMODEL; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
};
}

View File

@ -1,167 +0,0 @@
#include <STDInclude.hpp>
#include "IXModelSurfs.hpp"
namespace Assets
{
void IXModelSurfs::saveXSurfaceCollisionTree(Game::XSurfaceCollisionTree* entry, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::XSurfaceCollisionTree, 40);
Utils::Stream* buffer = builder->getBuffer();
Game::XSurfaceCollisionTree* destEntry = buffer->dest<Game::XSurfaceCollisionTree>();
buffer->save(entry);
if (entry->nodes)
{
AssertSize(Game::XSurfaceCollisionNode, 16);
buffer->align(Utils::Stream::ALIGN_16);
buffer->saveArray(entry->nodes, entry->nodeCount);
Utils::Stream::ClearPointer(&destEntry->nodes);
}
if (entry->leafs)
{
AssertSize(Game::XSurfaceCollisionLeaf, 2);
buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(entry->leafs, entry->leafCount);
Utils::Stream::ClearPointer(&destEntry->leafs);
}
}
void IXModelSurfs::saveXSurface(Game::XSurface* surf, Game::XSurface* destSurf, Components::ZoneBuilder::Zone* builder)
{
Utils::Stream* buffer = builder->getBuffer();
if (surf->vertInfo.vertsBlend)
{
if (builder->hasPointer(surf->vertInfo.vertsBlend))
{
destSurf->vertInfo.vertsBlend = builder->getPointer(surf->vertInfo.vertsBlend);
}
else
{
buffer->align(Utils::Stream::ALIGN_2);
builder->storePointer(surf->vertInfo.vertsBlend);
buffer->saveArray(surf->vertInfo.vertsBlend, surf->vertInfo.vertCount[0] + (surf->vertInfo.vertCount[1] * 3) + (surf->vertInfo.vertCount[2] * 5) + (surf->vertInfo.vertCount[3] * 7));
Utils::Stream::ClearPointer(&destSurf->vertInfo.vertsBlend);
}
}
// Access vertex block
buffer->pushBlock(Game::XFILE_BLOCK_VERTEX);
if (surf->verts0)
{
AssertSize(Game::GfxPackedVertex, 32);
if (builder->hasPointer(surf->verts0))
{
destSurf->verts0 = builder->getPointer(surf->verts0);
}
else
{
buffer->align(Utils::Stream::ALIGN_16);
builder->storePointer(surf->verts0);
buffer->saveArray(surf->verts0, surf->vertCount);
Utils::Stream::ClearPointer(&destSurf->verts0);
}
}
buffer->popBlock();
// Save_XRigidVertListArray
if (surf->vertList)
{
AssertSize(Game::XRigidVertList, 12);
if (builder->hasPointer(surf->vertList))
{
destSurf->vertList = builder->getPointer(surf->vertList);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(surf->vertList);
Game::XRigidVertList* destCt = buffer->dest<Game::XRigidVertList>();
buffer->saveArray(surf->vertList, surf->vertListCount);
for (unsigned int i = 0; i < surf->vertListCount; ++i)
{
Game::XRigidVertList* destRigidVertList = &destCt[i];
Game::XRigidVertList* rigidVertList = &surf->vertList[i];
if (rigidVertList->collisionTree)
{
if (builder->hasPointer(rigidVertList->collisionTree))
{
destRigidVertList->collisionTree = builder->getPointer(rigidVertList->collisionTree);
}
else {
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(rigidVertList->collisionTree);
this->saveXSurfaceCollisionTree(rigidVertList->collisionTree, builder);
Utils::Stream::ClearPointer(&destRigidVertList->collisionTree);
}
}
}
Utils::Stream::ClearPointer(&destSurf->vertList);
}
}
// Access index block
buffer->pushBlock(Game::XFILE_BLOCK_INDEX);
if (builder->hasPointer(surf->triIndices))
{
destSurf->triIndices = builder->getPointer(surf->triIndices);
}
else
{
buffer->align(Utils::Stream::ALIGN_16);
builder->storePointer(surf->triIndices);
buffer->saveArray(surf->triIndices, surf->triCount * 3);
Utils::Stream::ClearPointer(&destSurf->triIndices);
}
buffer->popBlock();
}
void IXModelSurfs::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::XModelSurfs, 36);
Utils::Stream* buffer = builder->getBuffer();
Game::XModelSurfs* asset = header.modelSurfs;
Game::XModelSurfs* dest = buffer->dest<Game::XModelSurfs>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->surfs)
{
AssertSize(Game::XSurface, 64);
buffer->align(Utils::Stream::ALIGN_4);
Game::XSurface* destSurfaces = buffer->dest<Game::XSurface>();
buffer->saveArray(asset->surfs, asset->numsurfs);
for (int i = 0; i < asset->numsurfs; ++i)
{
this->saveXSurface(&asset->surfs[i], &destSurfaces[i], builder);
}
Utils::Stream::ClearPointer(&dest->surfs);
}
buffer->popBlock();
}
}

View File

@ -1,16 +0,0 @@
#pragma once
namespace Assets
{
class IXModelSurfs : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::ASSET_TYPE_XMODEL_SURFS; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
private:
void saveXSurface(Game::XSurface* surf, Game::XSurface* destSurf, Components::ZoneBuilder::Zone* builder);
void saveXSurfaceCollisionTree(Game::XSurfaceCollisionTree* entry, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,585 +0,0 @@
#include <STDInclude.hpp>
#include "IclipMap_t.hpp"
namespace Assets
{
void IclipMap_t::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::clipMap_t, 256);
SaveLogEnter("clipMap_t");
Utils::Stream* buffer = builder->getBuffer();
Game::clipMap_t* asset = header.clipMap;
Game::clipMap_t* dest = buffer->dest<Game::clipMap_t>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name)
{
buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name);
}
if (asset->planes)
{
AssertSize(Game::cplane_s, 20);
SaveLogEnter("cplane_t");
if (builder->hasPointer(asset->planes))
{
dest->planes = builder->getPointer(asset->planes);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
// not sure if this is needed but both brushside and brushedge need it and it can't hurt
for (size_t i = 0; i < asset->planeCount; ++i)
{
builder->storePointer(&asset->planes[i]);
buffer->save(&asset->planes[i]);
}
Utils::Stream::ClearPointer(&dest->planes);
}
SaveLogExit();
}
if (asset->staticModelList)
{
AssertSize(Game::cStaticModel_s, 76);
SaveLogEnter("cStaticModel_t");
// xmodel is already stored
buffer->align(Utils::Stream::ALIGN_4);
Game::cStaticModel_s* destStaticModelList = buffer->dest<Game::cStaticModel_s>();
buffer->saveArray(asset->staticModelList, asset->numStaticModels);
for (unsigned int i = 0; i < asset->numStaticModels; ++i)
{
if (asset->staticModelList[i].xmodel)
{
destStaticModelList[i].xmodel = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, asset->staticModelList[i].xmodel).model;
}
}
Utils::Stream::ClearPointer(&dest->staticModelList);
SaveLogExit();
}
if (asset->materials)
{
AssertSize(Game::ClipMaterial, 12);
SaveLogEnter("ClipMaterial");
buffer->align(Utils::Stream::ALIGN_4);
Game::ClipMaterial* mats = buffer->dest<Game::ClipMaterial>();
buffer->saveArray(asset->materials, asset->numMaterials);
for (unsigned int i = 0; i < asset->numMaterials; ++i)
{
buffer->saveString(asset->materials[i].name);
Utils::Stream::ClearPointer(&mats[i].name);
}
Utils::Stream::ClearPointer(&dest->materials);
SaveLogExit();
}
if (asset->brushsides)
{
AssertSize(Game::cbrushside_t, 8);
SaveLogEnter("cbrushside_t");
buffer->align(Utils::Stream::ALIGN_4);
Game::cbrushside_t* sides = buffer->dest<Game::cbrushside_t>();
// we need the pointer to each of these to be stored so we can't write them all at once
for (unsigned int i = 0; i < asset->numBrushSides; ++i)
{
builder->storePointer(&asset->brushsides[i]); // for reference in cBrush
buffer->save(&asset->brushsides[i]);
}
for (unsigned int i = 0; i < asset->numBrushSides; ++i)
{
if (sides[i].plane)
{
AssertSize(Game::cplane_s, 20);
if (builder->hasPointer(sides[i].plane))
{
sides[i].plane = builder->getPointer(sides[i].plane);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(sides[i].plane);
buffer->save(sides[i].plane);
Utils::Stream::ClearPointer(&sides[i].plane);
}
}
}
Utils::Stream::ClearPointer(&dest->brushsides);
SaveLogExit();
}
if (asset->brushEdges)
{
SaveLogEnter("cBrushEdge");
// no align for char
for (unsigned int i = 0; i < asset->numBrushEdges; ++i)
{
builder->storePointer(&asset->brushEdges[i]); // for reference in cBrush
buffer->save(&asset->brushEdges[i]);
}
Utils::Stream::ClearPointer(&dest->brushEdges);
SaveLogExit();
}
if (asset->nodes)
{
AssertSize(Game::cNode_t, 8);
SaveLogEnter("cNode_t");
buffer->align(Utils::Stream::ALIGN_4);
Game::cNode_t* nodes = buffer->dest<Game::cNode_t>();
buffer->saveArray(asset->nodes, asset->numNodes);
for (unsigned int i = 0; i < asset->numNodes; ++i)
{
if (nodes[i].plane)
{
if (builder->hasPointer(nodes[i].plane))
{
nodes[i].plane = builder->getPointer(nodes[i].plane);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(nodes[i].plane);
buffer->save(nodes[i].plane);
Utils::Stream::ClearPointer(&nodes[i].plane);
}
}
else
{
AssertUnreachable;
Components::Logger::Error(Game::ERR_FATAL, "node {} of clipmap {} has no plane!", i, asset->name);
}
}
Utils::Stream::ClearPointer(&dest->nodes);
SaveLogExit();
}
if (asset->leafs)
{
AssertSize(Game::cLeaf_t, 40);
SaveLogEnter("cLeaf_t");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->leafs, asset->numLeafs);
Utils::Stream::ClearPointer(&dest->leafs);
SaveLogExit();
}
if (asset->leafbrushes)
{
SaveLogEnter("cLeafBrush_t");
buffer->align(Utils::Stream::ALIGN_2);
for (size_t i = 0; i < asset->numLeafBrushes; i++)
{
builder->storePointer(&asset->leafbrushes[i]);
buffer->saveObject(asset->leafbrushes[i]);
}
Utils::Stream::ClearPointer(&dest->leafbrushes);
SaveLogExit();
}
if (asset->leafbrushNodes)
{
AssertSize(Game::cLeafBrushNode_s, 20);
SaveLogEnter("cLeafBrushNode_t");
buffer->align(Utils::Stream::ALIGN_4);
Game::cLeafBrushNode_s* node = buffer->dest<Game::cLeafBrushNode_s>();
buffer->saveArray(asset->leafbrushNodes, asset->leafbrushNodesCount);
for (unsigned int i = 0; i < asset->leafbrushNodesCount; ++i)
{
if (node[i].leafBrushCount > 0)
{
if (node[i].data.leaf.brushes)
{
if (builder->hasPointer(node[i].data.leaf.brushes))
{
node[i].data.leaf.brushes = builder->getPointer(node[i].data.leaf.brushes);
}
else
{
buffer->align(Utils::Stream::ALIGN_2);
for (short j = 0; j < node[i].leafBrushCount; ++j)
{
builder->storePointer(&node[i].data.leaf.brushes[j]);
buffer->save(&node[i].data.leaf.brushes[j]);
}
Utils::Stream::ClearPointer(&node[i].data.leaf.brushes);
}
}
}
}
Utils::Stream::ClearPointer(&dest->leafbrushNodes);
SaveLogExit();
}
if (asset->leafsurfaces)
{
SaveLogEnter("cLeafSurface_t");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->leafsurfaces, asset->numLeafSurfaces);
Utils::Stream::ClearPointer(&dest->leafsurfaces);
SaveLogExit();
}
if (asset->verts)
{
AssertSize(Game::vec3_t, 12);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->verts, asset->vertCount);
Utils::Stream::ClearPointer(&dest->verts);
}
if (asset->triIndices)
{
buffer->align(Utils::Stream::ALIGN_2);
buffer->save(asset->triIndices, 6, asset->triCount);
Utils::Stream::ClearPointer(&dest->triIndices);
}
if (asset->triEdgeIsWalkable)
{
// no align for char
buffer->save(asset->triEdgeIsWalkable, 1, 4 * ((3 * asset->triCount + 31) >> 5));
Utils::Stream::ClearPointer(&dest->triEdgeIsWalkable);
}
if (asset->borders)
{
AssertSize(Game::CollisionBorder, 28);
SaveLogEnter("CollisionBorder");
buffer->align(Utils::Stream::ALIGN_4);
for (size_t i = 0; i < asset->borderCount; ++i)
{
builder->storePointer(&asset->borders[i]);
buffer->save(&asset->borders[i]);
}
Utils::Stream::ClearPointer(&dest->borders);
SaveLogExit();
}
if (asset->partitions)
{
AssertSize(Game::CollisionPartition, 12);
SaveLogEnter("CollisionPartition");
buffer->align(Utils::Stream::ALIGN_4);
Game::CollisionPartition* destPartitions = buffer->dest<Game::CollisionPartition>();
buffer->saveArray(asset->partitions, asset->partitionCount);
for (int i = 0; i < asset->partitionCount; ++i)
{
Game::CollisionPartition* destPartition = &destPartitions[i];
Game::CollisionPartition* partition = &asset->partitions[i];
if (partition->borders)
{
if (builder->hasPointer(partition->borders))
{
destPartition->borders = builder->getPointer(partition->borders);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(partition->borders);
buffer->save(partition->borders);
Utils::Stream::ClearPointer(&destPartition->borders);
}
}
}
Utils::Stream::ClearPointer(&dest->partitions);
SaveLogExit();
}
if (asset->aabbTrees)
{
AssertSize(Game::CollisionAabbTree, 32);
SaveLogEnter("CollisionAabbTree");
buffer->align(Utils::Stream::ALIGN_16);
buffer->saveArray(asset->aabbTrees, asset->aabbTreeCount);
Utils::Stream::ClearPointer(&dest->aabbTrees);
SaveLogExit();
}
if (asset->cmodels)
{
AssertSize(Game::cmodel_t, 68);
SaveLogEnter("cmodel_t");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->cmodels, asset->numSubModels);
Utils::Stream::ClearPointer(&dest->cmodels);
SaveLogExit();
}
if (asset->brushes)
{
AssertSize(Game::cbrush_t, 36);
SaveLogEnter("cbrush_t");
buffer->align(Utils::Stream::ALIGN_128);
Game::cbrush_t* destBrushes = buffer->dest<Game::cbrush_t>();
buffer->saveArray(asset->brushes, asset->numBrushes);
for (short i = 0; i < asset->numBrushes; ++i)
{
Game::cbrush_t* destBrush = &destBrushes[i];
Game::cbrush_t* brush = &asset->brushes[i];
if (brush->sides)
{
if (builder->hasPointer(brush->sides))
{
destBrush->sides = builder->getPointer(brush->sides);
}
else
{
AssertSize(Game::cbrushside_t, 8);
MessageBoxA(nullptr, "BrushSide shouldn't be written in cBrush!", "WARNING", MB_ICONEXCLAMATION);
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(brush->sides);
Game::cbrushside_t* side = buffer->dest<Game::cbrushside_t>();
buffer->save(brush->sides);
if (brush->sides->plane)
{
if (builder->hasPointer(brush->sides->plane))
{
side->plane = builder->getPointer(brush->sides->plane);
}
else
{
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(brush->sides->plane);
buffer->save(brush->sides->plane);
Utils::Stream::ClearPointer(&side->plane);
}
}
Utils::Stream::ClearPointer(&destBrush->sides);
}
}
if (brush->baseAdjacentSide)
{
if (builder->hasPointer(brush->baseAdjacentSide))
{
destBrush->baseAdjacentSide = builder->getPointer(brush->baseAdjacentSide);
}
else
{
builder->storePointer(brush->baseAdjacentSide);
buffer->save(brush->baseAdjacentSide);
Utils::Stream::ClearPointer(&destBrush->baseAdjacentSide);
}
}
}
Utils::Stream::ClearPointer(&dest->brushes);
SaveLogExit();
}
if (asset->brushBounds)
{
AssertSize(Game::Bounds, 24);
SaveLogEnter("Bounds");
buffer->align(Utils::Stream::ALIGN_128);
buffer->saveArray(asset->brushBounds, asset->numBrushes);
Utils::Stream::ClearPointer(&dest->brushBounds);
SaveLogExit();
}
if (asset->brushContents)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->brushContents, asset->numBrushes);
Utils::Stream::ClearPointer(&dest->brushContents);
}
if (asset->smodelNodes)
{
AssertSize(Game::SModelAabbNode, 28);
SaveLogEnter("SModelAabbNode");
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->smodelNodes, asset->smodelNodeCount);
Utils::Stream::ClearPointer(&dest->smodelNodes);
SaveLogExit();
}
if (asset->mapEnts)
{
dest->mapEnts = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MAP_ENTS, asset->mapEnts).mapEnts;
}
for (int i = 0; i < 2; ++i)
{
if (asset->dynEntDefList[i])
{
AssertSize(Game::DynEntityDef, 92);
buffer->align(Utils::Stream::ALIGN_4);
Game::DynEntityDef* dynEntDest = buffer->dest<Game::DynEntityDef>();
buffer->saveArray(asset->dynEntDefList[i], asset->dynEntCount[i]);
Game::DynEntityDef* dynEnt = asset->dynEntDefList[i];
for (int j = 0; j < asset->dynEntCount[i]; ++j)
{
if (dynEnt[j].xModel)
{
dynEntDest[j].xModel = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_XMODEL, dynEnt[j].xModel).model;
}
if (dynEnt[j].destroyFx)
{
dynEntDest[j].destroyFx = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_FX, dynEnt[j].destroyFx).fx;
}
if (dynEnt[j].physPreset)
{
dynEntDest[j].physPreset = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, dynEnt[j].physPreset).physPreset;
}
}
Utils::Stream::ClearPointer(&dest->dynEntDefList[i]);
}
}
buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME);
for (int i = 0; i < 2; ++i)
{
if (asset->dynEntPoseList[i])
{
AssertSize(Game::DynEntityPose, 32);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->dynEntPoseList[i], asset->dynEntCount[i]);
Utils::Stream::ClearPointer(&dest->dynEntPoseList[i]);
}
}
for (int i = 0; i < 2; ++i)
{
if (asset->dynEntClientList[i])
{
AssertSize(Game::DynEntityClient, 12);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->dynEntClientList[i], asset->dynEntCount[i]);
Utils::Stream::ClearPointer(&dest->dynEntClientList[i]);
}
}
for (int i = 0; i < 2; ++i)
{
if (asset->dynEntCollList[i])
{
AssertSize(Game::DynEntityColl, 20);
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->dynEntCollList[i], asset->dynEntCount[i]);
Utils::Stream::ClearPointer(&dest->dynEntCollList[i]);
}
}
buffer->popBlock();
buffer->popBlock();
SaveLogExit();
}
void IclipMap_t::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::clipMap_t* asset = header.clipMap;
for (unsigned int i = 0; i < asset->numStaticModels; ++i)
{
Game::XModel* m = asset->staticModelList[i].xmodel;
if (m)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, m);
}
}
for (int j = 0; j < 2; ++j)
{
Game::DynEntityDef* def = asset->dynEntDefList[j];
for (int i = 0; i < asset->dynEntCount[j]; ++i)
{
if (def[i].xModel)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, def[i].xModel);
}
if (def[i].destroyFx)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, def[i].destroyFx);
}
if (def[i].physPreset)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, def[i].physPreset);
}
}
}
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MAP_ENTS, asset->mapEnts);
}
void IclipMap_t::load(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder)
{
header->clipMap = builder->getIW4OfApi()->read<Game::clipMap_t>(Game::XAssetType::ASSET_TYPE_CLIPMAP_MP, _name);
assert(header->data);
}
}

View File

@ -1,94 +0,0 @@
#pragma once
namespace Assets
{
class IclipMap_t : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_CLIPMAP_MP; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
static void dump(Game::XAssetHeader /*header*/);
private:
class SModelQuadtree
{
public:
SModelQuadtree()
{
}
SModelQuadtree(Game::cStaticModel_s* modelList, int numModels)
{
numValues = 0;
for (int i = 0; i < numModels; ++i)
{
insert(&modelList[i]);
}
}
void insert(Game::cStaticModel_s* item)
{
if (numValues < 4) // add here
{
values[numValues++] = item;
}
else // add to child
{
if (numValues == 4) // split
{
// create children objects
for (int i = 0; i < 4; ++i)
{
children[i] = new SModelQuadtree();
}
for (int i = 0; i < numValues; ++i)
{
if (item->origin[0] > x && values[i]->origin[1] > y)
children[0]->insert(values[i]);
if (item->origin[0] < x && values[i]->origin[1] > y)
children[1]->insert(values[i]);
if (item->origin[0] < x && values[i]->origin[1] < y)
children[2]->insert(values[i]);
if (item->origin[0] > x && values[i]->origin[1] < y)
children[3]->insert(values[i]);
values[i] = nullptr;
}
for (int i = 0; i < 4; ++i)
{
children[i]->halfX = halfX / 2;
children[i]->halfY = halfY / 2;
children[i]->halfZ = halfZ;
}
// update origins here
numValues++;
}
if (item->origin[0] > x && item->origin[1] > y)
children[0]->insert(item);
if (item->origin[0] < x && item->origin[1] > y)
children[1]->insert(item);
if (item->origin[0] < x && item->origin[1] < y)
children[2]->insert(item);
if (item->origin[0] > x && item->origin[1] < y)
children[3]->insert(item);
}
}
private:
SModelQuadtree* children[4];
Game::cStaticModel_s* values[4];
int numValues;
float x, y, z;
float halfX, halfY, halfZ;
};
};
}

View File

@ -1,700 +0,0 @@
#include <STDInclude.hpp>
#include "ImenuDef_t.hpp"
namespace Assets
{
std::unordered_map<std::string, Game::menuDef_t*> ImenuDef_t::LoadedMenus;
void ImenuDef_t::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
{
// load from disk
auto menus = Components::Menus::LoadMenu(std::format("ui_mp/{}.menu", name));
if (menus.empty()) return;
if (menus.size() > 1) Components::Logger::Print("Menu '{}' on disk has more than one menudef in it. Only saving the first one\n", name);
header->menu = menus[0].second;
}
void ImenuDef_t::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
auto* asset = header.menu;
if (asset->window.background)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->window.background);
}
// mark items
for (int i = 0; i < asset->itemCount; ++i)
{
if (asset->items[i]->window.background)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->items[i]->window.background);
}
if (asset->items[i]->focusSound)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_SOUND, asset->items[i]->focusSound);
}
if (asset->items[i]->type == 6 && asset->items[i]->typeData.listBox &&
asset->items[i]->typeData.listBox->selectIcon)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->items[i]->typeData.listBox->selectIcon);
}
}
}
void ImenuDef_t::save_ExpressionSupportingData(Game::ExpressionSupportingData* asset, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::ExpressionSupportingData, 24);
Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS
buffer->enterStruct("ExpressionSupportingData");
#endif
buffer->align(Utils::Stream::ALIGN_4);
auto* dest = buffer->dest<Game::ExpressionSupportingData>();
buffer->save(asset);
if (asset->uifunctions.functions)
{
buffer->align(Utils::Stream::ALIGN_4);
auto** destStatement = buffer->dest<Game::Statement_s*>();
buffer->saveArray(asset->uifunctions.functions, asset->uifunctions.totalFunctions);
for (int i = 0; i < asset->uifunctions.totalFunctions; ++i)
{
if (asset->uifunctions.functions[i])
{
Utils::Stream::ClearPointer(&destStatement[i]);
buffer->align(Utils::Stream::ALIGN_4);
this->save_Statement_s(asset->uifunctions.functions[i], builder);
}
}
Utils::Stream::ClearPointer(&dest->uifunctions.functions);
}
if (asset->staticDvarList.staticDvars)
{
buffer->align(Utils::Stream::ALIGN_4);
auto** destStaticDvars = buffer->dest<Game::StaticDvar*>();
buffer->saveArray(asset->staticDvarList.staticDvars, asset->staticDvarList.numStaticDvars);
for (auto i = 0; i < asset->staticDvarList.numStaticDvars; ++i)
{
if (asset->staticDvarList.staticDvars[i])
{
Utils::Stream::ClearPointer(&destStaticDvars[i]);
buffer->align(Utils::Stream::ALIGN_4);
auto* destStaticDvar = buffer->dest<Game::StaticDvar>();
buffer->save(asset->staticDvarList.staticDvars[i]);
if (asset->staticDvarList.staticDvars[i]->dvarName)
{
buffer->saveString(asset->staticDvarList.staticDvars[i]->dvarName);
Utils::Stream::ClearPointer(&destStaticDvar->dvarName);
}
}
}
Utils::Stream::ClearPointer(&dest->staticDvarList.staticDvars);
}
if (asset->uiStrings.strings)
{
buffer->align(Utils::Stream::ALIGN_4);
const auto** destUIStrings = buffer->dest<const char*>();
buffer->saveArray(asset->uiStrings.strings, asset->uiStrings.totalStrings);
for (int i = 0; i < asset->uiStrings.totalStrings; ++i)
{
if (asset->uiStrings.strings[i])
{
buffer->saveString(asset->uiStrings.strings[i]);
Utils::Stream::ClearPointer(&destUIStrings[i]);
}
}
}
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
void ImenuDef_t::save_Statement_s(Game::Statement_s* asset, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::Statement_s, 24);
AssertSize(Game::expressionEntry, 12);
Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS
buffer->enterStruct("Statement_s");
#endif
// Write header data
auto* dest = buffer->dest<Game::Statement_s>();
buffer->save(asset);
// Write statement entries
if (asset->entries)
{
#ifdef WRITE_LOGS
buffer->enterStruct("statement entries");
#endif
buffer->align(Utils::Stream::ALIGN_4);
// Write entries
auto* destEntries = buffer->dest<Game::expressionEntry>();
buffer->save(asset->entries, sizeof(Game::expressionEntry), asset->numEntries);
// Loop through entries
for (int i = 0; i < asset->numEntries; ++i)
{
#ifdef WRITE_LOGS
buffer->enterStruct("entry");
#endif
if (asset->entries[i].type)
{
switch (asset->entries[i].data.operand.dataType)
{
// Those types do not require additional data
case 0:
case 1:
break;
// Expression string
case 2:
if (asset->entries[i].data.operand.internals.stringVal.string)
{
buffer->saveString(asset->entries[i].data.operand.internals.stringVal.string);
Utils::Stream::ClearPointer(&destEntries[i].data.operand.internals.stringVal.string);
}
break;
// Function
case 3:
if (asset->entries[i].data.operand.internals.function)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_Statement_s(asset->entries[i].data.operand.internals.function, builder);
Utils::Stream::ClearPointer(&destEntries[i].data.operand.internals.function);
}
break;
}
}
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
if (asset->supportingData)
{
this->save_ExpressionSupportingData(asset->supportingData, builder);
Utils::Stream::ClearPointer(&dest->supportingData);
}
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
void ImenuDef_t::save_MenuEventHandlerSet(Game::MenuEventHandlerSet* asset, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::MenuEventHandlerSet, 8);
Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS
buffer->enterStruct("MenuEventHandlerSet");
#endif
// Write header data
auto* destset = buffer->dest<Game::MenuEventHandlerSet>();
buffer->save(asset);
// Event handlers
if (asset->eventHandlers)
{
buffer->align(Utils::Stream::ALIGN_4);
// Write pointers to zone
buffer->save(asset->eventHandlers, sizeof(Game::MenuEventHandler*), asset->eventHandlerCount);
// Loop through eventHandlers
for (auto i = 0; i < asset->eventHandlerCount; ++i)
{
if (asset->eventHandlers[i])
{
buffer->align(Utils::Stream::ALIGN_4);
#ifdef WRITE_LOGS
buffer->enterStruct("MenuEventHandler");
#endif
// Write menu event handler
auto* dest = buffer->dest<Game::MenuEventHandler>();
buffer->save(asset->eventHandlers[i]);
// Write additional data based on type
switch (asset->eventHandlers[i]->eventType)
{
// unconditional scripts
case 0:
if (asset->eventHandlers[i]->eventData.unconditionalScript)
{
buffer->saveString(asset->eventHandlers[i]->eventData.unconditionalScript);
Utils::Stream::ClearPointer(&dest->eventData.unconditionalScript);
}
break;
// ConditionalScript
case 1:
if (asset->eventHandlers[i]->eventData.conditionalScript)
{
buffer->align(Utils::Stream::ALIGN_4);
auto* destConditionalScript = buffer->dest<Game::ConditionalScript>();
buffer->save(asset->eventHandlers[i]->eventData.conditionalScript);
// eventExpression
if (asset->eventHandlers[i]->eventData.conditionalScript->eventExpression)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_Statement_s(asset->eventHandlers[i]->eventData.conditionalScript->eventExpression, builder);
Utils::Stream::ClearPointer(&destConditionalScript->eventExpression);
}
// eventHandlerSet
if (asset->eventHandlers[i]->eventData.conditionalScript->eventHandlerSet)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_MenuEventHandlerSet(asset->eventHandlers[i]->eventData.conditionalScript->eventHandlerSet, builder);
Utils::Stream::ClearPointer(&destConditionalScript->eventHandlerSet);
}
Utils::Stream::ClearPointer(&dest->eventData.conditionalScript);
}
break;
// elseScript
case 2:
if (asset->eventHandlers[i]->eventData.elseScript)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_MenuEventHandlerSet(asset->eventHandlers[i]->eventData.elseScript, builder);
Utils::Stream::ClearPointer(&dest->eventData.elseScript);
}
break;
// localVarData expressions
case 3:
case 4:
case 5:
case 6:
if (asset->eventHandlers[i]->eventData.setLocalVarData)
{
buffer->align(Utils::Stream::ALIGN_4);
// header data
auto* destLocalVarData = buffer->dest<Game::SetLocalVarData>();
buffer->save(asset->eventHandlers[i]->eventData.setLocalVarData);
// localVarName
if (asset->eventHandlers[i]->eventData.setLocalVarData->localVarName)
{
buffer->saveString(asset->eventHandlers[i]->eventData.setLocalVarData->localVarName);
Utils::Stream::ClearPointer(&destLocalVarData->localVarName);
}
// statement
if (asset->eventHandlers[i]->eventData.setLocalVarData->expression)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_Statement_s(asset->eventHandlers[i]->eventData.setLocalVarData->expression, builder);
Utils::Stream::ClearPointer(&destLocalVarData->expression);
}
Utils::Stream::ClearPointer(&dest->eventData.setLocalVarData);
}
break;
}
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
}
Utils::Stream::ClearPointer(&destset->eventHandlers);
}
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
void ImenuDef_t::save_ItemKeyHandler(Game::ItemKeyHandler* asset, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::ItemKeyHandler, 12);
Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS
buffer->enterStruct("ItemKeyHandler");
#endif
while (asset)
{
// Write header
auto* dest = buffer->dest<Game::ItemKeyHandler>();
buffer->save(asset);
// MenuEventHandlerSet
if (asset->action)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_MenuEventHandlerSet(asset->action, builder);
Utils::Stream::ClearPointer(&dest->action);
}
if (asset->next)
{
// align every index, besides the first one?
buffer->align(Utils::Stream::ALIGN_4);
}
// Next key handler
asset = asset->next;
}
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
#define EVENTHANDLERSET(__index) \
if (asset->__index) \
{ \
buffer->align(Utils::Stream::ALIGN_4); \
this->save_MenuEventHandlerSet(asset->__index, builder); \
Utils::Stream::ClearPointer(&dest->__index); \
}
#define STATEMENT(__index) \
if (asset->__index) \
{ \
buffer->align(Utils::Stream::ALIGN_4); \
this->save_Statement_s(asset->__index, builder); \
Utils::Stream::ClearPointer(&dest->__index); \
}
void ImenuDef_t::save_itemDefData_t(Game::itemDefData_t* asset, int type, Game::itemDef_s* dest, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::newsTickerDef_s, 28);
AssertSize(Game::listBoxDef_s, 324);
AssertSize(Game::editFieldDef_s, 32);
AssertSize(Game::multiDef_s, 392);
Utils::Stream* buffer = builder->getBuffer();
#ifdef WRITE_LOGS
buffer->enterStruct("itemDefData_t");
#endif
// feeder
if (type == 6)
{
buffer->align(Utils::Stream::ALIGN_4);
auto* destlb = buffer->dest<Game::listBoxDef_s>();
buffer->save(asset->listBox);
if (asset->listBox->onDoubleClick)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_MenuEventHandlerSet(asset->listBox->onDoubleClick, builder);
}
if (asset->listBox->selectIcon)
{
destlb->selectIcon = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->listBox->selectIcon).material;
}
}
// HexRays spaghetti
else if (type != 4 && type != 9 && type != 16 && type != 18 && type != 11 && type != 14 && type != 10 && type != 17 && type != 22 && type != 23 && type != 0)
{
switch (type)
{
// enum dvar
case 13:
buffer->saveString(asset->enumDvarName);
break;
// newsticker
case 20:
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->ticker);
break;
// textScrollDef
case 21:
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->scroll);
break;
case 12:
buffer->align(Utils::Stream::ALIGN_4);
auto* destdef = buffer->dest<Game::multiDef_s>();
buffer->save(asset->multi);
for (int i = 0; i < 32; ++i)
{
if (asset->multi->dvarList[i])
{
buffer->saveString(asset->multi->dvarList[i]);
Utils::Stream::ClearPointer(&destdef->dvarList[i]);
}
}
for (int i = 0; i < 32; ++i)
{
if (asset->multi->dvarStr[i])
{
buffer->saveString(asset->multi->dvarStr[i]);
Utils::Stream::ClearPointer(&destdef->dvarStr[i]);
}
}
break;
}
}
// editFieldDef
else
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->save(asset->editField);
}
Utils::Stream::ClearPointer(&dest->typeData.data);
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
void ImenuDef_t::save_itemDef_s(Game::itemDef_s *asset, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::itemDef_s, 0x17C);
Utils::Stream* buffer = builder->getBuffer();
auto* dest = buffer->dest<Game::itemDef_s>();
#ifdef WRITE_LOGS
if (asset->window.name)
buffer->enterStruct(Utils::String::VA("itemDef_s: name = '%s'", asset->window.name));
else if (asset->window.background)
buffer->enterStruct(Utils::String::VA("itemDef_s: bg = '%s'", asset->window.background->info.name));
else
buffer->enterStruct("itemDef_s");
#endif
buffer->save(asset);
// window data
save_windowDef_t<Game::itemDef_s>(&asset->window, dest, builder);
// text
if (asset->text)
{
buffer->saveString(asset->text);
Utils::Stream::ClearPointer(&dest->text);
}
// MenuEventHandlerSets
EVENTHANDLERSET(mouseEnterText);
EVENTHANDLERSET(mouseExitText);
EVENTHANDLERSET(mouseEnter);
EVENTHANDLERSET(mouseExit);
EVENTHANDLERSET(action);
EVENTHANDLERSET(accept);
EVENTHANDLERSET(onFocus);
EVENTHANDLERSET(leaveFocus);
// Dvar strings
if (asset->dvar)
{
buffer->saveString(asset->dvar);
Utils::Stream::ClearPointer(&dest->dvar);
}
if (asset->dvarTest)
{
buffer->saveString(asset->dvarTest);
Utils::Stream::ClearPointer(&dest->dvarTest);
}
// ItemKeyHandler
if (asset->onKey)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_ItemKeyHandler(asset->onKey, builder);
Utils::Stream::ClearPointer(&dest->onKey);
}
// Dvar strings
if (asset->enableDvar)
{
buffer->saveString(asset->enableDvar);
Utils::Stream::ClearPointer(&dest->enableDvar);
}
if (asset->localVar)
{
buffer->saveString(asset->localVar);
Utils::Stream::ClearPointer(&dest->localVar);
}
// Focus sound
if (asset->focusSound)
{
dest->focusSound = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_SOUND, asset->focusSound).sound;
}
// itemDefData
if (asset->typeData.data)
{
this->save_itemDefData_t(&asset->typeData, asset->type, dest, builder);
}
// floatExpressions
if (asset->floatExpressions)
{
buffer->align(Utils::Stream::ALIGN_4);
#ifdef WRITE_LOGS
buffer->enterStruct("floatExpressions");
#endif
auto* destExp = buffer->dest<Game::ItemFloatExpression>();
buffer->saveArray(asset->floatExpressions, asset->floatExpressionCount);
for (int i = 0; i < asset->floatExpressionCount; ++i)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_Statement_s(asset->floatExpressions[i].expression, builder);
Utils::Stream::ClearPointer(&destExp[i].expression);
}
Utils::Stream::ClearPointer(&dest->floatExpressions);
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
// Statements
STATEMENT(visibleExp);
STATEMENT(disabledExp);
STATEMENT(textExp);
STATEMENT(materialExp);
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
}
void ImenuDef_t::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::menuDef_t, 400);
AssertSize(Game::windowDef_t, 0xA4);
#ifdef WRITE_LOGS
buffer->enterStruct("ImenuDef_t");
#endif
Utils::Stream* buffer = builder->getBuffer();
auto* asset = header.menu;
auto* dest = buffer->dest<Game::menuDef_t>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
// ExpressionSupportingData
if (asset->expressionData)
{
// dest->expressionData = nullptr;
this->save_ExpressionSupportingData(asset->expressionData, builder);
Utils::Stream::ClearPointer(&dest->expressionData);
}
// Window data
save_windowDef_t<Game::menuDef_t>(&asset->window, dest, builder);
// Font
if (asset->font)
{
buffer->saveString(asset->font);
Utils::Stream::ClearPointer(&dest->font);
}
// MenuEventHandlerSets
EVENTHANDLERSET(onOpen);
EVENTHANDLERSET(onCloseRequest);
EVENTHANDLERSET(onClose);
EVENTHANDLERSET(onESC);
// ItemKeyHandler
if (asset->onKey)
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_ItemKeyHandler(asset->onKey, builder);
Utils::Stream::ClearPointer(&dest->onKey);
}
// Statement
STATEMENT(visibleExp);
// Strings
if (asset->allowedBinding)
{
buffer->saveString(asset->allowedBinding);
Utils::Stream::ClearPointer(&dest->allowedBinding);
}
if (asset->soundName)
{
buffer->saveString(asset->soundName);
Utils::Stream::ClearPointer(&dest->soundName);
}
// Statements
STATEMENT(rectXExp);
STATEMENT(rectYExp);
STATEMENT(rectHExp);
STATEMENT(rectWExp);
STATEMENT(openSoundExp);
STATEMENT(closeSoundExp);
// Items
if (asset->items)
{
buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->items, asset->itemCount);
for (int i = 0; i < asset->itemCount; ++i)
{
if (asset->items[i])
{
buffer->align(Utils::Stream::ALIGN_4);
this->save_itemDef_s(asset->items[i], builder);
}
}
}
#ifdef WRITE_LOGS
buffer->leaveStruct();
#endif
buffer->popBlock();
}
}

View File

@ -1,45 +0,0 @@
#pragma once
namespace Assets
{
class ImenuDef_t : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_MENU; }
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
static std::unordered_map<std::string, Game::menuDef_t*> LoadedMenus;
private:
template <typename T> void save_windowDef_t(Game::windowDef_t* asset, T* dest, Components::ZoneBuilder::Zone* builder)
{
Utils::Stream* buffer = builder->getBuffer();
if (asset->name)
{
buffer->saveString(asset->name);
Utils::Stream::ClearPointer(&dest->window.name);
}
if (asset->group)
{
buffer->saveString(asset->group);
Utils::Stream::ClearPointer(&dest->window.group);
}
if (asset->background)
{
dest->window.background = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->background).material;
}
}
void save_ExpressionSupportingData(Game::ExpressionSupportingData* asset, Components::ZoneBuilder::Zone* builder);
void save_Statement_s(Game::Statement_s* asset, Components::ZoneBuilder::Zone* builder);
void save_MenuEventHandlerSet(Game::MenuEventHandlerSet* asset, Components::ZoneBuilder::Zone* builder);
void save_ItemKeyHandler(Game::ItemKeyHandler* asset, Components::ZoneBuilder::Zone* builder);
void save_itemDefData_t(Game::itemDefData_t* asset, int type, Game::itemDef_s* dest, Components::ZoneBuilder::Zone* builder);
void save_itemDef_s(Game::itemDef_s *asset, Components::ZoneBuilder::Zone* builder);
};
}

View File

@ -1,226 +0,0 @@
#include <STDInclude.hpp>
#include "Isnd_alias_list_t.hpp"
namespace Assets
{
void Isnd_alias_list_t::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->sound = builder->getIW4OfApi()->read<Game::snd_alias_list_t>(Game::XAssetType::ASSET_TYPE_SOUND, name);
if (!header->sound)
{
header->sound = Components::AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, name.data()).sound;
}
}
void Isnd_alias_list_t::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
Game::snd_alias_list_t* asset = header.sound;
for (unsigned int i = 0; i < asset->count; ++i)
{
Game::snd_alias_t* alias = &asset->head[i];
if (alias->soundFile && alias->soundFile->type == Game::snd_alias_type_t::SAT_LOADED)
{
builder->loadAsset(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, alias->soundFile->u.loadSnd);
}
if (alias->volumeFalloffCurve)
{
if (!builder->loadAsset(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, alias->volumeFalloffCurve))
{
// (Should never happen, but just in case)
alias->volumeFalloffCurve->filename = "$default";
builder->loadAsset(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, alias->volumeFalloffCurve);
}
}
}
}
void Isnd_alias_list_t::dump(Game::XAssetHeader header)
{
Components::ZoneBuilder::GetExporter()->write(Game::XAssetType::ASSET_TYPE_SOUND, header.data);
}
Isnd_alias_list_t::Isnd_alias_list_t()
{
Components::Command::Add("dumpSound", [this](const Components::Command::Params* param)
{
const auto header = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_SOUND, param->get(1));
if (header.data)
{
Components::ZoneBuilder::RefreshExporterWorkDirectory();
this->dump(header);
}
});
}
void Isnd_alias_list_t::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{
AssertSize(Game::snd_alias_list_t, 12);
auto* buffer = builder->getBuffer();
auto* asset = header.sound;
auto* dest = buffer->dest<Game::snd_alias_list_t>();
buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->aliasName)
{
if (builder->hasPointer(asset->aliasName))
{
dest->aliasName = builder->getPointer(asset->aliasName);
}
else
{
builder->storePointer(asset->aliasName);
buffer->saveString(asset->aliasName);
Utils::Stream::ClearPointer(&dest->aliasName);
}
}
if (asset->head)
{
if (builder->hasPointer(asset->head))
{
dest->head = builder->getPointer(asset->head);
}
else
{
AssertSize(Game::snd_alias_t, 100);
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->head);
auto* destHead = buffer->dest<Game::snd_alias_t>();
buffer->saveArray(asset->head, asset->count);
for (unsigned int i = 0; i < asset->count; ++i)
{
Game::snd_alias_t* destAlias = &destHead[i];
Game::snd_alias_t* alias = &asset->head[i];
if (alias->aliasName)
{
if (builder->hasPointer(alias->aliasName))
{
destAlias->aliasName = builder->getPointer(alias->aliasName);
}
else
{
builder->storePointer(alias->aliasName);
buffer->saveString(alias->aliasName);
Utils::Stream::ClearPointer(&destAlias->aliasName);
}
}
if (alias->subtitle)
{
buffer->saveString(alias->subtitle);
Utils::Stream::ClearPointer(&destAlias->subtitle);
}
if (alias->secondaryAliasName)
{
buffer->saveString(alias->secondaryAliasName);
Utils::Stream::ClearPointer(&destAlias->secondaryAliasName);
}
if (alias->chainAliasName)
{
buffer->saveString(alias->chainAliasName);
Utils::Stream::ClearPointer(&destAlias->chainAliasName);
}
if (alias->mixerGroup)
{
buffer->saveString(alias->mixerGroup);
Utils::Stream::ClearPointer(&destAlias->mixerGroup);
}
if (alias->soundFile)
{
if (builder->hasPointer(alias->soundFile))
{
destAlias->soundFile = builder->getPointer(alias->soundFile);
}
else
{
AssertSize(Game::snd_alias_t, 100);
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(alias->soundFile);
auto* destSoundFile = buffer->dest<Game::SoundFile>();
buffer->save(alias->soundFile);
// Save_SoundFileRef
{
if (alias->soundFile->type == Game::snd_alias_type_t::SAT_LOADED)
{
destSoundFile->u.loadSnd = builder->saveSubAsset(Game::ASSET_TYPE_LOADED_SOUND, alias->soundFile->u.loadSnd).loadSnd;
}
else
{
// Save_StreamedSound
{
if (alias->soundFile->u.streamSnd.filename.info.raw.dir)
{
buffer->saveString(alias->soundFile->u.streamSnd.filename.info.raw.dir);
Utils::Stream::ClearPointer(&destSoundFile->u.streamSnd.filename.info.raw.dir);
}
if (alias->soundFile->u.streamSnd.filename.info.raw.name)
{
buffer->saveString(alias->soundFile->u.streamSnd.filename.info.raw.name);
Utils::Stream::ClearPointer(&destSoundFile->u.streamSnd.filename.info.raw.name);
}
}
}
}
Utils::Stream::ClearPointer(&destAlias->soundFile);
}
}
if (alias->volumeFalloffCurve)
{
destAlias->volumeFalloffCurve = builder->saveSubAsset(Game::ASSET_TYPE_SOUND_CURVE, alias->volumeFalloffCurve).sndCurve;
}
if (alias->speakerMap)
{
if (builder->hasPointer(alias->speakerMap))
{
destAlias->speakerMap = builder->getPointer(alias->speakerMap);
}
else
{
AssertSize(Game::SpeakerMap, 408);
buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(alias->speakerMap);
auto* destSoundFile = buffer->dest<Game::SpeakerMap>();
buffer->save(alias->speakerMap);
if (alias->speakerMap->name)
{
buffer->saveString(alias->speakerMap->name);
Utils::Stream::ClearPointer(&destSoundFile->name);
}
Utils::Stream::ClearPointer(&destAlias->speakerMap);
}
}
}
Utils::Stream::ClearPointer(&dest->head);
}
}
buffer->popBlock();
}
}

View File

@ -1,17 +0,0 @@
#pragma once
namespace Assets
{
class Isnd_alias_list_t : public Components::AssetHandler::IAsset
{
public:
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_SOUND; }
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
void dump(Game::XAssetHeader header) override;
Isnd_alias_list_t();
};
}

View File

@ -329,7 +329,7 @@ namespace Components
void Auth::StoreKey()
{
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && GuidKey.isValid())
if (!Dedicated::IsEnabled() && GuidKey.isValid())
{
Proto::Auth::Certificate cert;
cert.set_token(GuidToken.toString());
@ -350,7 +350,7 @@ namespace Components
void Auth::LoadKey(bool force)
{
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return;
if (Dedicated::IsEnabled()) return;
if (!force && GuidKey.isValid()) return;
Proto::Auth::Certificate cert;
@ -509,7 +509,7 @@ namespace Components
Logger::Print("Your guid: {:#X}\n", Steam::SteamUser()->GetSteamID().bits);
});
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
if (!Dedicated::IsEnabled())
{
Command::Add("securityLevel", [](const Command::Params* params)
{

View File

@ -135,11 +135,7 @@ namespace Components
Utils::Hook(0x5AC975, CG_DrawVersion_Hk, HOOK_CALL).install()->quick();
// Console title
if (ZoneBuilder::IsEnabled())
{
Utils::Hook::Set<const char*>(0x4289E8, "IW4x (" REVISION_STR "): ZoneBuilder");
}
else if (Dedicated::IsEnabled())
if (Dedicated::IsEnabled())
{
#ifdef EXPERIMENTAL_BUILD
Utils::Hook::Set<const char*>(0x4289E8, "IW4x " REVISION_STR "-develop: Dedicated");

View File

@ -909,7 +909,7 @@ namespace Components
AddConsoleCommand();
#endif
if (Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
if (Dedicated::IsEnabled())
{
Scheduler::Loop(RefreshStatus, Scheduler::Pipeline::MAIN);
}
@ -923,7 +923,7 @@ namespace Components
Utils::Hook(0x4B2080, StdOutPrint, HOOK_JUMP).install()->quick();
Utils::Hook(0x43D570, StdOutError, HOOK_JUMP).install()->quick();
}
else if (Flags::HasFlag("console") || ZoneBuilder::IsEnabled()) // ZoneBuilder uses the game's console, until the native one is adapted.
else if (Flags::HasFlag("console")) // ZoneBuilder uses the game's console, until the native one is adapted.
{
Utils::Hook::Nop(0x60BB58, 11);

View File

@ -182,7 +182,7 @@ namespace Components
COMLogFilter = Dvar::Register<bool>("com_logFilter", true,
Game::DVAR_LATCH, "Removes ~95% of unneeded lines from the log");
if (IsEnabled() || ZoneBuilder::IsEnabled())
if (IsEnabled())
{
// Make sure all callbacks are handled
Scheduler::Loop(Steam::SteamAPI_RunCallbacks, Scheduler::Pipeline::SERVER);
@ -243,9 +243,7 @@ namespace Components
// Intercept time wrapping
Utils::Hook(0x62737D, TimeWrapStub, HOOK_CALL).install()->quick();
//Utils::Hook::Set<DWORD>(0x62735C, 50'000); // Time wrap after 50 seconds (for testing - i don't want to wait 3 weeks)
if (!ZoneBuilder::IsEnabled())
{
Events::OnDvarInit([]
{

View File

@ -116,7 +116,7 @@ namespace Components
Discord::Discord()
{
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
if (Dedicated::IsEnabled())
{
return;
}

View File

@ -207,7 +207,7 @@ namespace Components
const Game::dvar_t* Dvar::Dvar_RegisterName(const char* dvarName, const char* /*value*/, std::uint16_t flags, const char* description)
{
// Name watcher
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
if (!Dedicated::IsEnabled())
{
Scheduler::Loop([]
{

View File

@ -527,12 +527,9 @@ namespace Components
Utils::Hook(Game::DB_ReadXFile, FastFiles::ReadXFileStub, HOOK_JUMP).install()->quick();
// Allow custom zone loading
if (!ZoneBuilder::IsEnabled())
{
Utils::Hook(0x506BC7, FastFiles::LoadInitialZones, HOOK_CALL).install()->quick();
Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).install()->quick();
Utils::Hook(0x506B25, FastFiles::LoadGfxZones, HOOK_CALL).install()->quick();
}
Utils::Hook(0x506BC7, FastFiles::LoadInitialZones, HOOK_CALL).install()->quick();
Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).install()->quick();
Utils::Hook(0x506B25, FastFiles::LoadGfxZones, HOOK_CALL).install()->quick();
// basic checks (hash jumps, both normal and playlist)
Utils::Hook::Nop(0x5B97A3, 2);
@ -583,7 +580,7 @@ namespace Components
FastFiles::AddZonePath("zone\\patch\\");
FastFiles::AddZonePath("zone\\dlc\\");
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
if (!Dedicated::IsEnabled())
{
Scheduler::Loop([]
{

View File

@ -253,11 +253,6 @@ namespace Components
void FileSystem::RegisterFolders()
{
if (ZoneBuilder::IsEnabled())
{
RegisterFolder("zonedata");
}
RegisterFolder("userraw");
}

View File

@ -554,7 +554,7 @@ namespace Components
{
Friends::LoggedOn = false;
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return;
if (Dedicated::IsEnabled()) return;
Friends::UIStreamFriendly = Dvar::Register<bool>("ui_streamFriendly", false, Game::DVAR_ARCHIVE, "Stream friendly UI");
Friends::CLAnonymous = Dvar::Register<bool>("cl_anonymous", false, Game::DVAR_ARCHIVE, "Enable invisible mode for Steam");
@ -704,7 +704,7 @@ namespace Components
Friends::~Friends()
{
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return;
if (Dedicated::IsEnabled()) return;
Friends::StoreFriendsList();

View File

@ -2082,11 +2082,6 @@ namespace Components
Gamepad::Gamepad()
{
if (ZoneBuilder::IsEnabled())
{
return;
}
// Initialize gamepad environment
Utils::Hook(0x4059FE, CG_RegisterDvars_Hk, HOOK_CALL).install()->quick();

View File

@ -201,7 +201,7 @@ namespace Components
IPCPipe::IPCPipe()
{
if (Dedicated::IsEnabled() || Loader::IsPerformingUnitTests() || ZoneBuilder::IsEnabled()) return;
if (Dedicated::IsEnabled() || Loader::IsPerformingUnitTests()) return;
// Server pipe
ServerPipe.onConnect(ConnectClient);

View File

@ -1,464 +0,0 @@
#include <STDInclude.hpp>
#include "MapDump.hpp"
namespace Components
{
class MapDumper
{
public:
MapDumper(Game::GfxWorld* world) : world_(world)
{
}
void dump()
{
if (!this->world_) return;
Logger::Print("Exporting '{}'...\n", this->world_->baseName);
this->parseVertices();
this->parseFaces();
this->parseStaticModels();
this->write();
}
private:
struct Vertex
{
Game::vec3_t coordinate;
Game::vec2_t texture;
Game::vec3_t normal;
};
struct Face
{
int a{};
int b{};
int c{};
};
struct FaceList
{
std::vector<Face> indices{};
};
class File
{
public:
File() {}
File(const std::string& file)
{
Utils::IO::WriteFile(file, {});
this->stream_ = std::ofstream(file, std::ofstream::out);
}
void append(const std::string& str)
{
this->stream_.write(str.data(), str.size());
}
private:
std::ofstream stream_{};
};
Game::GfxWorld* world_{};
std::vector<Vertex> vertices_{};
std::unordered_map<Game::Material*, FaceList> faces_{};
std::vector<Game::Material*> facesOrder_{};
File object_{};
File material_{};
void transformAxes(Game::vec3_t& vec) const
{
std::swap(vec[0], vec[1]);
std::swap(vec[1], vec[2]);
}
void parseVertices()
{
Logger::Print("Parsing vertices...\n");
for (unsigned int i = 0; i < this->world_->draw.vertexCount; ++i)
{
const auto* vertex = &this->world_->draw.vd.vertices[i];
Vertex v{};
v.coordinate[0] = vertex->xyz[0];
v.coordinate[1] = vertex->xyz[1];
v.coordinate[2] = vertex->xyz[2];
this->transformAxes(v.coordinate);
v.texture[0] = vertex->texCoord[0];
v.texture[1] = -vertex->texCoord[1];
Game::Vec3UnpackUnitVec(vertex->normal, &v.normal);
this->transformAxes(v.normal);
this->vertices_.push_back(v);
}
}
void parseFaces()
{
Logger::Print("Parsing faces...\n");
for (unsigned int i = 0; i < this->world_->dpvs.staticSurfaceCount; ++i)
{
const auto* surface = &this->world_->dpvs.surfaces[i];
const unsigned int vertOffset = surface->tris.firstVertex + 1;
const unsigned int indexOffset = surface->tris.baseIndex;
// Fuck cube maps for now
if(this->findImage(surface->material, "colorMap")->mapType == 5) continue;
auto& f = this->getFaceList(surface->material);
for (unsigned short j = 0; j < surface->tris.triCount; ++j)
{
Face face{};
face.a = this->world_->draw.indices[indexOffset + j * 3 + 0] + vertOffset;
face.b = this->world_->draw.indices[indexOffset + j * 3 + 1] + vertOffset;
face.c = this->world_->draw.indices[indexOffset + j * 3 + 2] + vertOffset;
f.indices.push_back(face);
}
}
}
FaceList& getFaceList(Game::Material* material)
{
auto& faceList = this->faces_[material];
if (this->facesOrder_.size() < this->faces_.size())
{
this->facesOrder_.push_back(material);
}
return faceList;
}
void performWorldTransformation(const Game::GfxPackedPlacement& placement, Vertex& v) const
{
Game::MatrixVecMultiply(placement.axis, v.normal, v.normal);
Game::Vec3Normalize(v.normal);
Game::MatrixVecMultiply(placement.axis, v.coordinate, v.coordinate);
v.coordinate[0] = v.coordinate[0] * placement.scale + placement.origin[0];
v.coordinate[1] = v.coordinate[1] * placement.scale + placement.origin[1];
v.coordinate[2] = v.coordinate[2] * placement.scale + placement.origin[2];
}
std::vector<Vertex> parseSurfaceVertices(const Game::XSurface* surface, const Game::GfxPackedPlacement& placement)
{
std::vector<Vertex> vertices;
for (unsigned short j = 0; j < surface->vertCount; j++)
{
const auto *vertex = &surface->verts0[j];
Vertex v{};
v.coordinate[0] = vertex->xyz[0];
v.coordinate[1] = vertex->xyz[1];
v.coordinate[2] = vertex->xyz[2];
// Why...
Game::Vec2UnpackTexCoords(vertex->texCoord, &v.texture);
std::swap(v.texture[0], v.texture[1]);
v.texture[1] *= -1;
Game::Vec3UnpackUnitVec(vertex->normal, &v.normal);
this->performWorldTransformation(placement, v);
this->transformAxes(v.coordinate);
this->transformAxes(v.normal);
vertices.push_back(v);
}
return vertices;
}
std::vector<Face> parseSurfaceFaces(const Game::XSurface* surface) const
{
std::vector<Face> faces;
for (unsigned short j = 0; j < surface->triCount; ++j)
{
Face face{};
face.a = surface->triIndices[j * 3 + 0];
face.b = surface->triIndices[j * 3 + 1];
face.c = surface->triIndices[j * 3 + 2];
faces.push_back(face);
}
return faces;
}
void removeVertex(const int index, std::vector<Face>& faces, std::vector<Vertex>& vertices) const
{
vertices.erase(vertices.begin() + index);
for (auto &face : faces)
{
if (face.a > index) --face.a;
if (face.b > index) --face.b;
if (face.c > index) --face.c;
}
}
void filterSurfaceVertices(std::vector<Face>& faces, std::vector<Vertex>& vertices) const
{
for (auto i = 0; i < int(vertices.size()); ++i)
{
auto referenced = false;
for (const auto &face : faces)
{
if (face.a == i || face.b == i || face.c == i)
{
referenced = true;
break;
}
}
if (!referenced)
{
this->removeVertex(i--, faces, vertices);
}
}
}
void parseStaticModel(Game::GfxStaticModelDrawInst* model)
{
for (unsigned char i = 0; i < model->model->numsurfs; ++i)
{
this->getFaceList(model->model->materialHandles[i]);
}
const auto* lod = &model->model->lodInfo[model->model->numLods - 1];
const auto baseIndex = this->vertices_.size() + 1;
const auto surfIndex = lod->surfIndex;
assert(lod->modelSurfs->numsurfs <= model->model->numsurfs);
for (unsigned short i = 0; i < lod->modelSurfs->numsurfs; ++i)
{
// TODO: Something is still wrong about the models. Probably baseTriIndex and baseVertIndex might help
const auto* surface = &lod->modelSurfs->surfs[i];
auto faces = this->parseSurfaceFaces(surface);
auto vertices = this->parseSurfaceVertices(surface, model->placement);
this->filterSurfaceVertices(faces, vertices);
auto& f = this->getFaceList(model->model->materialHandles[i + surfIndex]);
for (const auto& vertex : vertices)
{
this->vertices_.push_back(vertex);
}
for (auto face : faces)
{
face.a += baseIndex;
face.b += baseIndex;
face.c += baseIndex;
f.indices.push_back(std::move(face));
}
}
}
void parseStaticModels()
{
Logger::Print("Parsing static models...\n");
for (unsigned i = 0u; i < this->world_->dpvs.smodelCount; ++i)
{
this->parseStaticModel(this->world_->dpvs.smodelDrawInsts + i);
}
}
void write()
{
this->object_ = File(Utils::String::VA("raw/mapdump/%s/%s.obj", this->world_->baseName, this->world_->baseName));
this->material_ = File(Utils::String::VA("raw/mapdump/%s/%s.mtl", this->world_->baseName, this->world_->baseName));
this->object_.append("# Generated by IW4x\n");
this->object_.append("# Credit to SE2Dev for his D3DBSP Tool\n");
this->object_.append(Utils::String::VA("o %s\n", this->world_->baseName));
this->object_.append(Utils::String::VA("mtllib %s.mtl\n\n", this->world_->baseName));
this->material_.append("# IW4x MTL File\n");
this->material_.append("# Credit to SE2Dev for his D3DBSP Tool\n");
this->writeVertices();
this->writeFaces();
Logger::Print("Writing files...\n");
this->object_ = {};
this->material_ = {};
}
void writeVertices()
{
Logger::Print("Writing vertices...\n");
this->object_.append("# Vertices\n");
for (const auto& vertex : this->vertices_)
{
this->object_.append(Utils::String::VA("v %.6f %.6f %.6f\n", vertex.coordinate[0], vertex.coordinate[1], vertex.coordinate[2]));
}
Logger::Print("Writing texture coordinates...\n");
this->object_.append("\n# Texture coordinates\n");
for (const auto& vertex : this->vertices_)
{
this->object_.append(Utils::String::VA("vt %.6f %.6f\n", vertex.texture[0], vertex.texture[1]));
}
Logger::Print("Writing normals...\n");
this->object_.append("\n# Normals\n");
for (const auto& vertex : this->vertices_)
{
this->object_.append(Utils::String::VA("vn %.6f %.6f %.6f\n", vertex.normal[0], vertex.normal[1], vertex.normal[2]));
}
this->object_.append("\n");
}
Game::GfxImage* findImage(Game::Material* material, const std::string& type) const
{
Game::GfxImage* image = nullptr;
const auto hash = Game::R_HashString(type.data());
for (char l = 0; l < material->textureCount; ++l)
{
if (material->textureTable[l].nameHash == hash)
{
image = material->textureTable[l].u.image; // Hopefully our map
break;
}
}
return image;
}
Game::GfxImage* extractImage(Game::Material* material, const std::string& type) const
{
auto* image = this->findImage(material, type);
if (!image)
{
return image;
}
std::string _name = Utils::String::VA("raw/mapdump/%s/textures/%s.png", this->world_->baseName, image->name);
D3DXSaveTextureToFileA(_name.data(), D3DXIFF_PNG, image->texture.map, nullptr);
return image;
}
void writeMaterial(Game::Material* material)
{
std::string name = material->info.name;
const auto pos = name.find_last_of('/');
if (pos != std::string::npos)
{
name = name.substr(pos + 1);
}
this->object_.append(Utils::String::VA("usemtl %s\n", name.data()));
this->object_.append("s off\n");
auto* colorMap = this->extractImage(material, "colorMap");
auto* normalMap = this->extractImage(material, "normalMap");
auto* specularMap = this->extractImage(material, "specularMap");
this->material_.append(Utils::String::VA("\nnewmtl %s\n", name.data()));
this->material_.append("Ka 1.0000 1.0000 1.0000\n");
this->material_.append("Kd 1.0000 1.0000 1.0000\n");
this->material_.append("illum 1\n");
this->material_.append(Utils::String::VA("map_Ka textures/%s.png\n", colorMap->name));
this->material_.append(Utils::String::VA("map_Kd textures/%s.png\n", colorMap->name));
if (specularMap)
{
this->material_.append(Utils::String::VA("map_Ks textures/%s.png\n", specularMap->name));
}
if (normalMap)
{
this->material_.append(Utils::String::VA("bump textures/%s.png\n", normalMap->name));
}
}
void writeFaces()
{
Logger::Print("Writing faces...\n");
Utils::IO::CreateDir(Utils::String::VA("raw/mapdump/%s/textures", this->world_->baseName));
this->material_.append(Utils::String::VA("# Material count: %d\n", this->faces_.size()));
this->object_.append("# Faces\n");
for (const auto& material : this->facesOrder_)
{
this->writeMaterial(material);
const auto& faces = this->getFaceList(material);
for (const auto& index : faces.indices)
{
const int a = index.a;
const int b = index.b;
const int c = index.c;
this->object_.append(Utils::String::VA("f %d/%d/%d %d/%d/%d %d/%d/%d\n", a, a, a, b, b, b, c, c, c));
}
this->object_.append("\n");
}
}
};
MapDump::MapDump()
{
Command::Add("dumpmap", []()
{
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
{
Logger::Print("DirectX needs to be enabled, please start a client to use this command!\n");
return;
}
Game::GfxWorld* world = nullptr;
Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_GFXWORLD, [](Game::XAssetHeader header, void* world)
{
*reinterpret_cast<Game::GfxWorld**>(world) = header.gfxWorld;
}, &world, false);
if (world)
{
MapDumper dumper(world);
dumper.dump();
Logger::Print("Map '{}' exported!\n", world->baseName);
}
else
{
Logger::Print("No map loaded, unable to dump anything!\n");
}
});
}
}

View File

@ -1,10 +0,0 @@
#pragma once
namespace Components
{
class MapDump : public Component
{
public:
MapDump();
};
}

View File

@ -862,7 +862,7 @@ namespace Components
// Allow hiding specific smodels
Utils::Hook(0x50E67C, Maps::HideModelStub, HOOK_CALL).install()->quick();
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
if (Dedicated::IsEnabled())
{
return;
}

View File

@ -793,11 +793,6 @@ namespace Components
{
menuParseKeywordHash = reinterpret_cast<Game::KeywordHashEntry<Game::menuDef_t, 128, 3523>**>(0x63AE928);
if (ZoneBuilder::IsEnabled())
{
Game::Menu_Setup(Game::uiContext);
}
if (Dedicated::IsEnabled()) return;
// Intercept asset finding

View File

@ -58,14 +58,7 @@ namespace Components
}
#endif
if (ZoneBuilder::IsEnabled())
{
Logger::Print("Loading model surface {} at path \"{}\" failed!", name, path);
}
else
{
Logger::Error(Game::ERR_FATAL, "Loading model {} failed!", name);
}
Logger::Error(Game::ERR_FATAL, "Loading model {} failed!", name);
return nullptr;
}

View File

@ -39,7 +39,7 @@ namespace Components
News::News()
{
if (ZoneBuilder::IsEnabled() || Dedicated::IsEnabled()) return; // Maybe also dedi?
if (Dedicated::IsEnabled()) return;
Dvar::Register<bool>("g_firstLaunch", true, Game::DVAR_ARCHIVE, "");

View File

@ -395,7 +395,6 @@ namespace Components
Node::Node()
{
if (ZoneBuilder::IsEnabled()) return;
Dvar::Register<bool>("net_natFix", false, 0, "Fix node registration for certain firewalls/routers");
Scheduler::Loop([]

View File

@ -317,7 +317,7 @@ namespace Components
Connect(Container.target);
});
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
if (!Dedicated::IsEnabled())
{
Scheduler::Loop([]
{

View File

@ -29,7 +29,7 @@ namespace Components
Console::FreeNativeConsole();
if (Loader::IsPerformingUnitTests() || Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return;
if (Loader::IsPerformingUnitTests() || Dedicated::IsEnabled()) return;
FirstInstance = (CreateMutexA(nullptr, FALSE, "iw4x_mutex") && GetLastError() != ERROR_ALREADY_EXISTS);

View File

@ -149,159 +149,10 @@ namespace Components
{
if (Dedicated::IsEnabled()) return;
// Do not execute this when building zones
if (!ZoneBuilder::IsEnabled())
{
// Correctly upgrade stats
Utils::Hook(0x42F088, StructuredData::UpdateVersionOffsets, HOOK_CALL).install()->quick();
// Correctly upgrade stats
Utils::Hook(0x42F088, StructuredData::UpdateVersionOffsets, HOOK_CALL).install()->quick();
// 15 or more custom classes
Utils::Hook::Set<BYTE>(0x60A2FE, NUM_CUSTOM_CLASSES);
return;
}
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& filename, bool* /*restrict*/)
{
// Only intercept playerdatadef loading
if (type != Game::ASSET_TYPE_STRUCTURED_DATA_DEF || filename != "mp/playerdata.def") return;
// Store asset
Game::StructuredDataDefSet* data = asset.structuredDataDefSet;
if (!data) return;
if (data->defCount != 1)
{
Logger::Error(Game::ERR_FATAL, "PlayerDataDefSet contains more than 1 definition!");
return;
}
if (data->defs[0].version != 155)
{
Logger::Error(Game::ERR_FATAL, "Initial PlayerDataDef is not version 155, patching not possible!");
return;
}
std::unordered_map<int, std::vector<std::vector<std::string>>> patchDefinitions;
std::unordered_map<int, std::unordered_map<std::string, std::string>> otherPatchDefinitions;
// First check if all versions are present
for (int i = 156;; ++i)
{
// We're on DB thread (OnLoad) so use DB thread for FS
FileSystem::File definition(std::format("{}/{}.json", filename, i), Game::FsThread::FS_THREAD_DATABASE);
if (!definition.exists()) break;
std::vector<std::vector<std::string>> enumContainer;
std::unordered_map<std::string, std::string> otherPatches;
nlohmann::json defData;
try
{
defData = nlohmann::json::parse(definition.getBuffer());
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "JSON Parse Error: {}\n", ex.what());
return;
}
if (!defData.is_object())
{
Logger::Error(Game::ERR_FATAL, "PlayerDataDef patch for version {} is invalid!", i);
return;
}
for (auto pType = 0; pType < StructuredData::PlayerDataType::COUNT; ++pType)
{
auto enumData = defData[StructuredData::EnumTranslation[pType]];
std::vector<std::string> entryData;
if (enumData.is_array())
{
for (const auto& rawEntry : enumData)
{
if (rawEntry.is_string())
{
entryData.push_back(rawEntry.get<std::string>());
}
}
}
enumContainer.push_back(entryData);
}
auto other = defData["other"];
if (other.is_object())
{
for (auto& item : other.items())
{
if (item.value().is_string())
{
otherPatches[item.key()] = item.value().get<std::string>();
}
}
}
patchDefinitions[i] = enumContainer;
otherPatchDefinitions[i] = otherPatches;
}
// Nothing to patch
if (patchDefinitions.empty()) return;
// Reallocate the definition
auto* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->defCount + patchDefinitions.size());
std::memcpy(&newData[patchDefinitions.size()], data->defs, sizeof Game::StructuredDataDef * data->defCount);
// Prepare the buffers
for (unsigned int i = 0; i < patchDefinitions.size(); ++i)
{
std::memcpy(&newData[i], data->defs, sizeof Game::StructuredDataDef);
newData[i].version = (patchDefinitions.size() - i) + 155;
// Reallocate the enum array
auto* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(data->defs->enumCount);
std::memcpy(newEnums, data->defs->enums, sizeof Game::StructuredDataEnum * data->defs->enumCount);
newData[i].enums = newEnums;
}
// Apply new data
data->defs = newData;
data->defCount += patchDefinitions.size();
// Patch the definition
for (unsigned int i = 0; i < data->defCount; ++i)
{
// No need to patch version 155
if (newData[i].version == 155) continue;
if (patchDefinitions.contains(newData[i].version))
{
auto patchData = patchDefinitions[newData[i].version];
auto otherData = otherPatchDefinitions[newData[i].version];
// Invalid patch data
if (patchData.size() != StructuredData::PlayerDataType::COUNT)
{
Logger::Error(Game::ERR_FATAL, "PlayerDataDef patch for version {} wasn't parsed correctly!", newData[i].version);
continue;
}
// Apply the patch data
for (auto pType = 0; pType < StructuredData::PlayerDataType::COUNT; ++pType)
{
if (!patchData[pType].empty())
{
StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]);
}
}
StructuredData::PatchAdditionalData(&newData[i], otherData);
}
}
});
// 15 or more custom classes
Utils::Hook::Set<BYTE>(0x60A2FE, NUM_CUSTOM_CLASSES);
}
}

View File

@ -147,7 +147,7 @@ namespace Components
Toast::Toast()
{
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
if (Dedicated::IsEnabled())
{
return;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,175 +0,0 @@
#pragma once
#include <api.hpp>
#define XFILE_MAGIC_UNSIGNED 0x3030317566665749
#define XFILE_VERSION 276
#define XFILE_HEADER_IW4X 0x78345749 // 'IW4x'
#define XFILE_VERSION_IW4X 3
namespace Components
{
class ZoneBuilder : public Component
{
public:
class Zone
{
public:
class AssetRecursionMarker
{
public:
AssetRecursionMarker(Zone* _builder) : builder(_builder)
{
this->builder->increaseAssetDepth();
}
~AssetRecursionMarker()
{
this->builder->decreaseAssetDepth();
}
private:
Zone* builder;
};
Zone(const std::string& zoneName);
~Zone();
void build();
Utils::Stream* getBuffer();
Utils::Memory::Allocator* getAllocator();
iw4of::api* getIW4OfApi();
bool hasPointer(const void* pointer);
void storePointer(const void* pointer);
template<typename T>
T* getPointer(const T* pointer) { return reinterpret_cast<T*>(this->safeGetPointer(pointer)); }
int findAsset(Game::XAssetType type, std::string name);
Game::XAssetHeader findSubAsset(Game::XAssetType type, std::string name);
Game::XAsset* getAsset(int index);
uint32_t getAssetTableOffset(int index);
bool hasAlias(Game::XAsset asset);
Game::XAssetHeader saveSubAsset(Game::XAssetType type, void* ptr);
bool loadAssetByName(Game::XAssetType type, const std::string& name, bool isSubAsset = true);
bool loadAsset(Game::XAssetType type, void* data, bool isSubAsset = true);
int addScriptString(unsigned short gameIndex);
int addScriptString(const std::string& str);
int findScriptString(const std::string& str);
void addRawAsset(Game::XAssetType type, void* ptr);
void mapScriptString(unsigned short& gameIndex);
void renameAsset(Game::XAssetType type, const std::string& asset, const std::string& newName);
std::string getAssetName(Game::XAssetType type, const std::string& asset);
void store(Game::XAssetHeader header);
void incrementExternalSize(unsigned int size);
void increaseAssetDepth() { ++this->assetDepth; }
void decreaseAssetDepth() { --this->assetDepth; }
bool isPrimaryAsset() { return this->assetDepth <= 1; }
private:
void loadFastFiles() const;
bool loadAssets();
bool loadAssetByName(const std::string& type, std::string name, bool isSubAsset = true);
void saveData();
void writeZone();
unsigned int getAlias(Game::XAsset asset);
void storeAlias(Game::XAsset asset);
void addBranding();
iw4of::params_t getIW4OfApiParams();
uint32_t safeGetPointer(const void* pointer);
int indexStart;
unsigned int externalSize;
Utils::Stream buffer;
iw4of::api iw4ofApi;
std::string zoneName;
Utils::CSV dataMap;
Utils::Memory::Allocator memAllocator;
std::vector<Game::XAsset> loadedAssets;
std::vector<Game::XAsset> markedAssets;
std::vector<Game::XAsset> loadedSubAssets;
std::vector<std::string> scriptStrings;
std::map<unsigned short, unsigned int> scriptStringMap;
std::map<std::string, std::string> renameMap[Game::XAssetType::ASSET_TYPE_COUNT];
std::map<const void*, uint32_t> pointerMap;
std::vector<std::pair<Game::XAsset, uint32_t>> aliasList;
Game::RawFile branding;
size_t assetDepth;
};
ZoneBuilder();
~ZoneBuilder();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
bool unitTest() override;
#endif
static bool IsEnabled();
static std::string TraceZone;
static std::vector<std::pair<Game::XAssetType, std::string>> TraceAssets;
static void BeginAssetTrace(const std::string& zone);
static std::vector<std::pair<Game::XAssetType, std::string>> EndAssetTrace();
static Game::XAssetHeader GetEmptyAssetIfCommon(Game::XAssetType type, const std::string& name, Zone* builder);
static void RefreshExporterWorkDirectory();
static iw4of::api* GetExporter();
private:
static int StoreTexture(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image);
static void ReleaseTexture(Game::XAssetHeader header);
static std::string FindMaterialByTechnique(const std::string& name);
static void ReallocateLoadedSounds(void*& data, void* a2);
static BOOL APIENTRY EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/);
static void HandleError(Game::errorParm_t code, const char* fmt, ...);
static void SoftErrorAssetOverflow();
static void AssumeMainThreadRole();
static void ResetThreadRole();
static bool IsThreadMainThreadHook();
static Game::Sys_File Sys_CreateFile_Stub(const char* dir, const char* filename);
static iw4of::params_t GetExporterAPIParams();
static void Com_Quitf_t();
static void CommandThreadCallback();
static bool MainThreadInterrupted;
static DWORD InterruptingThreadId;
static volatile bool CommandThreadTerminate;
static std::thread CommandThread;
static iw4of::api ExporterAPI;
static std::string DumpingZone;
};
}

View File

@ -2969,279 +2969,6 @@ namespace Components
}
}
static const unsigned int crcTable[] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t Zones::HashCRC32StringInt(const std::string& string, uint32_t initialCrc)
{
auto curPtr = reinterpret_cast<std::uint8_t*>(const_cast<char*>(string.data()));
auto remaining = string.size();
auto crc = ~initialCrc;
for (; remaining--; ++curPtr)
{
crc = (crc >> 8) ^ crcTable[(crc ^ *curPtr) & 0xFF];
}
return (~crc);
}
std::unordered_map<int, Zones::FileData> Zones::fileDataMap;
std::mutex Zones::fileDataMutex;
__declspec(naked) int Zones::FS_FOpenFileReadForThreadOriginal(const char*, int*, int)
{
__asm
{
sub esp, 0x33C
push 0x643276
ret
}
}
int Zones::FS_FOpenFileReadForThreadHook(const char* file, int* filePointer, int thread)
{
const auto retval = FS_FOpenFileReadForThreadOriginal(file, filePointer, thread);
if (file != nullptr && filePointer != nullptr && strlen(file) >= 4 && retval > 0)
{
std::string fileBuffer;
fileBuffer.resize(retval);
auto readSize = Game::FS_Read(&fileBuffer[0], retval, *filePointer);
// check if file should be skipped
auto skipFile = false;
if (std::strlen(file) > 5 && ((std::strncmp(&file[strlen(file) - 4], ".iwi", 4) != 0)))
{
skipFile = true;
}
else if (readSize >= 3 && (std::memcmp(&fileBuffer[0], "IWi", 3) == 0))
{
skipFile = true;
}
// if the header seems encrypted...
if (fileBuffer.size() > 4 && readSize == retval && !skipFile)
{
auto packedSize = fileBuffer.size() - 4;
auto unpackedSize = *reinterpret_cast<int*>(&fileBuffer[fileBuffer.size() - 4]);
// calc encrypted buffer size
auto encryptedBufferSize = fileBuffer.size();
encryptedBufferSize -= 4;
encryptedBufferSize += 16 - (encryptedBufferSize % 16);
// prepare encryptedData buffer
std::string encryptedData;
encryptedData.resize(encryptedBufferSize);
memcpy(&encryptedData[0], &fileBuffer[0], packedSize);
// prepare decryptedData buffer
std::string decryptedData;
decryptedData.resize(encryptedBufferSize);
register_cipher(&aes_desc);
auto aes = find_cipher("aes");
// attempt to decrypt the IWI
symmetric_CTR ctr_state;
ZeroMemory(&ctr_state, sizeof(symmetric_CTR));
// decryption keys
std::uint8_t aesKey[24] = { 0x15, 0x9a, 0x03, 0x25, 0xe0, 0x75, 0x2e, 0x80, 0xc6, 0xc0, 0x94, 0x2a, 0x50, 0x5c, 0x1c, 0x68, 0x8c, 0x17, 0xef, 0x53, 0x99, 0xf8, 0x68, 0x3c };
std::uint32_t aesIV[4] = { 0x1010101, 0x1010101, 0x1010101, 0x1010101 };
auto strippedFileName = std::filesystem::path(file).filename().string();
auto nonce = HashCRC32StringInt(strippedFileName, strippedFileName.size());
std::uint8_t iv[16];
std::memset(iv, 0, sizeof iv);
std::memcpy(iv, &nonce, 4);
std::memcpy(iv + 4, &unpackedSize, 4);
ctr_start(aes, reinterpret_cast<unsigned char*>(&aesIV[0]), &aesKey[0], sizeof aesKey, 0, CTR_COUNTER_BIG_ENDIAN, &ctr_state);
// decrypt image
auto readDataSize = 0u;
while (readDataSize < packedSize)
{
auto left = (packedSize - readDataSize);
auto blockSize = (left > 0x8000) ? 0x8000 : left;
std::memcpy(iv + 8, &readDataSize, 4);
std::memcpy(iv + 12, &blockSize, 4);
ctr_setiv(iv, sizeof iv, &ctr_state);
ctr_decrypt(reinterpret_cast<uint8_t*>(&encryptedData[readDataSize]), reinterpret_cast<uint8_t*>(&decryptedData[readDataSize]), blockSize, &ctr_state);
readDataSize += blockSize;
}
ctr_done(&ctr_state);
if (static_cast<std::uint8_t>(decryptedData[0]) == 0x78)
{
FileData data = {};
data.readPos = 0;
data.len = unpackedSize;
data.fileContents.resize(unpackedSize);
// decompress the buffer
auto result = uncompress(reinterpret_cast<std::uint8_t*>(&data.fileContents[0]),
reinterpret_cast<unsigned long*>(&data.len), reinterpret_cast<const uint8_t*>(&decryptedData[0]), packedSize);
// insert file data
if (result == Z_OK)
{
std::lock_guard _(fileDataMutex);
fileDataMap[*filePointer] = data;
return unpackedSize;
}
}
}
// un-read data, file is apparently not encrypted
Game::FS_Seek(*filePointer, 0, Game::FS_SEEK_SET);
}
return retval;
}
__declspec(naked) int Zones::FS_ReadOriginal(void*, size_t, int)
{
__asm
{
push ecx
mov eax, [esp + 0x10]
push 0x4A04C5
ret
}
}
int Zones::FS_ReadHook(void* buffer, size_t size, int filePointer)
{
std::lock_guard _(fileDataMutex);
if (auto itr = fileDataMap.find(filePointer); itr != fileDataMap.end())
{
if (!itr->second.fileContents.empty())
{
const auto readSize = std::min(size, itr->second.fileContents.size() - itr->second.readPos);
std::memcpy(buffer, &itr->second.fileContents[itr->second.readPos], readSize);
itr->second.readPos += readSize;
return static_cast<int>(readSize);
}
}
return FS_ReadOriginal(buffer, size, filePointer);
}
__declspec(naked) void Zones::FS_FCloseFileOriginal(int)
{
__asm
{
mov eax, [esp + 4]
push esi
push 0x462005
ret
}
}
void Zones::FS_FCloseFileHook(int filePointer)
{
std::lock_guard _(fileDataMutex);
FS_FCloseFileOriginal(filePointer);
if (const auto itr = fileDataMap.find(filePointer); itr != fileDataMap.end())
{
fileDataMap.erase(itr);
}
}
__declspec(naked) std::uint32_t Zones::FS_SeekOriginal(int, int, int)
{
__asm
{
push esi
mov esi, [esp + 8]
push 0x4A63D5
ret
}
}
std::uint32_t Zones::FS_SeekHook(int fileHandle, int seekPosition, int seekOrigin)
{
std::lock_guard _(fileDataMutex);
if (const auto itr = fileDataMap.find(fileHandle); itr != fileDataMap.end())
{
if (seekOrigin == Game::FS_SEEK_SET)
{
itr->second.readPos = seekPosition;
}
else if (seekOrigin == Game::FS_SEEK_CUR)
{
itr->second.readPos += seekPosition;
}
else if (seekOrigin == Game::FS_SEEK_END)
{
itr->second.readPos = itr->second.fileContents.size() - seekPosition;
}
return itr->second.readPos;
}
return FS_SeekOriginal(fileHandle, seekPosition, seekOrigin);
}
__declspec(naked) void Zones::LoadMapTriggersModelPointer()
{
static auto DB_ConvertOffsetToPointer_Address = 0x4A82B0;
@ -3483,75 +3210,6 @@ namespace Components
{
Zones::ZoneVersion = 0;
if (ZoneBuilder::IsEnabled())
{
Command::Add("decryptImages", []()
{
auto images = FileSystem::GetSysFileList("iw4x/images", "iwi");
Logger::Print("decrypting {} images...\n", images.size());
for (auto& image : images)
{
char* buffer = nullptr;
auto fileLength = Game::FS_ReadFile(Utils::String::Format("images/{}", image), &buffer);
if (fileLength && buffer)
{
if (!std::filesystem::exists("raw/images"))
{
std::filesystem::create_directories("raw/images");
}
if (!std::filesystem::exists(Utils::String::Format("raw/images/{}", image)))
{
const auto fp = fopen(Utils::String::Format("raw/images/{}", image), "wb");
if (fp)
{
fwrite(buffer, fileLength, 1, fp);
fclose(fp);
}
}
Game::FS_FreeFile(buffer);
}
}
Logger::Print("decrypted {} images!\n", images.size());
});
Command::Add("decryptSounds", []()
{
auto sounds = FileSystem::GetSysFileList("iw4x/sound", "iwi");
Logger::Print("decrypting {} sounds...\n", sounds.size());
for (auto& sound : sounds)
{
char* buffer = nullptr;
auto len = Game::FS_ReadFile(Utils::String::Format("sound/{}", sound), &buffer);
if (len && buffer)
{
auto path = std::filesystem::path(sound.data());
std::filesystem::create_directories("raw/sound" / path.parent_path());
if (!std::filesystem::exists(std::format("raw/sound/{}", sound)))
{
FILE* fp;
if (!fopen_s(&fp, Utils::String::Format("raw/sound/{}", sound), "wb") && fp)
{
fwrite(buffer, len, 1, fp);
fclose(fp);
}
}
Game::FS_FreeFile(buffer);
}
}
Logger::Print("decrypted {} sounds!\n", sounds.size());
});
}
// patch max filecount Sys_ListFiles can return
Utils::Hook::Set<std::uint32_t>(0x45A66B, (maxFileCount + fileCountMultiplier) * 4);
Utils::Hook::Set<std::uint32_t>(0x64AF78, maxFileCount);
@ -3572,15 +3230,6 @@ namespace Components
// addon_map_ents asset type (we reuse it for weaponattach)
Utils::Hook::Set<BYTE>(0x418B31, 0x72);
// encrypted images hooks
if (ZoneBuilder::IsEnabled())
{
Utils::Hook(0x462000, Zones::FS_FCloseFileHook, HOOK_JUMP).install()->quick();
Utils::Hook(0x4A04C0, Zones::FS_ReadHook, HOOK_JUMP).install()->quick();
Utils::Hook(0x643270, Zones::FS_FOpenFileReadForThreadHook, HOOK_JUMP).install()->quick();
Utils::Hook(0x4A63D0, Zones::FS_SeekHook, HOOK_JUMP).install()->quick();
}
// asset hooks
Utils::Hook(0x47146D, Zones::LoadTracerDef, HOOK_CALL).install()->quick();
Utils::Hook(0x4714A3, Zones::LoadTracerDefFxEffect, HOOK_JUMP).install()->quick();

View File

@ -29,9 +29,6 @@ namespace Components
static int FxEffectIndex;
static char* FxEffectStrings[64];
static std::unordered_map<int, FileData> fileDataMap;
static std::mutex fileDataMutex;
static bool CheckGameMapSp(int type);
static void GameMapSpPatchStub();
@ -83,15 +80,6 @@ namespace Components
static int LoadMapEnts(bool atStreamStart, Game::MapEnts* buffer, int size);
static void Load_ClipInfo(bool atStreamStart);
static int LoadClipMap(bool atStreamStart);
static uint32_t HashCRC32StringInt(const std::string& Value, uint32_t Initial);
static int FS_FOpenFileReadForThreadOriginal(const char*, int*, int);
static int FS_FOpenFileReadForThreadHook(const char* file, int* filePointer, int thread);
static int FS_ReadOriginal(void*, size_t, int);
static int FS_ReadHook(void* buffer, size_t size, int filePointer);
static void FS_FCloseFileOriginal(int);
static void FS_FCloseFileHook(int filePointer);
static std::uint32_t FS_SeekOriginal(int, int, int);
static std::uint32_t FS_SeekHook(int fileHandle, int seekPosition, int seekOrigin);
static void LoadMapTriggersModelPointer();
static void LoadMapTriggersHullPointer();
static void LoadMapTriggersSlabPointer();

View File

@ -143,6 +143,12 @@ using namespace std::literals;
#define BASEGAME_NAME "iw4mp_ceg.exe"
#define CLIENT_CONFIG "iw4x_config.cfg"
#define XFILE_MAGIC_UNSIGNED 0x3030317566665749
#define XFILE_VERSION 276
#define XFILE_HEADER_IW4X 0x78345749 // 'IW4x'
#define XFILE_VERSION_IW4X 3
// Resource stuff
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS

View File

@ -23,11 +23,7 @@ namespace Steam
if (!idBits)
{
if (Components::ZoneBuilder::IsEnabled())
{
idBits = *reinterpret_cast<unsigned __int64*>(const_cast<char*>("DEDICATE"));
}
else if (Components::Singleton::IsFirstInstance() && !Components::Dedicated::IsEnabled()) // ECDSA guid
if (Components::Singleton::IsFirstInstance() && !Components::Dedicated::IsEnabled()) // ECDSA guid
{
idBits = Components::Auth::GetKeyHash();
}

View File

@ -132,7 +132,7 @@ namespace Steam
void Proxy::RunGame()
{
if (Steam::Enabled() && !Components::Dedicated::IsEnabled() && !Components::ZoneBuilder::IsEnabled())
if (Steam::Enabled() && !Components::Dedicated::IsEnabled())
{
SetEnvironmentVariableA("SteamAppId", ::Utils::String::VA("%lu", Proxy::AppId));
SetEnvironmentVariableA("SteamGameId", ::Utils::String::VA("%llu", Proxy::AppId & 0xFFFFFF));
@ -146,7 +146,7 @@ namespace Steam
void Proxy::SetMod(const std::string& mod)
{
if (!Proxy::ClientUser || !Proxy::SteamApps || !Steam::Enabled() || Components::Dedicated::IsEnabled() || Components::ZoneBuilder::IsEnabled()) return;
if (!Proxy::ClientUser || !Proxy::SteamApps || !Steam::Enabled() || Components::Dedicated::IsEnabled()) return;
if (!Proxy::SteamApps->BIsSubscribedApp(Proxy::AppId))
{
@ -382,7 +382,7 @@ namespace Steam
SetDllDirectoryA(directoy.data());
if (!Components::Dedicated::IsEnabled() && !Components::ZoneBuilder::IsEnabled())
if (!Components::Dedicated::IsEnabled())
{
Proxy::LaunchWatchGuard();