maint: remove components I will never use
This commit is contained in:
parent
7c05b151b7
commit
2ae991ccbf
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
deps/iw4-open-formats
vendored
1
deps/iw4-open-formats
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 5e17794ed16351d3f77b72ff1ff8c52621e7b51d
|
44
deps/premake/iw4-open-formats.lua
vendored
44
deps/premake/iw4-open-formats.lua
vendored
@ -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)
|
@ -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());
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
};
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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([]
|
||||
{
|
||||
|
@ -116,7 +116,7 @@ namespace Components
|
||||
|
||||
Discord::Discord()
|
||||
{
|
||||
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
|
||||
if (Dedicated::IsEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -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([]
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
// 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([]
|
||||
{
|
||||
|
@ -253,11 +253,6 @@ namespace Components
|
||||
|
||||
void FileSystem::RegisterFolders()
|
||||
{
|
||||
if (ZoneBuilder::IsEnabled())
|
||||
{
|
||||
RegisterFolder("zonedata");
|
||||
}
|
||||
|
||||
RegisterFolder("userraw");
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class MapDump : public Component
|
||||
{
|
||||
public:
|
||||
MapDump();
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -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, "");
|
||||
|
||||
|
@ -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([]
|
||||
|
@ -317,7 +317,7 @@ namespace Components
|
||||
Connect(Container.target);
|
||||
});
|
||||
|
||||
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
|
||||
if (!Dedicated::IsEnabled())
|
||||
{
|
||||
Scheduler::Loop([]
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
};
|
||||
}
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user