Zonebuilder update for iw5xport compat (#750)
Co-authored-by: Louvenarde <louve@louve.systems> Co-authored-by: Roxanne <roxanne@thegamebakers.com> Co-authored-by: FutureRave <edoardo.sanguineti222@gmail.com>
This commit is contained in:
parent
14b3610fee
commit
eccdf2e25e
@ -1,7 +1,7 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
#include "IFxEffectDef.hpp"
|
#include "IFxEffectDef.hpp"
|
||||||
|
|
||||||
#define IW4X_FX_VERSION 1
|
#define IW4X_FX_VERSION 2
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
@ -65,132 +65,139 @@ namespace Assets
|
|||||||
void IFxEffectDef::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
|
void IFxEffectDef::loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Components::FileSystem::File fxFile(std::format("fx/{}.iw4xFx", name));
|
Components::FileSystem::File fxFile(std::format("fx/{}.iw4xFx", name));
|
||||||
|
if (!fxFile.exists())
|
||||||
if (fxFile.exists())
|
|
||||||
{
|
{
|
||||||
Utils::Stream::Reader buffer(builder->getAllocator(), fxFile.getBuffer());
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
__int64 magic = buffer.read<__int64>();
|
Utils::Stream::Reader buffer(builder->getAllocator(), fxFile.getBuffer());
|
||||||
if (std::memcmp(&magic, "IW4xFx ", 8))
|
|
||||||
|
auto magic = buffer.read<std::int64_t>();
|
||||||
|
if (std::memcmp(&magic, "IW4xFx ", 8) != 0)
|
||||||
|
{
|
||||||
|
Components::Logger::Error(Game::ERR_FATAL, "Reading fx '{}' failed, header is invalid!", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int version = buffer.read<int>();
|
||||||
|
if (version > IW4X_FX_VERSION)
|
||||||
|
{
|
||||||
|
Components::Logger::Error(Game::ERR_FATAL, "Reading fx '{}' failed, expected version is {}, but it was {}!", name, IW4X_FX_VERSION, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* asset = buffer.readObject<Game::FxEffectDef>();
|
||||||
|
header->fx = asset;
|
||||||
|
|
||||||
|
if (asset->name)
|
||||||
|
{
|
||||||
|
asset->name = buffer.readCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->elemDefs)
|
||||||
|
{
|
||||||
|
asset->elemDefs = buffer.readArray<Game::FxElemDef>(asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot);
|
||||||
|
|
||||||
|
for (auto i = 0; i < (asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot); ++i)
|
||||||
{
|
{
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading fx '{}' failed, header is invalid!", name);
|
auto* elemDef = &asset->elemDefs[i];
|
||||||
}
|
|
||||||
|
|
||||||
int version = buffer.read<int>();
|
if (elemDef->velSamples)
|
||||||
if (version != IW4X_FX_VERSION)
|
|
||||||
{
|
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading fx '{}' failed, expected version is {}, but it was {}!", name, IW4X_FX_VERSION, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::FxEffectDef* asset = buffer.readObject<Game::FxEffectDef>();
|
|
||||||
header->fx = asset;
|
|
||||||
|
|
||||||
if (asset->name)
|
|
||||||
{
|
|
||||||
asset->name = buffer.readCString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->elemDefs)
|
|
||||||
{
|
|
||||||
asset->elemDefs = buffer.readArray<Game::FxElemDef>(asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot);
|
|
||||||
|
|
||||||
for (int i = 0; i < (asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot); ++i)
|
|
||||||
{
|
{
|
||||||
Game::FxElemDef* elemDef = &asset->elemDefs[i];
|
elemDef->velSamples = buffer.readArray<Game::FxElemVelStateSample>(elemDef->velIntervalCount + 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (elemDef->velSamples)
|
if (elemDef->visSamples)
|
||||||
{
|
{
|
||||||
elemDef->velSamples = buffer.readArray<Game::FxElemVelStateSample>(elemDef->velIntervalCount + 1);
|
elemDef->visSamples = buffer.readArray<Game::FxElemVisStateSample>(elemDef->visStateIntervalCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elemDef->visSamples)
|
// Save_FxElemDefVisuals
|
||||||
|
{
|
||||||
|
if (elemDef->elemType == Game::FX_ELEM_TYPE_DECAL)
|
||||||
{
|
{
|
||||||
elemDef->visSamples = buffer.readArray<Game::FxElemVisStateSample>(elemDef->visStateIntervalCount + 1);
|
if (elemDef->visuals.markArray)
|
||||||
}
|
|
||||||
|
|
||||||
// Save_FxElemDefVisuals
|
|
||||||
{
|
|
||||||
if (elemDef->elemType == Game::FX_ELEM_TYPE_DECAL)
|
|
||||||
{
|
{
|
||||||
if (elemDef->visuals.markArray)
|
elemDef->visuals.markArray = buffer.readArray<Game::FxElemMarkVisuals>(elemDef->visualCount);
|
||||||
|
|
||||||
|
for (char j = 0; j < elemDef->visualCount; ++j)
|
||||||
{
|
{
|
||||||
elemDef->visuals.markArray = buffer.readArray<Game::FxElemMarkVisuals>(elemDef->visualCount);
|
if (elemDef->visuals.markArray[j].materials[0])
|
||||||
|
|
||||||
for (char j = 0; j < elemDef->visualCount; ++j)
|
|
||||||
{
|
{
|
||||||
if (elemDef->visuals.markArray[j].materials[0])
|
elemDef->visuals.markArray[j].materials[0] = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_MATERIAL, buffer.readString(), builder).material;
|
||||||
{
|
}
|
||||||
elemDef->visuals.markArray[j].materials[0] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, buffer.readString().data(), builder).material;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elemDef->visuals.markArray[j].materials[1])
|
if (elemDef->visuals.markArray[j].materials[1])
|
||||||
{
|
{
|
||||||
elemDef->visuals.markArray[j].materials[1] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, buffer.readString().data(), builder).material;
|
elemDef->visuals.markArray[j].materials[1] = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_MATERIAL, buffer.readString(), builder).material;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (elemDef->visualCount > 1)
|
}
|
||||||
|
else if (elemDef->visualCount > 1)
|
||||||
|
{
|
||||||
|
if (elemDef->visuals.array)
|
||||||
{
|
{
|
||||||
if (elemDef->visuals.array)
|
elemDef->visuals.array = buffer.readArray<Game::FxElemVisuals>(elemDef->visualCount);
|
||||||
{
|
|
||||||
elemDef->visuals.array = buffer.readArray<Game::FxElemVisuals>(elemDef->visualCount);
|
|
||||||
|
|
||||||
for (char j = 0; j < elemDef->visualCount; ++j)
|
for (char j = 0; j < elemDef->visualCount; ++j)
|
||||||
|
{
|
||||||
|
this->loadFxElemVisuals(&elemDef->visuals.array[j], elemDef->elemType, builder, &buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (elemDef->visualCount == 1)
|
||||||
|
{
|
||||||
|
this->loadFxElemVisuals(&elemDef->visuals.instance, elemDef->elemType, builder, &buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elemDef->effectOnImpact.handle)
|
||||||
|
{
|
||||||
|
elemDef->effectOnImpact.handle = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_FX, buffer.readString(), builder).fx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elemDef->effectOnDeath.handle)
|
||||||
|
{
|
||||||
|
elemDef->effectOnDeath.handle = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_FX, buffer.readString(), builder).fx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elemDef->effectEmitted.handle)
|
||||||
|
{
|
||||||
|
elemDef->effectEmitted.handle = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_FX, buffer.readString(), builder).fx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save_FxElemExtendedDefPtr
|
||||||
|
{
|
||||||
|
|
||||||
|
if (elemDef->elemType == Game::FX_ELEM_TYPE_TRAIL)
|
||||||
|
{
|
||||||
|
// Save_FxTrailDef
|
||||||
|
{
|
||||||
|
if (elemDef->extended.trailDef)
|
||||||
|
{
|
||||||
|
auto* trailDef = buffer.readObject<Game::FxTrailDef>();
|
||||||
|
elemDef->extended.trailDef = trailDef;
|
||||||
|
|
||||||
|
if (trailDef->verts)
|
||||||
{
|
{
|
||||||
this->loadFxElemVisuals(&elemDef->visuals.array[j], elemDef->elemType, builder, &buffer);
|
trailDef->verts = buffer.readArray<Game::FxTrailVertex>(trailDef->vertCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trailDef->inds)
|
||||||
|
{
|
||||||
|
trailDef->inds = buffer.readArray<unsigned short>(trailDef->indCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
else if (version >= 2)
|
||||||
|
{
|
||||||
|
if (elemDef->elemType == Game::FX_ELEM_TYPE_SPARK_FOUNTAIN)
|
||||||
{
|
{
|
||||||
this->loadFxElemVisuals(&elemDef->visuals.instance, elemDef->elemType, builder, &buffer);
|
if (elemDef->extended.sparkFountainDef)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elemDef->effectOnImpact.handle)
|
|
||||||
{
|
|
||||||
elemDef->effectOnImpact.handle = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_FX, buffer.readString().data(), builder).fx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elemDef->effectOnDeath.handle)
|
|
||||||
{
|
|
||||||
elemDef->effectOnDeath.handle = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_FX, buffer.readString().data(), builder).fx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elemDef->effectEmitted.handle)
|
|
||||||
{
|
|
||||||
elemDef->effectEmitted.handle = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_FX, buffer.readString().data(), builder).fx;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save_FxElemExtendedDefPtr
|
|
||||||
{
|
|
||||||
|
|
||||||
if (elemDef->elemType == Game::FX_ELEM_TYPE_TRAIL)
|
|
||||||
{
|
|
||||||
// Save_FxTrailDef
|
|
||||||
{
|
{
|
||||||
if (elemDef->extended.trailDef)
|
elemDef->extended.sparkFountainDef = buffer.readObject<Game::FxSparkFountainDef>();
|
||||||
{
|
|
||||||
Game::FxTrailDef* trailDef = buffer.readObject<Game::FxTrailDef>();
|
|
||||||
elemDef->extended.trailDef = trailDef;
|
|
||||||
|
|
||||||
if (trailDef->verts)
|
|
||||||
{
|
|
||||||
trailDef->verts = buffer.readArray<Game::FxTrailVertex>(trailDef->vertCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trailDef->inds)
|
|
||||||
{
|
|
||||||
trailDef->inds = buffer.readArray<unsigned short>(trailDef->indCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (elemDef->extended.trailDef)
|
|
||||||
{
|
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Fx element of type {} has traildef, that's impossible?\n", elemDef->elemType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,7 +277,7 @@ namespace Assets
|
|||||||
// TODO: Convert editor fx to real fx
|
// TODO: Convert editor fx to real fx
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(name);
|
(void)name;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,13 +12,13 @@ namespace Assets
|
|||||||
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
|
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void markFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder);
|
static 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);
|
static 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);
|
static 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 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);
|
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
|
||||||
|
|
||||||
void loadFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader);
|
static void loadFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
#include "IFxWorld.hpp"
|
#include "IFxWorld.hpp"
|
||||||
|
|
||||||
|
#define IW4X_FXWORLD_VERSION 1
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
void IFxWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IFxWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
@ -187,6 +192,161 @@ namespace Assets
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IFxWorld::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
|
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)
|
||||||
|
{
|
||||||
|
std::string name = _name;
|
||||||
|
Utils::String::Replace(name, "maps/mp/", "");
|
||||||
|
Utils::String::Replace(name, ".d3dbsp", "");
|
||||||
|
|
||||||
|
Components::FileSystem::File fxWorldFile(std::format("fxworld/{}.iw4x.json", name));
|
||||||
|
if (!fxWorldFile.exists())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json fxWorldJson;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fxWorldJson = nlohmann::json::parse(fxWorldFile.getBuffer());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid JSON for gameworld {}! Error message: {}", name, e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fxWorldJson.is_object())
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid FXWORLD JSON for {}\n", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto version = fxWorldJson["version"].is_number() ? fxWorldJson["version"].get<int>() : 0;
|
||||||
|
if (version != IW4X_FXWORLD_VERSION)
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid FXWORLD json version for {}, expected {} and got {}\n", name, IW4X_FXWORLD_VERSION, version);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto map = builder->getAllocator()->allocate<Game::FxWorld>();
|
||||||
|
map->name = builder->getAllocator()->duplicateString(_name);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto glassSys = &map->glassSys;
|
||||||
|
auto glassSysJson = fxWorldJson["glassSys"];
|
||||||
|
|
||||||
|
glassSys->time = glassSysJson["time"].get<int>();
|
||||||
|
glassSys->prevTime = glassSysJson["prevTime"].get<int>();
|
||||||
|
glassSys->defCount = glassSysJson["defCount"].get<unsigned int>();
|
||||||
|
glassSys->pieceLimit = glassSysJson["pieceLimit"].get<unsigned int>();
|
||||||
|
glassSys->pieceWordCount = glassSysJson["pieceWordCount"].get<unsigned int>();
|
||||||
|
glassSys->initPieceCount = glassSysJson["initPieceCount"].get<unsigned int>();
|
||||||
|
glassSys->cellCount = glassSysJson["cellCount"].get<unsigned int>();
|
||||||
|
glassSys->activePieceCount = glassSysJson["activePieceCount"].get<unsigned int>();
|
||||||
|
glassSys->firstFreePiece = glassSysJson["firstFreePiece"].get<unsigned int>();
|
||||||
|
glassSys->geoDataLimit = glassSysJson["geoDataLimit"].get<unsigned int>();
|
||||||
|
glassSys->geoDataCount = glassSysJson["geoDataCount"].get<unsigned int>();
|
||||||
|
glassSys->initGeoDataCount = glassSysJson["initGeoDataCount"].get<unsigned int>();
|
||||||
|
|
||||||
|
auto i = 0;
|
||||||
|
glassSys->defs = builder->getAllocator()->allocateArray<Game::FxGlassDef>(glassSys->defCount);
|
||||||
|
for (auto member : glassSysJson["defs"])
|
||||||
|
{
|
||||||
|
auto def = &glassSys->defs[i];
|
||||||
|
|
||||||
|
def->halfThickness = member["halfThickness"].get<float>();
|
||||||
|
|
||||||
|
auto xy = 0;
|
||||||
|
for (auto x = 0; x < 2; x++)
|
||||||
|
{
|
||||||
|
for (auto y = 0; y < 2; y++)
|
||||||
|
{
|
||||||
|
def->texVecs[x][y] = member["texVecs"][xy].get<float>();
|
||||||
|
xy++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def->color.packed = member["color"].get<int>();
|
||||||
|
|
||||||
|
auto matShateredName = member["materialShattered"].get<std::string>();
|
||||||
|
auto matName = member["material"].get<std::string>();
|
||||||
|
auto physPresetName = member["physPreset"].get<std::string>();
|
||||||
|
def->material = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_MATERIAL, matName, builder).material;
|
||||||
|
def->materialShattered = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_MATERIAL, matShateredName, builder).material;
|
||||||
|
def->physPreset = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_PHYSPRESET, physPresetName, builder ).physPreset;
|
||||||
|
|
||||||
|
assert(def->material);
|
||||||
|
assert(def->materialShattered);
|
||||||
|
assert(def->physPreset);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
glassSys->initPieceStates = builder->getAllocator()->allocateArray<Game::FxGlassInitPieceState>(glassSys->initPieceCount);
|
||||||
|
for (auto member : glassSysJson["initPieceStates"])
|
||||||
|
{
|
||||||
|
auto initial = &glassSys->initPieceStates[i];
|
||||||
|
|
||||||
|
for (int j = 0; j < ARRAYSIZE(initial->frame.quat); j++)
|
||||||
|
{
|
||||||
|
initial->frame.quat[j] = member["frame"]["quat"][j].get<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < ARRAYSIZE(initial->frame.origin); j++)
|
||||||
|
{
|
||||||
|
initial->frame.origin[j] = member["frame"]["origin"][j].get<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
initial->radius = member["radius"].get<float>();
|
||||||
|
initial->texCoordOrigin[0] = member["texCoordOrigin"][0].get<float>();
|
||||||
|
initial->texCoordOrigin[1] = member["texCoordOrigin"][1].get<float>();
|
||||||
|
initial->supportMask = member["supportMask"].get<int>();
|
||||||
|
initial->areaX2 = member["areaX2"].get<float>();
|
||||||
|
initial->defIndex = member["defIndex"].get<char>();
|
||||||
|
initial->vertCount = member["vertCount"].get<char>();
|
||||||
|
initial->fanDataCount = member["fanDataCount"].get<char>();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
glassSys->initGeoData = builder->getAllocator()->allocateArray<Game::FxGlassGeometryData>(glassSys->initGeoDataCount);
|
||||||
|
for (auto member : glassSysJson["initGeoData"])
|
||||||
|
{
|
||||||
|
auto data = &glassSys->initGeoData[i];
|
||||||
|
data->anonymous[0] = member[0];
|
||||||
|
data->anonymous[1] = member[1];
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const nlohmann::json::exception& e)
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Malformed FXWORLD JSON for {}! Error message: {}\n", name, e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
map->glassSys.piecePlaces = builder->getAllocator()->allocateArray<Game::FxGlassPiecePlace>(map->glassSys.pieceLimit);
|
||||||
|
map->glassSys.pieceStates = builder->getAllocator()->allocateArray<Game::FxGlassPieceState>(map->glassSys.pieceLimit);
|
||||||
|
map->glassSys.pieceDynamics = builder->getAllocator()->allocateArray<Game::FxGlassPieceDynamics>(map->glassSys.pieceLimit);
|
||||||
|
map->glassSys.geoData = builder->getAllocator()->allocateArray<Game::FxGlassGeometryData>(map->glassSys.geoDataLimit);
|
||||||
|
map->glassSys.isInUse = builder->getAllocator()->allocateArray<unsigned int>(map->glassSys.pieceWordCount);
|
||||||
|
map->glassSys.cellBits = builder->getAllocator()->allocateArray<unsigned int>(map->glassSys.pieceWordCount * map->glassSys.cellCount);
|
||||||
|
map->glassSys.visData = builder->getAllocator()->allocateArray<char>((map->glassSys.pieceLimit + 15) & 0xFFFFFFF0); // ugh
|
||||||
|
map->glassSys.linkOrg = reinterpret_cast<float(*)[3]>(builder->getAllocator()->allocateArray<float>(map->glassSys.pieceLimit));
|
||||||
|
map->glassSys.halfThickness = builder->getAllocator()->allocateArray<float>(map->glassSys.pieceLimit * 3);
|
||||||
|
map->glassSys.lightingHandles = builder->getAllocator()->allocateArray<unsigned short>(map->glassSys.initPieceCount);
|
||||||
|
|
||||||
|
header->fxWorld = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
Game::FxWorld* map = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FXWORLD, name.data()).fxWorld;
|
||||||
if (map) return;
|
if (map) return;
|
||||||
@ -194,7 +354,7 @@ namespace Assets
|
|||||||
// Generate
|
// Generate
|
||||||
map = builder->getAllocator()->allocate<Game::FxWorld>();
|
map = builder->getAllocator()->allocate<Game::FxWorld>();
|
||||||
map->name = builder->getAllocator()->duplicateString(name);
|
map->name = builder->getAllocator()->duplicateString(name);
|
||||||
|
|
||||||
// No glass for you!
|
// No glass for you!
|
||||||
ZeroMemory(&map->glassSys, sizeof(map->glassSys));
|
ZeroMemory(&map->glassSys, sizeof(map->glassSys));
|
||||||
|
|
||||||
|
@ -10,5 +10,7 @@ namespace Assets
|
|||||||
void save(Game::XAssetHeader header, 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 mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||||
void load(Game::XAssetHeader* header, const std::string& name, 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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
nlohmann::json::array_t jsonPiecesIndices = jsonGlassName["piecesIndices"];
|
nlohmann::json::array_t jsonPiecesIndices = jsonGlassName["piecesIndices"];
|
||||||
glassData->glassNames[i].pieceCount = static_cast<unsigned short>(jsonPiecesIndices.size());
|
glassData->glassNames[i].pieceCount = static_cast<unsigned short>(jsonPiecesIndices.size());
|
||||||
|
glassData->glassNames[i].pieceIndices = builder->getAllocator()->allocateArray<unsigned short>(glassData->glassNames[i].pieceCount);
|
||||||
for (size_t j = 0; j < glassData->glassNames[i].pieceCount; j++)
|
for (size_t j = 0; j < glassData->glassNames[i].pieceCount; j++)
|
||||||
{
|
{
|
||||||
glassData->glassNames[i].pieceIndices[j] = jsonPiecesIndices[j].get<unsigned short>();
|
glassData->glassNames[i].pieceIndices[j] = jsonPiecesIndices[j].get<unsigned short>();
|
||||||
@ -162,9 +162,9 @@ namespace Assets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameWorldJson["glassPieces"].is_array())
|
if (jsonGlassData["glassPieces"].is_array())
|
||||||
{
|
{
|
||||||
nlohmann::json::array_t glassPieces = gameWorldJson["glassPieces"];
|
nlohmann::json::array_t glassPieces = jsonGlassData["glassPieces"];
|
||||||
glassData->pieceCount = glassPieces.size();
|
glassData->pieceCount = glassPieces.size();
|
||||||
glassData->glassPieces = builder->getAllocator()->allocateArray<Game::G_GlassPiece>(glassData->pieceCount);
|
glassData->glassPieces = builder->getAllocator()->allocateArray<Game::G_GlassPiece>(glassData->pieceCount);
|
||||||
|
|
||||||
|
@ -3,27 +3,6 @@
|
|||||||
|
|
||||||
#define IW4X_GFXMAP_VERSION 1
|
#define IW4X_GFXMAP_VERSION 1
|
||||||
|
|
||||||
// The xmodel vehicle_small_hatch_green_destructible_mp causes EXTREME lag
|
|
||||||
// when placed in the world, for reasons unknown.
|
|
||||||
//
|
|
||||||
// Something happens with the SModelSurfIterator which makes it load garbage
|
|
||||||
// as an XSurface in the middle of otherwise valid surfaces. This bug is very
|
|
||||||
// easy to reproduce with an empty map and just this car in the middle
|
|
||||||
//
|
|
||||||
// As of know we do not know why the iterator corruption occurs or what causes
|
|
||||||
// it. It doesn't seem linked to the SModel, nor to the materials or techsets,
|
|
||||||
// nor to the sortkeys, nor to the tilemode, boneinfo, and so on. So for now
|
|
||||||
// and to make it work for majority of users, we just swap the car. (no, using
|
|
||||||
// the identical car from iw4's favela_escape doesn't work either!)
|
|
||||||
//
|
|
||||||
// Two other models have this problem: ch_apartment_9story_noentry_02 and
|
|
||||||
// ch_apartment_5story_noentry_01
|
|
||||||
// But these exist in mp_vacant in slightly different versions, and can be
|
|
||||||
// swapped safely by deleting the two .iw4XModel files and requiring mp_vacant
|
|
||||||
// or a minimal zone containing just these two models.
|
|
||||||
//
|
|
||||||
#define SWAP_GREEN_VEHICLE_XMODEL 1
|
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
void IGfxWorld::loadGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader)
|
void IGfxWorld::loadGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader)
|
||||||
@ -44,11 +23,12 @@ namespace Assets
|
|||||||
|
|
||||||
for (unsigned int i = 0; i < world->surfaceCount; ++i)
|
for (unsigned int i = 0; i < world->surfaceCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxSurface* surface = &asset->surfaces[i];
|
auto* surface = &asset->surfaces[i];
|
||||||
|
|
||||||
if (surface->material)
|
if (surface->material)
|
||||||
{
|
{
|
||||||
world->dpvs.surfaces[i].material = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader->readString().data(), builder).material;
|
auto materialName = reader->readString();
|
||||||
|
world->dpvs.surfaces[i].material = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_MATERIAL, materialName, builder).material;
|
||||||
|
assert(world->dpvs.surfaces[i].material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,8 +49,19 @@ namespace Assets
|
|||||||
if (model->model)
|
if (model->model)
|
||||||
{
|
{
|
||||||
auto name = reader->readString();
|
auto name = reader->readString();
|
||||||
|
while (name.ends_with("."))
|
||||||
|
{
|
||||||
|
// Happens with some flowers in mp_paris
|
||||||
|
// I'm not confident this will work on every map
|
||||||
|
// But regardless Game FS does not support having a file terminated with "."
|
||||||
|
// Probably an artist made a typo in MW3...
|
||||||
|
// Example: "foliage_gardenflowers_red_bright..iw4xModel"
|
||||||
|
name = name.substr(0, name.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!name.empty());
|
||||||
|
|
||||||
model->model = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_XMODEL, name.data(), builder).model;
|
model->model = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_XMODEL, name, builder).model;
|
||||||
|
|
||||||
assert(model->model);
|
assert(model->model);
|
||||||
}
|
}
|
||||||
@ -86,7 +77,7 @@ namespace Assets
|
|||||||
|
|
||||||
for (unsigned int i = 0; i < asset->reflectionProbeCount; ++i)
|
for (unsigned int i = 0; i < asset->reflectionProbeCount; ++i)
|
||||||
{
|
{
|
||||||
asset->reflectionProbes[i] = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader->readString().data(), builder).image;
|
asset->reflectionProbes[i] = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_IMAGE, reader->readString(), builder).image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,28 +92,27 @@ namespace Assets
|
|||||||
|
|
||||||
for (int i = 0; i < asset->lightmapCount; ++i)
|
for (int i = 0; i < asset->lightmapCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxLightmapArray* lightmapArray = &asset->lightmaps[i];
|
auto* lightmapArray = &asset->lightmaps[i];
|
||||||
|
|
||||||
if (lightmapArray->primary)
|
if (lightmapArray->primary)
|
||||||
{
|
{
|
||||||
lightmapArray->primary = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader->readString().data(), builder).image;
|
lightmapArray->primary = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_IMAGE, reader->readString(), builder).image;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lightmapArray->secondary)
|
if (lightmapArray->secondary)
|
||||||
{
|
{
|
||||||
lightmapArray->secondary = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader->readString().data(), builder).image;
|
lightmapArray->secondary = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_IMAGE, reader->readString(), builder).image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->lightmapOverridePrimary)
|
if (asset->lightmapOverridePrimary)
|
||||||
{
|
{
|
||||||
asset->lightmapOverridePrimary = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader->readString().data(), builder).image;
|
asset->lightmapOverridePrimary = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_IMAGE, reader->readString(), builder).image;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset->lightmapOverrideSecondary)
|
if (asset->lightmapOverrideSecondary)
|
||||||
{
|
{
|
||||||
asset->lightmapOverrideSecondary = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader->readString().data(), builder).image;
|
asset->lightmapOverrideSecondary = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_IMAGE, reader->readString(), builder).image;
|
||||||
}
|
}
|
||||||
|
|
||||||
// saveGfxWorldVertexData
|
// saveGfxWorldVertexData
|
||||||
@ -156,295 +146,305 @@ namespace Assets
|
|||||||
|
|
||||||
Components::FileSystem::File mapFile(std::format("gfxworld/{}.iw4xGfxWorld", name));
|
Components::FileSystem::File mapFile(std::format("gfxworld/{}.iw4xGfxWorld", name));
|
||||||
|
|
||||||
if (mapFile.exists())
|
if (!mapFile.exists())
|
||||||
{
|
{
|
||||||
Utils::Stream::Reader reader(builder->getAllocator(), mapFile.getBuffer());
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
__int64 magic = reader.read<__int64>();
|
Utils::Stream::Reader reader(builder->getAllocator(), mapFile.getBuffer());
|
||||||
if (std::memcmp(&magic, "IW4xGfxW", 8))
|
|
||||||
|
auto magic = reader.read<std::int64_t>();
|
||||||
|
if (std::memcmp(&magic, "IW4xGfxW", 8) != 0)
|
||||||
|
{
|
||||||
|
Components::Logger::Error(Game::ERR_FATAL, "Reading gfxworld '{}' failed, header is invalid!", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int version = reader.read<int>();
|
||||||
|
if (version != IW4X_GFXMAP_VERSION)
|
||||||
|
{
|
||||||
|
Components::Logger::Error(Game::ERR_FATAL, "Reading gfxworld '{}' failed, expected version is {}, but it was {}!", name, IW4X_GFXMAP_VERSION, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* asset = reader.readObject<Game::GfxWorld>();
|
||||||
|
header->gfxWorld = asset;
|
||||||
|
|
||||||
|
if (asset->name)
|
||||||
|
{
|
||||||
|
asset->name = reader.readCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->baseName)
|
||||||
|
{
|
||||||
|
asset->baseName = reader.readCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->skies)
|
||||||
|
{
|
||||||
|
asset->skies = reader.readArray<Game::GfxSky>(asset->skyCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < asset->skyCount; ++i)
|
||||||
{
|
{
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading gfxworld '{}' failed, header is invalid!", name);
|
auto* sky = &asset->skies[i];
|
||||||
}
|
|
||||||
|
|
||||||
int version = reader.read<int>();
|
if (sky->skyStartSurfs)
|
||||||
if (version != IW4X_GFXMAP_VERSION)
|
|
||||||
{
|
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading gfxworld '{}' failed, expected version is {}, but it was {}!", name, IW4X_GFXMAP_VERSION, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
Game::GfxWorld* asset = reader.readObject<Game::GfxWorld>();
|
|
||||||
header->gfxWorld = asset;
|
|
||||||
|
|
||||||
if (asset->name)
|
|
||||||
{
|
|
||||||
asset->name = reader.readCString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->baseName)
|
|
||||||
{
|
|
||||||
asset->baseName = reader.readCString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->skies)
|
|
||||||
{
|
|
||||||
asset->skies = reader.readArray<Game::GfxSky>(asset->skyCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < asset->skyCount; ++i)
|
|
||||||
{
|
{
|
||||||
Game::GfxSky* sky = &asset->skies[i];
|
sky->skyStartSurfs = reader.readArray<int>(sky->skySurfCount);
|
||||||
|
}
|
||||||
|
|
||||||
if (sky->skyStartSurfs)
|
if (sky->skyImage)
|
||||||
|
{
|
||||||
|
sky->skyImage = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_IMAGE, reader.readString(), builder).image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GfxWorldDpvsPlanes
|
||||||
|
{
|
||||||
|
if (asset->dpvsPlanes.planes)
|
||||||
|
{
|
||||||
|
asset->dpvsPlanes.planes = reader.readArray<Game::cplane_s>(asset->planeCount);
|
||||||
|
|
||||||
|
auto clip = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_CLIPMAP_MP, asset->name, builder).clipMap;
|
||||||
|
if (clip)
|
||||||
|
{
|
||||||
|
assert(clip->planeCount == static_cast<unsigned int>(asset->planeCount));
|
||||||
|
for (size_t i = 0; i < clip->planeCount; i++)
|
||||||
{
|
{
|
||||||
sky->skyStartSurfs = reader.readArray<int>(sky->skySurfCount);
|
assert(!std::memcmp(&clip->planes[i], &asset->dpvsPlanes.planes[i], sizeof Game::cplane_s));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sky->skyImage)
|
asset->dpvsPlanes.planes = clip->planes;
|
||||||
{
|
}
|
||||||
sky->skyImage = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image;
|
else
|
||||||
}
|
{
|
||||||
|
Components::Logger::Error(Game::ERR_FATAL, "GfxWorld dpvs planes not mapped. This shouldn't happen. Make sure to load the ClipMap first!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GfxWorldDpvsPlanes
|
if (asset->dpvsPlanes.nodes)
|
||||||
{
|
{
|
||||||
if (asset->dpvsPlanes.planes)
|
asset->dpvsPlanes.nodes = reader.readArray<unsigned short>(asset->nodeCount);
|
||||||
{
|
|
||||||
void* oldPtr = asset->dpvsPlanes.planes;
|
|
||||||
asset->dpvsPlanes.planes = reader.readArray<Game::cplane_s>(asset->planeCount);
|
|
||||||
|
|
||||||
if (builder->getAllocator()->isPointerMapped(oldPtr))
|
|
||||||
{
|
|
||||||
asset->dpvsPlanes.planes = builder->getAllocator()->getPointer<Game::cplane_s>(oldPtr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder->getAllocator()->mapPointer(oldPtr, asset->dpvsPlanes.planes);
|
|
||||||
Components::Logger::Print("GfxWorld dpvs planes not mapped. This shouldn't happen. Make sure to load the ClipMap first!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->dpvsPlanes.nodes)
|
|
||||||
{
|
|
||||||
asset->dpvsPlanes.nodes = reader.readArray<unsigned short>(asset->nodeCount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cellCount = asset->dpvsPlanes.cellCount;
|
||||||
|
|
||||||
int cellCount = asset->dpvsPlanes.cellCount;
|
if (asset->aabbTreeCounts)
|
||||||
|
{
|
||||||
|
asset->aabbTreeCounts = reader.readArray<Game::GfxCellTreeCount>(cellCount);
|
||||||
|
}
|
||||||
|
|
||||||
if (asset->aabbTreeCounts)
|
if (asset->aabbTrees)
|
||||||
|
{
|
||||||
|
asset->aabbTrees = reader.readArray<Game::GfxCellTree>(cellCount);
|
||||||
|
|
||||||
|
for (auto i = 0; i < cellCount; ++i)
|
||||||
{
|
{
|
||||||
asset->aabbTreeCounts = reader.readArray<Game::GfxCellTreeCount>(cellCount);
|
auto* cellTree = &asset->aabbTrees[i];
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->aabbTrees)
|
if (cellTree->aabbTree)
|
||||||
{
|
|
||||||
asset->aabbTrees = reader.readArray<Game::GfxCellTree>(cellCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < cellCount; ++i)
|
|
||||||
{
|
{
|
||||||
Game::GfxCellTree* cellTree = &asset->aabbTrees[i];
|
cellTree->aabbTree = reader.readArray<Game::GfxAabbTree>(asset->aabbTreeCounts[i].aabbTreeCount);
|
||||||
|
|
||||||
if (cellTree->aabbTree)
|
for (int j = 0; j < asset->aabbTreeCounts[i].aabbTreeCount; ++j)
|
||||||
{
|
{
|
||||||
cellTree->aabbTree = reader.readArray<Game::GfxAabbTree>(asset->aabbTreeCounts[i].aabbTreeCount);
|
auto* aabbTree = &cellTree->aabbTree[j];
|
||||||
|
|
||||||
for (int j = 0; j < asset->aabbTreeCounts[i].aabbTreeCount; ++j)
|
if (aabbTree->smodelIndexes)
|
||||||
{
|
{
|
||||||
Game::GfxAabbTree* aabbTree = &cellTree->aabbTree[j];
|
auto* oldPointer = aabbTree->smodelIndexes;
|
||||||
|
if (builder->getAllocator()->isPointerMapped(oldPointer))
|
||||||
if (aabbTree->smodelIndexes)
|
|
||||||
{
|
{
|
||||||
unsigned short* oldPointer = aabbTree->smodelIndexes;
|
// We still have to read it
|
||||||
if(builder->getAllocator()->isPointerMapped(oldPointer))
|
reader.readArray<unsigned short>(aabbTree->smodelIndexCount);
|
||||||
{
|
|
||||||
// We still have to read it
|
|
||||||
reader.readArray<unsigned short>(aabbTree->smodelIndexCount);
|
|
||||||
|
|
||||||
aabbTree->smodelIndexes = builder->getAllocator()->getPointer<unsigned short>(oldPointer);
|
aabbTree->smodelIndexes = builder->getAllocator()->getPointer<unsigned short>(oldPointer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
aabbTree->smodelIndexes = reader.readArray<unsigned short>(aabbTree->smodelIndexCount);
|
aabbTree->smodelIndexes = reader.readArray<unsigned short>(aabbTree->smodelIndexCount);
|
||||||
|
|
||||||
for (unsigned short k = 0; k < aabbTree->smodelIndexCount; ++k)
|
for (unsigned short k = 0; k < aabbTree->smodelIndexCount; ++k)
|
||||||
{
|
{
|
||||||
builder->getAllocator()->mapPointer(&oldPointer[k], &aabbTree->smodelIndexes[k]);
|
builder->getAllocator()->mapPointer(&oldPointer[k], &aabbTree->smodelIndexes[k]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (asset->cells)
|
if (asset->cells)
|
||||||
|
{
|
||||||
|
asset->cells = reader.readArray<Game::GfxCell>(cellCount);
|
||||||
|
|
||||||
|
for (auto i = 0; i < cellCount; ++i)
|
||||||
{
|
{
|
||||||
asset->cells = reader.readArray<Game::GfxCell>(cellCount);
|
auto* cell = &asset->cells[i];
|
||||||
|
|
||||||
for (int i = 0; i < cellCount; ++i)
|
if (cell->portals)
|
||||||
{
|
{
|
||||||
Game::GfxCell* cell = &asset->cells[i];
|
cell->portals = reader.readArray<Game::GfxPortal>(cell->portalCount);
|
||||||
|
|
||||||
if (cell->portals)
|
for (auto j = 0; j < cell->portalCount; ++j)
|
||||||
{
|
{
|
||||||
cell->portals = reader.readArray<Game::GfxPortal>(cell->portalCount);
|
auto* portal = &cell->portals[j];
|
||||||
|
if (portal->vertices)
|
||||||
for (int j = 0; j < cell->portalCount; ++j)
|
|
||||||
{
|
{
|
||||||
Game::GfxPortal* portal = &cell->portals[j];
|
portal->vertices = reader.readArray<Game::vec3_t>(portal->vertexCount);
|
||||||
|
|
||||||
if (portal->vertices)
|
|
||||||
{
|
|
||||||
portal->vertices = reader.readArray<Game::vec3_t>(portal->vertexCount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cell->reflectionProbes)
|
if (cell->reflectionProbes)
|
||||||
|
{
|
||||||
|
cell->reflectionProbes = reader.readArray<char>(cell->reflectionProbeCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->loadGfxWorldDraw(&asset->draw, builder, &reader);
|
||||||
|
|
||||||
|
// GfxLightGrid
|
||||||
|
{
|
||||||
|
if (asset->lightGrid.rowDataStart)
|
||||||
|
{
|
||||||
|
asset->lightGrid.rowDataStart = reader.readArray<unsigned short>((asset->lightGrid.maxs[asset->lightGrid.rowAxis] - asset->lightGrid.mins[asset->lightGrid.rowAxis]) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->lightGrid.rawRowData)
|
||||||
|
{
|
||||||
|
asset->lightGrid.rawRowData = reader.readArray<char>(asset->lightGrid.rawRowDataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->lightGrid.entries)
|
||||||
|
{
|
||||||
|
asset->lightGrid.entries = reader.readArray<Game::GfxLightGridEntry>(asset->lightGrid.entryCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->lightGrid.colors)
|
||||||
|
{
|
||||||
|
asset->lightGrid.colors = reader.readArray<Game::GfxLightGridColors>(asset->lightGrid.colorCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->models)
|
||||||
|
{
|
||||||
|
asset->models = reader.readArray<Game::GfxBrushModel>(asset->modelCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->materialMemory)
|
||||||
|
{
|
||||||
|
asset->materialMemory = reader.readArray<Game::MaterialMemory>(asset->materialMemoryCount);
|
||||||
|
|
||||||
|
for (auto i = 0; i < asset->materialMemoryCount; ++i)
|
||||||
|
{
|
||||||
|
auto* materialMemory = &asset->materialMemory[i];
|
||||||
|
if (materialMemory->material)
|
||||||
|
{
|
||||||
|
auto materialName = reader.readString();
|
||||||
|
materialMemory->material = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_MATERIAL, materialName, builder).material;
|
||||||
|
assert(materialMemory->material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->sun.spriteMaterial)
|
||||||
|
{
|
||||||
|
auto materialName = reader.readString();
|
||||||
|
asset->sun.spriteMaterial = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_MATERIAL, materialName, builder).material;
|
||||||
|
assert(asset->sun.spriteMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->sun.flareMaterial)
|
||||||
|
{
|
||||||
|
auto materialName = reader.readString();
|
||||||
|
asset->sun.flareMaterial = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_MATERIAL, materialName, builder).material;
|
||||||
|
assert(asset->sun.flareMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->outdoorImage)
|
||||||
|
{
|
||||||
|
auto materialName = reader.readString();
|
||||||
|
asset->outdoorImage = Components::AssetHandler::FindAssetForZone(Game::ASSET_TYPE_IMAGE, materialName, builder).image;
|
||||||
|
assert(asset->outdoorImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->primaryLightCount > 0)
|
||||||
|
{
|
||||||
|
Utils::Stream::ClearPointer(&asset->primaryLightEntityShadowVis);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->dpvsDyn.dynEntClientCount[0] > 0)
|
||||||
|
{
|
||||||
|
Utils::Stream::ClearPointer(&asset->sceneDynModel);
|
||||||
|
Utils::Stream::ClearPointer(&asset->primaryLightDynEntShadowVis[0]);
|
||||||
|
Utils::Stream::ClearPointer(&asset->nonSunPrimaryLightForModelDynEnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->dpvsDyn.dynEntClientCount[1] > 0)
|
||||||
|
{
|
||||||
|
Utils::Stream::ClearPointer(&asset->sceneDynBrush);
|
||||||
|
Utils::Stream::ClearPointer(&asset->primaryLightDynEntShadowVis[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->shadowGeom)
|
||||||
|
{
|
||||||
|
asset->shadowGeom = reader.readArray<Game::GfxShadowGeometry>(asset->primaryLightCount);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
|
||||||
|
{
|
||||||
|
auto* shadowGeometry = &asset->shadowGeom[i];
|
||||||
|
|
||||||
|
if (shadowGeometry->sortedSurfIndex)
|
||||||
|
{
|
||||||
|
shadowGeometry->sortedSurfIndex = reader.readArray<unsigned short>(shadowGeometry->surfaceCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowGeometry->smodelIndex)
|
||||||
|
{
|
||||||
|
shadowGeometry->smodelIndex = reader.readArray<unsigned short>(shadowGeometry->smodelCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->lightRegion)
|
||||||
|
{
|
||||||
|
asset->lightRegion = reader.readArray<Game::GfxLightRegion>(asset->primaryLightCount);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
|
||||||
|
{
|
||||||
|
auto* lightRegion = &asset->lightRegion[i];
|
||||||
|
|
||||||
|
if (lightRegion->hulls)
|
||||||
|
{
|
||||||
|
lightRegion->hulls = reader.readArray<Game::GfxLightRegionHull>(lightRegion->hullCount);
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < lightRegion->hullCount; ++j)
|
||||||
{
|
{
|
||||||
cell->reflectionProbes = reader.readArray<char>(cell->reflectionProbeCount);
|
auto* lightRegionHull = &lightRegion->hulls[j];
|
||||||
}
|
if (lightRegionHull->axis)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->loadGfxWorldDraw(&asset->draw, builder, &reader);
|
|
||||||
|
|
||||||
// GfxLightGrid
|
|
||||||
{
|
|
||||||
if (asset->lightGrid.rowDataStart)
|
|
||||||
{
|
|
||||||
asset->lightGrid.rowDataStart = reader.readArray<unsigned short>((asset->lightGrid.maxs[asset->lightGrid.rowAxis] - asset->lightGrid.mins[asset->lightGrid.rowAxis]) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->lightGrid.rawRowData)
|
|
||||||
{
|
|
||||||
asset->lightGrid.rawRowData = reader.readArray<char>(asset->lightGrid.rawRowDataSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->lightGrid.entries)
|
|
||||||
{
|
|
||||||
asset->lightGrid.entries = reader.readArray<Game::GfxLightGridEntry>(asset->lightGrid.entryCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->lightGrid.colors)
|
|
||||||
{
|
|
||||||
asset->lightGrid.colors = reader.readArray<Game::GfxLightGridColors>(asset->lightGrid.colorCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->models)
|
|
||||||
{
|
|
||||||
asset->models = reader.readArray<Game::GfxBrushModel>(asset->modelCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->materialMemory)
|
|
||||||
{
|
|
||||||
asset->materialMemory = reader.readArray<Game::MaterialMemory>(asset->materialMemoryCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < asset->materialMemoryCount; ++i)
|
|
||||||
{
|
|
||||||
Game::MaterialMemory* materialMemory = &asset->materialMemory[i];
|
|
||||||
|
|
||||||
if (materialMemory->material)
|
|
||||||
{
|
|
||||||
materialMemory->material = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.readString().data(), builder).material;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->sun.spriteMaterial)
|
|
||||||
{
|
|
||||||
asset->sun.spriteMaterial = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.readString().data(), builder).material;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->sun.flareMaterial)
|
|
||||||
{
|
|
||||||
asset->sun.flareMaterial = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_MATERIAL, reader.readString().data(), builder).material;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->outdoorImage)
|
|
||||||
{
|
|
||||||
asset->outdoorImage = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->primaryLightCount > 0)
|
|
||||||
{
|
|
||||||
Utils::Stream::ClearPointer(&asset->primaryLightEntityShadowVis);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->dpvsDyn.dynEntClientCount[0] > 0)
|
|
||||||
{
|
|
||||||
Utils::Stream::ClearPointer(&asset->sceneDynModel);
|
|
||||||
Utils::Stream::ClearPointer(&asset->primaryLightDynEntShadowVis[0]);
|
|
||||||
Utils::Stream::ClearPointer(&asset->nonSunPrimaryLightForModelDynEnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->dpvsDyn.dynEntClientCount[1] > 0)
|
|
||||||
{
|
|
||||||
Utils::Stream::ClearPointer(&asset->sceneDynBrush);
|
|
||||||
Utils::Stream::ClearPointer(&asset->primaryLightDynEntShadowVis[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->shadowGeom)
|
|
||||||
{
|
|
||||||
asset->shadowGeom = reader.readArray<Game::GfxShadowGeometry>(asset->primaryLightCount);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
|
|
||||||
{
|
|
||||||
Game::GfxShadowGeometry* shadowGeometry = &asset->shadowGeom[i];
|
|
||||||
|
|
||||||
if (shadowGeometry->sortedSurfIndex)
|
|
||||||
{
|
|
||||||
shadowGeometry->sortedSurfIndex = reader.readArray<unsigned short>(shadowGeometry->surfaceCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shadowGeometry->smodelIndex)
|
|
||||||
{
|
|
||||||
shadowGeometry->smodelIndex = reader.readArray<unsigned short>(shadowGeometry->smodelCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset->lightRegion)
|
|
||||||
{
|
|
||||||
asset->lightRegion = reader.readArray<Game::GfxLightRegion>(asset->primaryLightCount);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
|
|
||||||
{
|
|
||||||
Game::GfxLightRegion* lightRegion = &asset->lightRegion[i];
|
|
||||||
|
|
||||||
if (lightRegion->hulls)
|
|
||||||
{
|
|
||||||
lightRegion->hulls = reader.readArray<Game::GfxLightRegionHull>(lightRegion->hullCount);
|
|
||||||
|
|
||||||
for (unsigned int j = 0; j < lightRegion->hullCount; ++j)
|
|
||||||
{
|
{
|
||||||
Game::GfxLightRegionHull* lightRegionHull = &lightRegion->hulls[j];
|
lightRegionHull->axis = reader.readArray<Game::GfxLightRegionAxis>(lightRegionHull->axisCount);
|
||||||
|
|
||||||
if (lightRegionHull->axis)
|
|
||||||
{
|
|
||||||
lightRegionHull->axis = reader.readArray<Game::GfxLightRegionAxis>(lightRegionHull->axisCount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->loadGfxWorldDpvsStatic(asset, &asset->dpvs, builder, &reader);
|
this->loadGfxWorldDpvsStatic(asset, &asset->dpvs, builder, &reader);
|
||||||
|
|
||||||
// Obsolete, IW3 has no support for that
|
// Obsolete, IW3 has no support for that
|
||||||
if (asset->heroOnlyLights)
|
if (asset->heroOnlyLights)
|
||||||
{
|
{
|
||||||
asset->heroOnlyLights = reader.readArray<Game::GfxHeroOnlyLight>(asset->heroOnlyLightCount);
|
asset->heroOnlyLights = reader.readArray<Game::GfxHeroOnlyLight>(asset->heroOnlyLightCount);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGfxWorld::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IGfxWorld::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
Game::GfxWorld* asset = header.gfxWorld;
|
auto* asset = header.gfxWorld;
|
||||||
|
|
||||||
if (asset->draw.reflectionProbes)
|
if (asset->draw.reflectionProbes)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < asset->draw.reflectionProbeCount; ++i)
|
for (unsigned int i = 0; i < asset->draw.reflectionProbeCount; ++i)
|
||||||
@ -455,7 +455,7 @@ namespace Assets
|
|||||||
|
|
||||||
if (asset->draw.lightmaps)
|
if (asset->draw.lightmaps)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < asset->draw.lightmapCount; ++i)
|
for (auto i = 0; i < asset->draw.lightmapCount; ++i)
|
||||||
{
|
{
|
||||||
if (asset->draw.lightmaps[i].primary)
|
if (asset->draw.lightmaps[i].primary)
|
||||||
{
|
{
|
||||||
@ -599,7 +599,7 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
Game::GfxImage** imageDest = buffer->dest<Game::GfxImage*>();
|
auto** imageDest = buffer->dest<Game::GfxImage*>();
|
||||||
buffer->saveArray(asset->reflectionProbes, asset->reflectionProbeCount);
|
buffer->saveArray(asset->reflectionProbes, asset->reflectionProbeCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < asset->reflectionProbeCount; ++i)
|
for (unsigned int i = 0; i < asset->reflectionProbeCount; ++i)
|
||||||
@ -648,13 +648,13 @@ namespace Assets
|
|||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
|
|
||||||
Game::GfxLightmapArray* lightmapArrayDestTable = buffer->dest<Game::GfxLightmapArray>();
|
auto* lightmapArrayDestTable = buffer->dest<Game::GfxLightmapArray>();
|
||||||
buffer->saveArray(asset->lightmaps, asset->lightmapCount);
|
buffer->saveArray(asset->lightmaps, asset->lightmapCount);
|
||||||
|
|
||||||
for (int i = 0; i < asset->lightmapCount; ++i)
|
for (int i = 0; i < asset->lightmapCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxLightmapArray* lightmapArrayDest = &lightmapArrayDestTable[i];
|
auto* lightmapArrayDest = &lightmapArrayDestTable[i];
|
||||||
Game::GfxLightmapArray* lightmapArray = &asset->lightmaps[i];
|
auto* lightmapArray = &asset->lightmaps[i];
|
||||||
|
|
||||||
if (lightmapArray->primary)
|
if (lightmapArray->primary)
|
||||||
{
|
{
|
||||||
@ -854,13 +854,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxSurface");
|
SaveLogEnter("GfxSurface");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxSurface* destSurfaceTable = buffer->dest<Game::GfxSurface>();
|
auto* destSurfaceTable = buffer->dest<Game::GfxSurface>();
|
||||||
buffer->saveArray(asset->surfaces, world->surfaceCount);
|
buffer->saveArray(asset->surfaces, world->surfaceCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < world->surfaceCount; ++i)
|
for (unsigned int i = 0; i < world->surfaceCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxSurface* surface = &asset->surfaces[i];
|
auto* surface = &asset->surfaces[i];
|
||||||
Game::GfxSurface* destSurface = &destSurfaceTable[i];
|
auto* destSurface = &destSurfaceTable[i];
|
||||||
|
|
||||||
if (surface->material)
|
if (surface->material)
|
||||||
{
|
{
|
||||||
@ -890,13 +890,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxStaticModelDrawInst");
|
SaveLogEnter("GfxStaticModelDrawInst");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxStaticModelDrawInst* destModelTable = buffer->dest<Game::GfxStaticModelDrawInst>();
|
auto* destModelTable = buffer->dest<Game::GfxStaticModelDrawInst>();
|
||||||
buffer->saveArray(asset->smodelDrawInsts, asset->smodelCount);
|
buffer->saveArray(asset->smodelDrawInsts, asset->smodelCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < asset->smodelCount; ++i)
|
for (unsigned int i = 0; i < asset->smodelCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxStaticModelDrawInst* model = &asset->smodelDrawInsts[i];
|
auto* model = &asset->smodelDrawInsts[i];
|
||||||
Game::GfxStaticModelDrawInst* destModel = &destModelTable[i];
|
auto* destModel = &destModelTable[i];
|
||||||
|
|
||||||
if (model->model)
|
if (model->model)
|
||||||
{
|
{
|
||||||
@ -986,8 +986,8 @@ namespace Assets
|
|||||||
Utils::Stream* buffer = builder->getBuffer();
|
Utils::Stream* buffer = builder->getBuffer();
|
||||||
SaveLogEnter("GfxWorld");
|
SaveLogEnter("GfxWorld");
|
||||||
|
|
||||||
Game::GfxWorld* asset = header.gfxWorld;
|
auto* asset = header.gfxWorld;
|
||||||
Game::GfxWorld* dest = buffer->dest<Game::GfxWorld>();
|
auto* dest = buffer->dest<Game::GfxWorld>();
|
||||||
buffer->save(asset);
|
buffer->save(asset);
|
||||||
|
|
||||||
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
||||||
@ -1012,13 +1012,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxSky");
|
SaveLogEnter("GfxSky");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxSky* destSkyTable = buffer->dest<Game::GfxSky>();
|
auto* destSkyTable = buffer->dest<Game::GfxSky>();
|
||||||
buffer->saveArray(asset->skies, asset->skyCount);
|
buffer->saveArray(asset->skies, asset->skyCount);
|
||||||
|
|
||||||
for (int i = 0; i < asset->skyCount; ++i)
|
for (int i = 0; i < asset->skyCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxSky* destSky = &destSkyTable[i];
|
auto* destSky = &destSkyTable[i];
|
||||||
Game::GfxSky* sky = &asset->skies[i];
|
auto* sky = &asset->skies[i];
|
||||||
|
|
||||||
if (sky->skyStartSurfs)
|
if (sky->skyStartSurfs)
|
||||||
{
|
{
|
||||||
@ -1059,13 +1059,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxCellTree");
|
SaveLogEnter("GfxCellTree");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_128);
|
buffer->align(Utils::Stream::ALIGN_128);
|
||||||
Game::GfxCellTree* destCellTreeTable = buffer->dest<Game::GfxCellTree>();
|
auto* destCellTreeTable = buffer->dest<Game::GfxCellTree>();
|
||||||
buffer->saveArray(asset->aabbTrees, cellCount);
|
buffer->saveArray(asset->aabbTrees, cellCount);
|
||||||
|
|
||||||
for (int i = 0; i < cellCount; ++i)
|
for (int i = 0; i < cellCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxCellTree* destCellTree = &destCellTreeTable[i];
|
auto* destCellTree = &destCellTreeTable[i];
|
||||||
Game::GfxCellTree* cellTree = &asset->aabbTrees[i];
|
auto* cellTree = &asset->aabbTrees[i];
|
||||||
|
|
||||||
if (cellTree->aabbTree)
|
if (cellTree->aabbTree)
|
||||||
{
|
{
|
||||||
@ -1073,7 +1073,7 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxAabbTree");
|
SaveLogEnter("GfxAabbTree");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxAabbTree* destAabbTreeTable = buffer->dest<Game::GfxAabbTree>();
|
auto* destAabbTreeTable = buffer->dest<Game::GfxAabbTree>();
|
||||||
buffer->saveArray(cellTree->aabbTree, asset->aabbTreeCounts[i].aabbTreeCount);
|
buffer->saveArray(cellTree->aabbTree, asset->aabbTreeCounts[i].aabbTreeCount);
|
||||||
|
|
||||||
// ok this one is based on some assumptions because the actual count is this
|
// ok this one is based on some assumptions because the actual count is this
|
||||||
@ -1083,8 +1083,8 @@ namespace Assets
|
|||||||
|
|
||||||
for (int j = 0; j < asset->aabbTreeCounts[i].aabbTreeCount; ++j)
|
for (int j = 0; j < asset->aabbTreeCounts[i].aabbTreeCount; ++j)
|
||||||
{
|
{
|
||||||
Game::GfxAabbTree* destAabbTree = &destAabbTreeTable[j];
|
auto* destAabbTree = &destAabbTreeTable[j];
|
||||||
Game::GfxAabbTree* aabbTree = &cellTree->aabbTree[j];
|
auto* aabbTree = &cellTree->aabbTree[j];
|
||||||
|
|
||||||
if (aabbTree->smodelIndexes)
|
if (aabbTree->smodelIndexes)
|
||||||
{
|
{
|
||||||
@ -1122,13 +1122,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxCell");
|
SaveLogEnter("GfxCell");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxCell* destCellTable = buffer->dest<Game::GfxCell>();
|
auto* destCellTable = buffer->dest<Game::GfxCell>();
|
||||||
buffer->saveArray(asset->cells, cellCount);
|
buffer->saveArray(asset->cells, cellCount);
|
||||||
|
|
||||||
for (int i = 0; i < cellCount; ++i)
|
for (int i = 0; i < cellCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxCell* destCell = &destCellTable[i];
|
auto* destCell = &destCellTable[i];
|
||||||
Game::GfxCell* cell = &asset->cells[i];
|
auto* cell = &asset->cells[i];
|
||||||
|
|
||||||
if (cell->portals)
|
if (cell->portals)
|
||||||
{
|
{
|
||||||
@ -1136,13 +1136,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxPortal");
|
SaveLogEnter("GfxPortal");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxPortal* destPortalTable = buffer->dest<Game::GfxPortal>();
|
auto* destPortalTable = buffer->dest<Game::GfxPortal>();
|
||||||
buffer->saveArray(cell->portals, cell->portalCount);
|
buffer->saveArray(cell->portals, cell->portalCount);
|
||||||
|
|
||||||
for (int j = 0; j < cell->portalCount; ++j)
|
for (int j = 0; j < cell->portalCount; ++j)
|
||||||
{
|
{
|
||||||
Game::GfxPortal* destPortal = &destPortalTable[j];
|
auto* destPortal = &destPortalTable[j];
|
||||||
Game::GfxPortal* portal = &cell->portals[j];
|
auto* portal = &cell->portals[j];
|
||||||
|
|
||||||
if (portal->vertices)
|
if (portal->vertices)
|
||||||
{
|
{
|
||||||
@ -1189,13 +1189,13 @@ namespace Assets
|
|||||||
SaveLogEnter("MaterialMemory");
|
SaveLogEnter("MaterialMemory");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::MaterialMemory* destMaterialMemoryTable = buffer->dest<Game::MaterialMemory>();
|
auto* destMaterialMemoryTable = buffer->dest<Game::MaterialMemory>();
|
||||||
buffer->saveArray(asset->materialMemory, asset->materialMemoryCount);
|
buffer->saveArray(asset->materialMemory, asset->materialMemoryCount);
|
||||||
|
|
||||||
for (int i = 0; i < asset->materialMemoryCount; ++i)
|
for (int i = 0; i < asset->materialMemoryCount; ++i)
|
||||||
{
|
{
|
||||||
Game::MaterialMemory* destMaterialMemory = &destMaterialMemoryTable[i];
|
auto* destMaterialMemory = &destMaterialMemoryTable[i];
|
||||||
Game::MaterialMemory* materialMemory = &asset->materialMemory[i];
|
auto* materialMemory = &asset->materialMemory[i];
|
||||||
|
|
||||||
if (materialMemory->material)
|
if (materialMemory->material)
|
||||||
{
|
{
|
||||||
@ -1284,13 +1284,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxShadowGeometry");
|
SaveLogEnter("GfxShadowGeometry");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxShadowGeometry* destShadowGeometryTable = buffer->dest<Game::GfxShadowGeometry>();
|
auto* destShadowGeometryTable = buffer->dest<Game::GfxShadowGeometry>();
|
||||||
buffer->saveArray(asset->shadowGeom, asset->primaryLightCount);
|
buffer->saveArray(asset->shadowGeom, asset->primaryLightCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
|
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxShadowGeometry* destShadowGeometry = &destShadowGeometryTable[i];
|
auto* destShadowGeometry = &destShadowGeometryTable[i];
|
||||||
Game::GfxShadowGeometry* shadowGeometry = &asset->shadowGeom[i];
|
auto* shadowGeometry = &asset->shadowGeom[i];
|
||||||
|
|
||||||
if (shadowGeometry->sortedSurfIndex)
|
if (shadowGeometry->sortedSurfIndex)
|
||||||
{
|
{
|
||||||
@ -1317,13 +1317,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxLightRegion");
|
SaveLogEnter("GfxLightRegion");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxLightRegion* destLightRegionTable = buffer->dest<Game::GfxLightRegion>();
|
auto* destLightRegionTable = buffer->dest<Game::GfxLightRegion>();
|
||||||
buffer->saveArray(asset->lightRegion, asset->primaryLightCount);
|
buffer->saveArray(asset->lightRegion, asset->primaryLightCount);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
|
for (unsigned int i = 0; i < asset->primaryLightCount; ++i)
|
||||||
{
|
{
|
||||||
Game::GfxLightRegion* destLightRegion = &destLightRegionTable[i];
|
auto* destLightRegion = &destLightRegionTable[i];
|
||||||
Game::GfxLightRegion* lightRegion = &asset->lightRegion[i];
|
auto* lightRegion = &asset->lightRegion[i];
|
||||||
|
|
||||||
if (lightRegion->hulls)
|
if (lightRegion->hulls)
|
||||||
{
|
{
|
||||||
@ -1331,13 +1331,13 @@ namespace Assets
|
|||||||
SaveLogEnter("GfxLightRegionHull");
|
SaveLogEnter("GfxLightRegionHull");
|
||||||
|
|
||||||
buffer->align(Utils::Stream::ALIGN_4);
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
Game::GfxLightRegionHull* destLightRegionHullTable = buffer->dest<Game::GfxLightRegionHull>();
|
auto* destLightRegionHullTable = buffer->dest<Game::GfxLightRegionHull>();
|
||||||
buffer->saveArray(lightRegion->hulls, lightRegion->hullCount);
|
buffer->saveArray(lightRegion->hulls, lightRegion->hullCount);
|
||||||
|
|
||||||
for (unsigned int j = 0; j < lightRegion->hullCount; ++j)
|
for (unsigned int j = 0; j < lightRegion->hullCount; ++j)
|
||||||
{
|
{
|
||||||
Game::GfxLightRegionHull* destLightRegionHull = &destLightRegionHullTable[j];
|
auto* destLightRegionHull = &destLightRegionHullTable[j];
|
||||||
Game::GfxLightRegionHull* lightRegionHull = &lightRegion->hulls[j];
|
auto* lightRegionHull = &lightRegion->hulls[j];
|
||||||
|
|
||||||
if (lightRegionHull->axis)
|
if (lightRegionHull->axis)
|
||||||
{
|
{
|
||||||
@ -1373,7 +1373,6 @@ namespace Assets
|
|||||||
Utils::Stream::ClearPointer(&dest->heroOnlyLights);
|
Utils::Stream::ClearPointer(&dest->heroOnlyLights);
|
||||||
}
|
}
|
||||||
|
|
||||||
//buffer->setPointerAssertion(false);
|
|
||||||
buffer->popBlock();
|
buffer->popBlock();
|
||||||
SaveLogExit();
|
SaveLogExit();
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace Assets
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::LoadedSound* sound = builder->getAllocator()->allocate<Game::LoadedSound>();
|
auto* sound = builder->getAllocator()->allocate<Game::LoadedSound>();
|
||||||
if (!sound)
|
if (!sound)
|
||||||
{
|
{
|
||||||
Components::Logger::Print("Error allocating memory for sound structure!\n");
|
Components::Logger::Print("Error allocating memory for sound structure!\n");
|
||||||
@ -27,16 +27,16 @@ namespace Assets
|
|||||||
|
|
||||||
Utils::Stream::Reader reader(builder->getAllocator(), soundFile.getBuffer());
|
Utils::Stream::Reader reader(builder->getAllocator(), soundFile.getBuffer());
|
||||||
|
|
||||||
unsigned int chunkIDBuffer = reader.read<unsigned int>();
|
auto chunkIDBuffer = reader.read<unsigned int>();
|
||||||
if (chunkIDBuffer != 0x46464952) // RIFF
|
if (chunkIDBuffer != 0x46464952) // RIFF
|
||||||
{
|
{
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading sound '{}' failed, header is invalid!", name);
|
Components::Logger::Error(Game::ERR_FATAL, "Reading sound '{}' failed, header is invalid!", name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int chunkSize = reader.read<unsigned int>();
|
auto chunkSize = reader.read<unsigned int>();
|
||||||
|
|
||||||
unsigned int format = reader.read<unsigned int>();
|
auto format = reader.read<unsigned int>();
|
||||||
if (format != 0x45564157) // WAVE
|
if (format != 0x45564157) // WAVE
|
||||||
{
|
{
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading sound '{}' failed, header is invalid!", name);
|
Components::Logger::Error(Game::ERR_FATAL, "Reading sound '{}' failed, header is invalid!", name);
|
||||||
@ -62,7 +62,10 @@ namespace Assets
|
|||||||
|
|
||||||
sound->sound.info.channels = reader.read<short>();
|
sound->sound.info.channels = reader.read<short>();
|
||||||
sound->sound.info.rate = reader.read<int>();
|
sound->sound.info.rate = reader.read<int>();
|
||||||
sound->sound.info.samples = reader.read<int>();
|
|
||||||
|
// We read samples later, this is byte rate we don't need it
|
||||||
|
reader.read<int>();
|
||||||
|
|
||||||
sound->sound.info.block_size = reader.read<short>();
|
sound->sound.info.block_size = reader.read<short>();
|
||||||
sound->sound.info.bits = reader.read<short>();
|
sound->sound.info.bits = reader.read<short>();
|
||||||
|
|
||||||
@ -76,6 +79,7 @@ namespace Assets
|
|||||||
|
|
||||||
case 0x61746164: // data
|
case 0x61746164: // data
|
||||||
sound->sound.info.data_len = chunkSize;
|
sound->sound.info.data_len = chunkSize;
|
||||||
|
sound->sound.info.samples = chunkSize / (sound->sound.info.bits / 8);
|
||||||
sound->sound.data = reader.readArray<char>(chunkSize);
|
sound->sound.data = reader.readArray<char>(chunkSize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -102,9 +106,9 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
AssertSize(Game::LoadedSound, 44);
|
AssertSize(Game::LoadedSound, 44);
|
||||||
|
|
||||||
Utils::Stream* buffer = builder->getBuffer();
|
auto* buffer = builder->getBuffer();
|
||||||
Game::LoadedSound* asset = header.loadSnd;
|
auto* asset = header.loadSnd;
|
||||||
Game::LoadedSound* dest = buffer->dest<Game::LoadedSound>();
|
auto* dest = buffer->dest<Game::LoadedSound>();
|
||||||
buffer->save(asset);
|
buffer->save(asset);
|
||||||
|
|
||||||
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
||||||
|
@ -40,6 +40,8 @@ namespace Assets
|
|||||||
if (!header->data) this->loadJson(header, name, builder); // Check if we want to load a material from disk
|
if (!header->data) this->loadJson(header, name, builder); // Check if we want to load a material from disk
|
||||||
if (!header->data) this->loadBinary(header, name, builder); // Check if we want to load a material from disk (binary format)
|
if (!header->data) this->loadBinary(header, name, builder); // Check if we want to load a material from disk (binary format)
|
||||||
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
|
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
|
||||||
|
|
||||||
|
assert(header->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -206,12 +208,17 @@ namespace Assets
|
|||||||
textureDef->u.image = nullptr;
|
textureDef->u.image = nullptr;
|
||||||
if (textureJson["image"].is_string())
|
if (textureJson["image"].is_string())
|
||||||
{
|
{
|
||||||
textureDef->u.image = Components::AssetHandler::FindAssetForZone
|
textureDef->u.image = Components::AssetHandler::FindAssetForZone(
|
||||||
(
|
Game::ASSET_TYPE_IMAGE,
|
||||||
Game::XAssetType::ASSET_TYPE_IMAGE,
|
|
||||||
textureJson["image"].get<std::string>(),
|
textureJson["image"].get<std::string>(),
|
||||||
builder
|
builder
|
||||||
).image;
|
).image;
|
||||||
|
|
||||||
|
assert(textureDef->u.image);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AssertUnreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
if (!header->data) this->loadFromDisk(header, name, builder); // Check if we need to import a new one into the game
|
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) this->loadNative(header, name, builder); // Check if there is a native one
|
||||||
|
|
||||||
|
assert(header->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMaterialTechniqueSet::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
|
void IMaterialTechniqueSet::loadNative(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* /*builder*/)
|
||||||
@ -28,6 +30,7 @@ namespace Assets
|
|||||||
*tech = nullptr;
|
*tech = nullptr;
|
||||||
|
|
||||||
Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Missing technique '{}'\n", name);
|
Components::Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Missing technique '{}'\n", name);
|
||||||
|
AssertUnreachable;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
#include "IPhysPreset.hpp"
|
#include "IPhysPreset.hpp"
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
@ -7,9 +9,9 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
AssertSize(Game::PhysPreset, 44);
|
AssertSize(Game::PhysPreset, 44);
|
||||||
|
|
||||||
Utils::Stream* buffer = builder->getBuffer();
|
auto* buffer = builder->getBuffer();
|
||||||
Game::PhysPreset* asset = header.physPreset;
|
auto* asset = header.physPreset;
|
||||||
Game::PhysPreset* dest = buffer->dest<Game::PhysPreset>();
|
auto* dest = buffer->dest<Game::PhysPreset>();
|
||||||
buffer->save(asset);
|
buffer->save(asset);
|
||||||
|
|
||||||
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
||||||
@ -28,4 +30,54 @@ namespace Assets
|
|||||||
|
|
||||||
buffer->popBlock();
|
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)
|
||||||
|
{
|
||||||
|
Components::FileSystem::File physPresetFile(std::format("physpreset/{}.iw4x.json", name));
|
||||||
|
auto* asset = builder->getAllocator()->allocate<Game::PhysPreset>();
|
||||||
|
|
||||||
|
if (physPresetFile.exists())
|
||||||
|
{
|
||||||
|
nlohmann::json physPresetJson;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
physPresetJson = nlohmann::json::parse(physPresetFile.getBuffer());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid JSON for physpreset {}! {}", name, e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
asset->name = builder->getAllocator()->duplicateString(physPresetJson["name"].get<std::string>());
|
||||||
|
asset->type = physPresetJson["type"].get<int>();
|
||||||
|
asset->bounce = physPresetJson["bounce"].get<float>();
|
||||||
|
asset->mass = physPresetJson["mass"].get<float>();
|
||||||
|
asset->friction = physPresetJson["friction"].get<float>();
|
||||||
|
asset->bulletForceScale = physPresetJson["bulletForceScale"].get<float>();
|
||||||
|
asset->explosiveForceScale = physPresetJson["explosiveForceScale"].get<float>();
|
||||||
|
asset->sndAliasPrefix = builder->getAllocator()->duplicateString(physPresetJson["sndAliasPrefix"].get<std::string>());
|
||||||
|
asset->piecesSpreadFraction = physPresetJson["piecesSpreadFraction"].get<float>();
|
||||||
|
asset->piecesUpwardVelocity = physPresetJson["piecesUpwardVelocity"].get<float>();
|
||||||
|
asset->tempDefaultToCylinder = physPresetJson["tempDefaultToCylinder"].get<bool>();
|
||||||
|
asset->perSurfaceSndAlias = physPresetJson["perSurfaceSndAlias"].get<bool>();
|
||||||
|
|
||||||
|
assert(asset->mass > std::numeric_limits<float>::epsilon());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Malformed JSON for physpreset {}! {}", name, e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header->physPreset = asset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,7 @@ namespace Assets
|
|||||||
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PHYSPRESET; }
|
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_PHYSPRESET; }
|
||||||
|
|
||||||
void save(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;
|
||||||
|
void loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
#include "ISndCurve.hpp"
|
#include "ISndCurve.hpp"
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
@ -7,9 +9,9 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
AssertSize(Game::SndCurve, 136);
|
AssertSize(Game::SndCurve, 136);
|
||||||
|
|
||||||
Utils::Stream* buffer = builder->getBuffer();
|
auto* buffer = builder->getBuffer();
|
||||||
Game::SndCurve* asset = header.sndCurve;
|
auto* asset = header.sndCurve;
|
||||||
Game::SndCurve* dest = buffer->dest<Game::SndCurve>();
|
auto* dest = buffer->dest<Game::SndCurve>();
|
||||||
buffer->save(asset);
|
buffer->save(asset);
|
||||||
|
|
||||||
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
|
||||||
@ -22,4 +24,48 @@ namespace Assets
|
|||||||
|
|
||||||
buffer->popBlock();
|
buffer->popBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ISndCurve::load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
|
||||||
|
{
|
||||||
|
Components::FileSystem::File sndCurveFile(std::format("sndcurve/{}.iw4x.json", name));
|
||||||
|
|
||||||
|
if (!sndCurveFile.exists())
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Missing file for sndcurve {}!", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json sndCurveJson;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sndCurveJson = nlohmann::json::parse(sndCurveFile.getBuffer());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Invalid JSON for sndcurve {}! {}", name, e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* sndCurve = builder->getAllocator()->allocate<Game::SndCurve>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sndCurve->filename = builder->getAllocator()->duplicateString(sndCurveJson["filename"].get<std::string>());
|
||||||
|
sndCurve->knotCount = sndCurveJson["knotCount"].get<unsigned short>();
|
||||||
|
|
||||||
|
for (auto side = 0; side < 2; side++)
|
||||||
|
{
|
||||||
|
for (auto knot = 0; knot < 16; knot++)
|
||||||
|
{
|
||||||
|
sndCurve->knots[knot][side] = sndCurveJson["knots"][knot][side].get<float>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
Components::Logger::PrintError(Game::CON_CHANNEL_ERROR, "Malformed JSON for sndcurve {}! {}", name, e.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
header->sndCurve = sndCurve;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,6 @@ namespace Assets
|
|||||||
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_SOUND_CURVE; }
|
Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_SOUND_CURVE; }
|
||||||
|
|
||||||
void save(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,7 +1,7 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
#include "IXAnimParts.hpp"
|
#include "IXAnimParts.hpp"
|
||||||
|
|
||||||
#define IW4X_ANIM_VERSION 1
|
#define IW4X_ANIM_VERSION 2
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
@ -9,100 +9,148 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
Components::FileSystem::File animFile(std::format("xanim/{}.iw4xAnim", name));
|
Components::FileSystem::File animFile(std::format("xanim/{}.iw4xAnim", name));
|
||||||
|
|
||||||
if (animFile.exists())
|
if (!animFile.exists())
|
||||||
{
|
{
|
||||||
Utils::Stream::Reader reader(builder->getAllocator(), animFile.getBuffer());
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
__int64 magic = reader.read<__int64>();
|
Utils::Stream::Reader reader(builder->getAllocator(), animFile.getBuffer());
|
||||||
if (std::memcmp(&magic, "IW4xAnim", 8))
|
|
||||||
|
auto magic = reader.read<std::int64_t>();
|
||||||
|
if (std::memcmp(&magic, "IW4xAnim", 8) != 0)
|
||||||
|
{
|
||||||
|
Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, header is invalid!", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int version = reader.read<int>();
|
||||||
|
if (version > IW4X_ANIM_VERSION)
|
||||||
|
{
|
||||||
|
Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, expected version is {}, but it was {}!", name, IW4X_ANIM_VERSION, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* xanim = reader.readArray<Game::XAnimParts>();
|
||||||
|
if (!xanim)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xanim->name)
|
||||||
|
{
|
||||||
|
xanim->name = reader.readCString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xanim->names)
|
||||||
|
{
|
||||||
|
xanim->names = builder->getAllocator()->allocateArray<unsigned short>(xanim->boneCount[Game::PART_TYPE_ALL]);
|
||||||
|
for (int i = 0; i < xanim->boneCount[Game::PART_TYPE_ALL]; ++i)
|
||||||
{
|
{
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, header is invalid!", name);
|
xanim->names[i] = static_cast<std::uint16_t>(Game::SL_GetString(reader.readCString(), 0));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int version = reader.read<int>();
|
if (xanim->notify)
|
||||||
if (version != IW4X_ANIM_VERSION)
|
{
|
||||||
|
xanim->notify = reader.readArray<Game::XAnimNotifyInfo>(xanim->notifyCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < xanim->notifyCount; ++i)
|
||||||
{
|
{
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, expected version is {}, but it was {}!", name, IW4X_ANIM_VERSION, version);
|
xanim->notify[i].name = static_cast<std::uint16_t>(Game::SL_GetString(reader.readCString(), 0));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Game::XAnimParts* xanim = reader.readArray<Game::XAnimParts>();
|
if (xanim->dataByte)
|
||||||
|
{
|
||||||
|
xanim->dataByte = reader.readArray<char>(xanim->dataByteCount);
|
||||||
|
}
|
||||||
|
|
||||||
if (xanim)
|
if (xanim->dataShort)
|
||||||
|
{
|
||||||
|
xanim->dataShort = reader.readArray<short>(xanim->dataShortCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xanim->dataInt)
|
||||||
|
{
|
||||||
|
xanim->dataInt = reader.readArray<int>(xanim->dataIntCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xanim->randomDataByte)
|
||||||
|
{
|
||||||
|
xanim->randomDataByte = reader.readArray<char>(xanim->randomDataByteCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xanim->randomDataShort)
|
||||||
|
{
|
||||||
|
xanim->randomDataShort = reader.readArray<short>(xanim->randomDataShortCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xanim->randomDataInt)
|
||||||
|
{
|
||||||
|
xanim->randomDataInt = reader.readArray<int>(xanim->randomDataIntCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xanim->indices.data)
|
||||||
|
{
|
||||||
|
if (xanim->numframes < 256)
|
||||||
{
|
{
|
||||||
if (xanim->name)
|
xanim->indices._1 = reader.readArray<char>(xanim->indexCount);
|
||||||
{
|
}
|
||||||
xanim->name = reader.readCString();
|
else
|
||||||
}
|
{
|
||||||
|
xanim->indices._2 = reader.readArray<unsigned short>(xanim->indexCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (xanim->names)
|
if (version > 1)
|
||||||
|
{
|
||||||
|
if (xanim->deltaPart)
|
||||||
|
{
|
||||||
|
xanim->deltaPart = reader.readObject<Game::XAnimDeltaPart>();
|
||||||
|
auto delta = xanim->deltaPart;
|
||||||
|
if (delta->trans)
|
||||||
{
|
{
|
||||||
xanim->names = builder->getAllocator()->allocateArray<unsigned short>(xanim->boneCount[Game::PART_TYPE_ALL]);
|
delta->trans = reader.readObject<Game::XAnimPartTrans>();
|
||||||
for (int i = 0; i < xanim->boneCount[Game::PART_TYPE_ALL]; ++i)
|
if (delta->trans->size)
|
||||||
{
|
{
|
||||||
xanim->names[i] = static_cast<std::uint16_t>(Game::SL_GetString(reader.readCString(), 0));
|
delta->trans->u.frames = reader.read<Game::XAnimPartTransFrames>();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xanim->notify)
|
if (xanim->numframes > 0xFF)
|
||||||
{
|
{
|
||||||
xanim->notify = reader.readArray<Game::XAnimNotifyInfo>(xanim->notifyCount);
|
auto indices2 = reader.readArray<unsigned short>(delta->trans->size + 1);
|
||||||
|
std::memcpy(delta->trans->u.frames.indices._2, indices2, sizeof(short) * (delta->trans->size + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto indices1 = reader.readArray<char>(delta->trans->size + 1);
|
||||||
|
std::memcpy(delta->trans->u.frames.indices._1, indices1, delta->trans->size + 1);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < xanim->notifyCount; ++i)
|
if (delta->trans->u.frames.frames._1)
|
||||||
{
|
{
|
||||||
xanim->notify[i].name = static_cast<std::uint16_t>(Game::SL_GetString(reader.readCString(), 0));
|
if (delta->trans->smallTrans)
|
||||||
}
|
{
|
||||||
}
|
delta->trans->u.frames.frames._1 = reinterpret_cast<char(*)[3]>(3, (delta->trans->size + 1));
|
||||||
|
}
|
||||||
if (xanim->dataByte)
|
else
|
||||||
{
|
{
|
||||||
xanim->dataByte = reader.readArray<char>(xanim->dataByteCount);
|
delta->trans->u.frames.frames._2 = reinterpret_cast<unsigned short(*)[3]>(6, (delta->trans->size + 1));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (xanim->dataShort)
|
|
||||||
{
|
|
||||||
xanim->dataShort = reader.readArray<short>(xanim->dataShortCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xanim->dataInt)
|
|
||||||
{
|
|
||||||
xanim->dataInt = reader.readArray<int>(xanim->dataIntCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xanim->randomDataByte)
|
|
||||||
{
|
|
||||||
xanim->randomDataByte = reader.readArray<char>(xanim->randomDataByteCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xanim->randomDataShort)
|
|
||||||
{
|
|
||||||
xanim->randomDataShort = reader.readArray<short>(xanim->randomDataShortCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xanim->randomDataInt)
|
|
||||||
{
|
|
||||||
xanim->randomDataInt = reader.readArray<int>(xanim->randomDataIntCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xanim->indices.data)
|
|
||||||
{
|
|
||||||
if (xanim->numframes < 256)
|
|
||||||
{
|
|
||||||
xanim->indices._1 = reader.readArray<char>(xanim->indexCount);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xanim->indices._2 = reader.readArray<unsigned short>(xanim->indexCount);
|
auto frames = reader.readObject<Game::vec3_t>();
|
||||||
|
std::memcpy(delta->trans->u.frame0, frames, sizeof(Game::vec3_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reader.end())
|
|
||||||
{
|
|
||||||
Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, remaining raw data found!", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
header->parts = xanim;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!reader.end())
|
||||||
|
{
|
||||||
|
Components::Logger::Error(Game::ERR_FATAL, "Reading animation '{}' failed, remaining raw data found!", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
header->parts = xanim;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IXAnimParts::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void IXAnimParts::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <STDInclude.hpp>
|
#include <STDInclude.hpp>
|
||||||
#include "IXModel.hpp"
|
#include "IXModel.hpp"
|
||||||
|
|
||||||
#define IW4X_MODEL_VERSION 8
|
#define IW4X_MODEL_VERSION 9
|
||||||
|
|
||||||
namespace Assets
|
namespace Assets
|
||||||
{
|
{
|
||||||
@ -250,34 +250,32 @@ namespace Assets
|
|||||||
|
|
||||||
if (geom->brushWrapper)
|
if (geom->brushWrapper)
|
||||||
{
|
{
|
||||||
Game::BrushWrapper* brush = reader.readObject<Game::BrushWrapper>();
|
Game::BrushWrapper* brush = reader.readArrayOnce<Game::BrushWrapper>();
|
||||||
geom->brushWrapper = brush;
|
geom->brushWrapper = brush;
|
||||||
{
|
{
|
||||||
if (brush->brush.sides)
|
if (brush->brush.sides)
|
||||||
{
|
{
|
||||||
brush->brush.sides = reader.readArray<Game::cbrushside_t>(brush->brush.numsides);
|
brush->brush.sides = reader.readArrayOnce<Game::cbrushside_t>(brush->brush.numsides);
|
||||||
for (unsigned short j = 0; j < brush->brush.numsides; ++j)
|
for (unsigned short j = 0; j < brush->brush.numsides; ++j)
|
||||||
{
|
{
|
||||||
Game::cbrushside_t* side = &brush->brush.sides[j];
|
Game::cbrushside_t* side = &brush->brush.sides[j];
|
||||||
|
|
||||||
// TODO: Add pointer support
|
|
||||||
if (side->plane)
|
if (side->plane)
|
||||||
{
|
{
|
||||||
side->plane = reader.readObject<Game::cplane_s>();
|
side->plane = reader.readArrayOnce<Game::cplane_s>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (brush->brush.baseAdjacentSide)
|
if (brush->brush.baseAdjacentSide)
|
||||||
{
|
{
|
||||||
brush->brush.baseAdjacentSide = reader.readArray<char>(brush->totalEdgeCount);
|
brush->brush.baseAdjacentSide = reader.readArrayOnce<unsigned char>(brush->totalEdgeCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add pointer support
|
|
||||||
if (brush->planes)
|
if (brush->planes)
|
||||||
{
|
{
|
||||||
brush->planes = reader.readArray<Game::cplane_s>(brush->brush.numsides);
|
brush->planes = reader.readArrayOnce<Game::cplane_s>(brush->brush.numsides);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@ namespace Assets
|
|||||||
void save(Game::XAssetHeader header, 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 mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||||
void load(Game::XAssetHeader* header, const std::string& name, 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:
|
private:
|
||||||
class SModelQuadtree
|
class SModelQuadtree
|
||||||
@ -89,5 +90,9 @@ namespace Assets
|
|||||||
float x, y, z;
|
float x, y, z;
|
||||||
float halfX, halfY, halfZ;
|
float halfX, halfY, halfZ;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void loadBinary(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
|
||||||
|
void loadFromJSON(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,10 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
|
|
||||||
alias->soundFile->exists = true;
|
alias->soundFile->exists = true;
|
||||||
alias->aliasName = builder->getAllocator()->duplicateString(aliasName.get<std::string>());
|
|
||||||
|
// These must be THE SAME POINTER !!
|
||||||
|
// Wanna know why ? Check out 0x685646
|
||||||
|
alias->aliasName = aliasList->aliasName;
|
||||||
|
|
||||||
if (subtitle.is_string())
|
if (subtitle.is_string())
|
||||||
{
|
{
|
||||||
@ -244,7 +247,7 @@ namespace Assets
|
|||||||
alias->pitchMax = pitchMax.get<float>();
|
alias->pitchMax = pitchMax.get<float>();
|
||||||
alias->distMin = distMin.get<float>();
|
alias->distMin = distMin.get<float>();
|
||||||
alias->distMax = distMax.get<float>();
|
alias->distMax = distMax.get<float>();
|
||||||
alias->flags = flags.get<int>();
|
alias->flags.intValue = flags.get<int>();
|
||||||
alias->___u15.slavePercentage = slavePercentage.get<float>();
|
alias->___u15.slavePercentage = slavePercentage.get<float>();
|
||||||
alias->probability = probability.get<float>();
|
alias->probability = probability.get<float>();
|
||||||
alias->lfePercentage = lfePercentage.get<float>();
|
alias->lfePercentage = lfePercentage.get<float>();
|
||||||
@ -308,6 +311,9 @@ namespace Assets
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto curve = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, fallOffCurve, builder).sndCurve;
|
auto curve = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, fallOffCurve, builder).sndCurve;
|
||||||
|
|
||||||
|
assert(curve);
|
||||||
|
|
||||||
alias->volumeFalloffCurve = curve;
|
alias->volumeFalloffCurve = curve;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,11 +326,10 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
alias->soundFile->type = Game::SAT_STREAMED;
|
alias->soundFile->type = Game::SAT_STREAMED;
|
||||||
|
|
||||||
std::string streamedFile = soundFile.get<std::string>();
|
auto streamedFile = soundFile.get<std::string>();
|
||||||
std::string directory = ""s;
|
std::string directory;
|
||||||
int split = streamedFile.find_last_of('/');
|
auto split = streamedFile.find_last_of('/');
|
||||||
|
if (split != std::string::npos)
|
||||||
if (split >= 0)
|
|
||||||
{
|
{
|
||||||
directory = streamedFile.substr(0, split);
|
directory = streamedFile.substr(0, split);
|
||||||
streamedFile = streamedFile.substr(split+1);
|
streamedFile = streamedFile.substr(split+1);
|
||||||
@ -379,6 +384,127 @@ namespace Assets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Isnd_alias_list_t::dump(Game::XAssetHeader header)
|
||||||
|
{
|
||||||
|
nlohmann::json output;
|
||||||
|
Utils::Memory::Allocator strDuplicator;
|
||||||
|
auto ents = header.sound;
|
||||||
|
|
||||||
|
auto head = nlohmann::json::array_t();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ents->count; i++)
|
||||||
|
{
|
||||||
|
Game::snd_alias_t alias = ents->head[i];
|
||||||
|
|
||||||
|
auto channelMaps = nlohmann::json::array_t();
|
||||||
|
|
||||||
|
for (size_t j = 0; j < 2; j++)
|
||||||
|
{
|
||||||
|
for (size_t k = 0; k < 2; k++)
|
||||||
|
{
|
||||||
|
auto iw3ChannelMap = alias.speakerMap->channelMaps[j][k];
|
||||||
|
auto speakers = nlohmann::json::array_t();
|
||||||
|
|
||||||
|
for (size_t speakerIndex = 0; speakerIndex < iw3ChannelMap.speakerCount; speakerIndex++)
|
||||||
|
{
|
||||||
|
auto iw4Speaker = iw3ChannelMap.speakers[speakerIndex];
|
||||||
|
|
||||||
|
nlohmann::json::object_t speaker;
|
||||||
|
speaker.emplace("levels0", iw4Speaker.numLevels > 0 ? iw4Speaker.levels[0] : 0);
|
||||||
|
speaker.emplace("levels1", iw4Speaker.numLevels > 1 ? iw4Speaker.levels[1] : 0);
|
||||||
|
speaker.emplace("numLevels", iw4Speaker.numLevels);
|
||||||
|
speaker.emplace("speaker", iw4Speaker.speaker);
|
||||||
|
speakers.emplace_back(speaker);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto channelMap = nlohmann::json::object_t();
|
||||||
|
channelMap.emplace("entryCount", iw3ChannelMap.speakerCount);
|
||||||
|
channelMap.emplace("speakers", speakers);
|
||||||
|
channelMaps.emplace_back(channelMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto speakerMap = nlohmann::json::object_t();
|
||||||
|
speakerMap.emplace("channelMaps", channelMaps);
|
||||||
|
speakerMap.emplace("isDefault", alias.speakerMap->isDefault);
|
||||||
|
speakerMap.emplace("name", (alias.speakerMap->name));
|
||||||
|
|
||||||
|
std::string soundFile;
|
||||||
|
if (alias.soundFile)
|
||||||
|
{
|
||||||
|
switch (alias.soundFile->type)
|
||||||
|
{
|
||||||
|
// LOADED
|
||||||
|
case Game::snd_alias_type_t::SAT_LOADED:
|
||||||
|
// Save the LoadedSound subasset
|
||||||
|
soundFile = alias.soundFile->u.loadSnd->name;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// STREAMED
|
||||||
|
case Game::snd_alias_type_t::SAT_STREAMED:
|
||||||
|
{
|
||||||
|
soundFile = alias.soundFile->u.streamSnd.filename.info.raw.name;
|
||||||
|
|
||||||
|
if (alias.soundFile->u.streamSnd.filename.info.raw.dir)
|
||||||
|
{
|
||||||
|
soundFile = Utils::String::VA("%s/%s", alias.soundFile->u.streamSnd.filename.info.raw.dir, soundFile.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I DON'T KNOW :(
|
||||||
|
default:
|
||||||
|
Components::Logger::Print("Error dumping sound alias %s: unknown format %d\n", alias.aliasName, alias.soundFile->type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Components::Logger::Print("Error dumping sound alias %s: NULL soundfile!\n", alias.aliasName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto iw4Flags = alias.flags.intValue;
|
||||||
|
|
||||||
|
auto json_alias = nlohmann::json::object_t();
|
||||||
|
json_alias.emplace("aliasName", (alias.aliasName));
|
||||||
|
json_alias.emplace("centerPercentage", alias.centerPercentage);
|
||||||
|
json_alias.emplace("chainAliasName", (alias.chainAliasName == nullptr ? nlohmann::json() : alias.chainAliasName));
|
||||||
|
json_alias.emplace("distMax", alias.distMax);
|
||||||
|
json_alias.emplace("distMin", alias.distMin);
|
||||||
|
json_alias.emplace("envelopMax", alias.envelopMax);
|
||||||
|
json_alias.emplace("envelopMin", alias.envelopMin);
|
||||||
|
json_alias.emplace("envelopPercentage", alias.envelopPercentage);
|
||||||
|
json_alias.emplace("flags", iw4Flags);
|
||||||
|
json_alias.emplace("lfePercentage", alias.lfePercentage);
|
||||||
|
json_alias.emplace("mixerGroup", nlohmann::json());
|
||||||
|
json_alias.emplace("pitchMax", alias.pitchMax);
|
||||||
|
json_alias.emplace("pitchMin", alias.pitchMin);
|
||||||
|
json_alias.emplace("probability", alias.probability);
|
||||||
|
json_alias.emplace("secondaryAliasName", (alias.secondaryAliasName == nullptr ? nlohmann::json() : alias.secondaryAliasName));
|
||||||
|
json_alias.emplace("sequence", alias.sequence);
|
||||||
|
json_alias.emplace("slavePercentage", alias.___u15.slavePercentage);
|
||||||
|
json_alias.emplace("speakerMap", speakerMap);
|
||||||
|
json_alias.emplace("soundFile", (strDuplicator.duplicateString(soundFile)));
|
||||||
|
json_alias.emplace("startDelay", alias.startDelay);
|
||||||
|
json_alias.emplace("subtitle", (alias.subtitle == nullptr ? nlohmann::json() : alias.subtitle));
|
||||||
|
json_alias.emplace("type", alias.soundFile->type);
|
||||||
|
json_alias.emplace("volMax", alias.volMax);
|
||||||
|
json_alias.emplace("volMin", alias.volMin);
|
||||||
|
json_alias.emplace("volumeFalloffCurve", (alias.volumeFalloffCurve->filename));
|
||||||
|
|
||||||
|
head.emplace_back(json_alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.emplace("aliasName", (ents->aliasName));
|
||||||
|
output.emplace("count", ents->count);
|
||||||
|
output.emplace("head", head);
|
||||||
|
|
||||||
|
const auto dump = output.dump(4);
|
||||||
|
Utils::IO::WriteFile(std::format("raw/sounds/{}.json", ents->aliasName), dump);
|
||||||
|
}
|
||||||
|
|
||||||
void Isnd_alias_list_t::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
void Isnd_alias_list_t::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
|
||||||
{
|
{
|
||||||
AssertSize(Game::snd_alias_list_t, 12);
|
AssertSize(Game::snd_alias_list_t, 12);
|
||||||
@ -392,8 +518,16 @@ namespace Assets
|
|||||||
|
|
||||||
if (asset->aliasName)
|
if (asset->aliasName)
|
||||||
{
|
{
|
||||||
buffer->saveString(builder->getAssetName(this->getType(), asset->aliasName));
|
if (builder->hasPointer(asset->aliasName))
|
||||||
Utils::Stream::ClearPointer(&dest->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 (asset->head)
|
||||||
@ -419,8 +553,16 @@ namespace Assets
|
|||||||
|
|
||||||
if (alias->aliasName)
|
if (alias->aliasName)
|
||||||
{
|
{
|
||||||
buffer->saveString(alias->aliasName);
|
if (builder->hasPointer(alias->aliasName))
|
||||||
Utils::Stream::ClearPointer(&destAlias->aliasName);
|
{
|
||||||
|
destAlias->aliasName = builder->getPointer(alias->aliasName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder->storePointer(alias->aliasName);
|
||||||
|
buffer->saveString(alias->aliasName);
|
||||||
|
Utils::Stream::ClearPointer(&destAlias->aliasName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alias->subtitle)
|
if (alias->subtitle)
|
||||||
@ -467,7 +609,7 @@ namespace Assets
|
|||||||
{
|
{
|
||||||
if (alias->soundFile->type == Game::snd_alias_type_t::SAT_LOADED)
|
if (alias->soundFile->type == Game::snd_alias_type_t::SAT_LOADED)
|
||||||
{
|
{
|
||||||
destSoundFile->u.loadSnd = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, alias->soundFile->u.loadSnd).loadSnd;
|
destSoundFile->u.loadSnd = builder->saveSubAsset(Game::ASSET_TYPE_LOADED_SOUND, alias->soundFile->u.loadSnd).loadSnd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -494,7 +636,7 @@ namespace Assets
|
|||||||
|
|
||||||
if (alias->volumeFalloffCurve)
|
if (alias->volumeFalloffCurve)
|
||||||
{
|
{
|
||||||
destAlias->volumeFalloffCurve = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_SOUND_CURVE, alias->volumeFalloffCurve).sndCurve;
|
destAlias->volumeFalloffCurve = builder->saveSubAsset(Game::ASSET_TYPE_SOUND_CURVE, alias->volumeFalloffCurve).sndCurve;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alias->speakerMap)
|
if (alias->speakerMap)
|
||||||
|
@ -10,5 +10,6 @@ namespace Assets
|
|||||||
void load(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) override;
|
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 save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||||
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
|
||||||
|
void dump(Game::XAssetHeader header) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -242,6 +242,11 @@ namespace Components
|
|||||||
|
|
||||||
void Debug::CG_DrawDebugOverlays_Hk(const int localClientNum)
|
void Debug::CG_DrawDebugOverlays_Hk(const int localClientNum)
|
||||||
{
|
{
|
||||||
|
if (!DebugOverlay)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (DebugOverlay->current.integer)
|
switch (DebugOverlay->current.integer)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -80,11 +80,12 @@ namespace Components
|
|||||||
|
|
||||||
void Logger::ErrorInternal(const Game::errorParm_t error, const std::string_view& fmt, std::format_args&& args)
|
void Logger::ErrorInternal(const Game::errorParm_t error, const std::string_view& fmt, std::format_args&& args)
|
||||||
{
|
{
|
||||||
|
const auto msg = std::vformat(fmt, args);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if (IsDebuggerPresent()) __debugbreak();
|
if (IsDebuggerPresent()) __debugbreak();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const auto msg = std::vformat(fmt, args);
|
|
||||||
Game::Com_Error(error, "%s", msg.data());
|
Game::Com_Error(error, "%s", msg.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ namespace Components
|
|||||||
Dvar::Var Renderer::r_drawAABBTrees;
|
Dvar::Var Renderer::r_drawAABBTrees;
|
||||||
Dvar::Var Renderer::r_playerDrawDebugDistance;
|
Dvar::Var Renderer::r_playerDrawDebugDistance;
|
||||||
Dvar::Var Renderer::r_forceTechnique;
|
Dvar::Var Renderer::r_forceTechnique;
|
||||||
|
Dvar::Var Renderer::r_drawRunners;
|
||||||
|
|
||||||
float cyan[4] = { 0.0f, 0.5f, 0.5f, 1.0f };
|
float cyan[4] = { 0.0f, 0.5f, 0.5f, 1.0f };
|
||||||
float red[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
|
float red[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
|
||||||
@ -118,10 +119,13 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::R_TextureFromCodeError(const char* sampler, Game::GfxCmdBufState* state)
|
void Renderer::R_TextureFromCodeError(const char* sampler, Game::GfxCmdBufState* state, int samplerCode)
|
||||||
{
|
{
|
||||||
Logger::Error(Game::ERR_FATAL, "Tried to use sampler '{}' when it isn't valid for material '{}' and technique '{}'",
|
Logger::Error(
|
||||||
sampler, state->material->info.name, state->technique->name);
|
Game::ERR_FATAL,
|
||||||
|
"Tried to use sampler #{} ('{}') at the wrong timing! Additional info:\nMaterial: '{}'\nTechnique {}\nTechnique slot: {}\nTechnique flags:{}\nPass: {}\nPixel shader: {}\n",
|
||||||
|
samplerCode, sampler, state->material->info.name, state->technique->name, (int)state->techType, state->technique->flags, state->passIndex, state->pixelShader->name
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
__declspec(naked) void Renderer::StoreGfxBufContextPtrStub1()
|
__declspec(naked) void Renderer::StoreGfxBufContextPtrStub1()
|
||||||
@ -154,10 +158,11 @@ namespace Components
|
|||||||
|
|
||||||
// show error
|
// show error
|
||||||
pushad
|
pushad
|
||||||
|
push eax
|
||||||
push ebx
|
push ebx
|
||||||
push edx
|
push edx
|
||||||
call R_TextureFromCodeError
|
call R_TextureFromCodeError
|
||||||
add esp, 8
|
add esp, 0xC
|
||||||
popad
|
popad
|
||||||
|
|
||||||
// go back
|
// go back
|
||||||
@ -361,7 +366,7 @@ namespace Components
|
|||||||
if (staticModel->model)
|
if (staticModel->model)
|
||||||
{
|
{
|
||||||
|
|
||||||
Game::R_AddDebugBounds(staticModelsColor, b);
|
Game::R_AddDebugBounds(staticModelsColor, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,6 +463,41 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::DebugDrawRunners()
|
||||||
|
{
|
||||||
|
if (!Game::CL_IsCgameInitialized())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r_drawRunners.get<bool>())
|
||||||
|
{
|
||||||
|
auto* fxSystem = reinterpret_cast<Game::FxSystem*>(0x173F200);
|
||||||
|
|
||||||
|
if (fxSystem)
|
||||||
|
{
|
||||||
|
for (auto i = 0; i < fxSystem->activeElemCount; i++)
|
||||||
|
{
|
||||||
|
auto* elem = &fxSystem->effects[i];
|
||||||
|
if (elem->def)
|
||||||
|
{
|
||||||
|
Game::R_AddDebugString(sceneModelsColor, elem->frameNow.origin, 1.0f, elem->def->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto soundCount = *reinterpret_cast<int*>(0x7C5C90);
|
||||||
|
auto* sounds = reinterpret_cast<Game::ClientEntSound*>(0x7C5CA0);
|
||||||
|
|
||||||
|
for (auto i = 0; i < soundCount; i++)
|
||||||
|
{
|
||||||
|
if (sounds[i].aliasList)
|
||||||
|
{
|
||||||
|
Game::R_AddDebugString(staticModelsColor, sounds[i].origin, 1.0f, sounds[i].aliasList->aliasName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
void Renderer::DebugDrawAABBTrees()
|
void Renderer::DebugDrawAABBTrees()
|
||||||
{
|
{
|
||||||
if (!r_drawAABBTrees.get<bool>()) return;
|
if (!r_drawAABBTrees.get<bool>()) return;
|
||||||
@ -507,6 +547,7 @@ namespace Components
|
|||||||
{
|
{
|
||||||
if (Game::CL_IsCgameInitialized())
|
if (Game::CL_IsCgameInitialized())
|
||||||
{
|
{
|
||||||
|
DebugDrawRunners();
|
||||||
DebugDrawAABBTrees();
|
DebugDrawAABBTrees();
|
||||||
DebugDrawModelNames();
|
DebugDrawModelNames();
|
||||||
DebugDrawModelBoundingBoxes();
|
DebugDrawModelBoundingBoxes();
|
||||||
@ -561,6 +602,7 @@ namespace Components
|
|||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Renderer::r_drawRunners = Game::Dvar_RegisterBool("r_drawRunners", false, Game::DVAR_NONE, "Draw active sound & fx runners");
|
||||||
Renderer::r_drawModelBoundingBoxes = Game::Dvar_RegisterEnum("r_drawModelBoundingBoxes", values, 0, Game::DVAR_CHEAT, "Draw scene model bounding boxes");
|
Renderer::r_drawModelBoundingBoxes = Game::Dvar_RegisterEnum("r_drawModelBoundingBoxes", values, 0, Game::DVAR_CHEAT, "Draw scene model bounding boxes");
|
||||||
Renderer::r_drawSceneModelCollisions = Game::Dvar_RegisterBool("r_drawSceneModelCollisions", false, Game::DVAR_CHEAT, "Draw scene model collisions");
|
Renderer::r_drawSceneModelCollisions = Game::Dvar_RegisterBool("r_drawSceneModelCollisions", false, Game::DVAR_CHEAT, "Draw scene model collisions");
|
||||||
Renderer::r_drawTriggers = Game::Dvar_RegisterBool("r_drawTriggers", false, Game::DVAR_CHEAT, "Draw triggers");
|
Renderer::r_drawTriggers = Game::Dvar_RegisterBool("r_drawTriggers", false, Game::DVAR_CHEAT, "Draw triggers");
|
||||||
|
@ -28,7 +28,7 @@ namespace Components
|
|||||||
static void PostVidRestart();
|
static void PostVidRestart();
|
||||||
static void PostVidRestartStub();
|
static void PostVidRestartStub();
|
||||||
|
|
||||||
static void R_TextureFromCodeError(const char* sampler, Game::GfxCmdBufState* state);
|
static void R_TextureFromCodeError(const char* sampler, Game::GfxCmdBufState* state, int samplerCode);
|
||||||
static void StoreGfxBufContextPtrStub1();
|
static void StoreGfxBufContextPtrStub1();
|
||||||
static void StoreGfxBufContextPtrStub2();
|
static void StoreGfxBufContextPtrStub2();
|
||||||
|
|
||||||
@ -38,6 +38,7 @@ namespace Components
|
|||||||
static void DebugDrawSceneModelCollisions();
|
static void DebugDrawSceneModelCollisions();
|
||||||
static void DebugDrawModelBoundingBoxes();
|
static void DebugDrawModelBoundingBoxes();
|
||||||
static void DebugDrawModelNames();
|
static void DebugDrawModelNames();
|
||||||
|
static void DebugDrawRunners();
|
||||||
static void DebugDrawAABBTrees();
|
static void DebugDrawAABBTrees();
|
||||||
static void ForceTechnique();
|
static void ForceTechnique();
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ namespace Components
|
|||||||
static Utils::Signal<BackendCallback> SingleBackendFrameSignal;
|
static Utils::Signal<BackendCallback> SingleBackendFrameSignal;
|
||||||
|
|
||||||
static Dvar::Var r_drawTriggers;
|
static Dvar::Var r_drawTriggers;
|
||||||
|
static Dvar::Var r_drawRunners;
|
||||||
static Dvar::Var r_drawSceneModelCollisions;
|
static Dvar::Var r_drawSceneModelCollisions;
|
||||||
static Dvar::Var r_drawModelBoundingBoxes;
|
static Dvar::Var r_drawModelBoundingBoxes;
|
||||||
static Dvar::Var r_drawModelNames;
|
static Dvar::Var r_drawModelNames;
|
||||||
|
@ -882,8 +882,8 @@ namespace Game
|
|||||||
{
|
{
|
||||||
float normal[3];
|
float normal[3];
|
||||||
float dist;
|
float dist;
|
||||||
char type;
|
unsigned char type;
|
||||||
char pad[3];
|
unsigned char pad[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cbrushside_t
|
struct cbrushside_t
|
||||||
@ -896,13 +896,13 @@ namespace Game
|
|||||||
|
|
||||||
struct cbrush_t
|
struct cbrush_t
|
||||||
{
|
{
|
||||||
unsigned __int16 numsides;
|
unsigned short numsides;
|
||||||
unsigned __int16 glassPieceIndex;
|
unsigned short glassPieceIndex;
|
||||||
cbrushside_t* sides;
|
cbrushside_t* sides;
|
||||||
char* baseAdjacentSide;
|
unsigned char* baseAdjacentSide;
|
||||||
__int16 axialMaterialNum[2][3];
|
unsigned short axialMaterialNum[2][3];
|
||||||
char firstAdjacentSideOffsets[2][3];
|
unsigned char firstAdjacentSideOffsets[2][3];
|
||||||
char edgeCount[2][3];
|
unsigned char edgeCount[2][3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BrushWrapper
|
struct BrushWrapper
|
||||||
@ -2497,6 +2497,189 @@ namespace Game
|
|||||||
SAT_COUNT = 0x4,
|
SAT_COUNT = 0x4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct snd_volume_info_t
|
||||||
|
{
|
||||||
|
float volume;
|
||||||
|
float goalvolume;
|
||||||
|
float goalrate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_channelvolgroup
|
||||||
|
{
|
||||||
|
snd_volume_info_t channelvol[64];
|
||||||
|
bool active;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_background_info_t
|
||||||
|
{
|
||||||
|
float goalvolume;
|
||||||
|
float goalrate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_enveffect
|
||||||
|
{
|
||||||
|
int roomtype;
|
||||||
|
float drylevel;
|
||||||
|
float drygoal;
|
||||||
|
float dryrate;
|
||||||
|
float wetlevel;
|
||||||
|
float wetgoal;
|
||||||
|
float wetrate;
|
||||||
|
bool active;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct orientation_t
|
||||||
|
{
|
||||||
|
float origin[3];
|
||||||
|
float axis[3][3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_listener
|
||||||
|
{
|
||||||
|
orientation_t orient;
|
||||||
|
float velocity;
|
||||||
|
int clientNum;
|
||||||
|
bool active;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_amplifier
|
||||||
|
{
|
||||||
|
snd_listener* listener;
|
||||||
|
int minRadius;
|
||||||
|
int maxRadius;
|
||||||
|
float falloffExp;
|
||||||
|
float minVol;
|
||||||
|
float maxVol;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_entchannel_info_t
|
||||||
|
{
|
||||||
|
char name[64];
|
||||||
|
int priority;
|
||||||
|
bool is3d;
|
||||||
|
bool isRestricted;
|
||||||
|
bool isPausable;
|
||||||
|
int maxVoices;
|
||||||
|
int voiceCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_entchan_overrides_t
|
||||||
|
{
|
||||||
|
unsigned int isPausable[2];
|
||||||
|
float timescaleLerp[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SndFileLoadingState
|
||||||
|
{
|
||||||
|
SFLS_UNLOADED = 0x0,
|
||||||
|
SFLS_LOADING = 0x1,
|
||||||
|
SFLS_LOADED = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SndFileSpecificChannelInfo
|
||||||
|
{
|
||||||
|
SndFileLoadingState loadingState;
|
||||||
|
int srcChannelCount;
|
||||||
|
int baserate;
|
||||||
|
};
|
||||||
|
|
||||||
|
union SndEntHandle
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int entIndex;
|
||||||
|
} field;
|
||||||
|
int handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SndLengthId
|
||||||
|
{
|
||||||
|
SndLengthNotify_Subtitle = 0x0,
|
||||||
|
SndLengthNotify_EntityCustom = 0x1,
|
||||||
|
SndLengthNotifyCount = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sndLengthNotifyInfo
|
||||||
|
{
|
||||||
|
SndLengthId id[4];
|
||||||
|
void* data[4];
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum snd_alias_system_t
|
||||||
|
{
|
||||||
|
SASYS_UI = 0x0,
|
||||||
|
SASYS_CGAME = 0x1,
|
||||||
|
SASYS_GAME = 0x2,
|
||||||
|
SASYS_COUNT = 0x3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_channel_info_t
|
||||||
|
{
|
||||||
|
SndFileSpecificChannelInfo soundFileInfo;
|
||||||
|
SndEntHandle sndEnt;
|
||||||
|
int entchannel;
|
||||||
|
int startDelay;
|
||||||
|
int looptime;
|
||||||
|
int totalMsec;
|
||||||
|
int playbackId;
|
||||||
|
sndLengthNotifyInfo lengthNotifyInfo;
|
||||||
|
float basevolume;
|
||||||
|
float pitch;
|
||||||
|
struct snd_alias_t* alias0;
|
||||||
|
struct snd_alias_t* alias1;
|
||||||
|
int saveIndex0;
|
||||||
|
int saveIndex1;
|
||||||
|
float lerp;
|
||||||
|
float org[3];
|
||||||
|
float offset[3];
|
||||||
|
bool paused;
|
||||||
|
bool master;
|
||||||
|
float timescaleLerp;
|
||||||
|
snd_alias_system_t system;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct snd_local_t
|
||||||
|
{
|
||||||
|
bool Initialized2d;
|
||||||
|
bool Initialized3d;
|
||||||
|
bool paused;
|
||||||
|
int playbackIdCounter;
|
||||||
|
unsigned int playback_rate;
|
||||||
|
int playback_channels;
|
||||||
|
float timescale;
|
||||||
|
int pausetime;
|
||||||
|
int cpu;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
char buffer[16384];
|
||||||
|
volatile int size;
|
||||||
|
bool compress;
|
||||||
|
} restore;
|
||||||
|
float volume;
|
||||||
|
snd_volume_info_t mastervol;
|
||||||
|
snd_channelvolgroup channelVolGroups[4];
|
||||||
|
snd_channelvolgroup* channelvol;
|
||||||
|
snd_background_info_t background[4];
|
||||||
|
int ambient_track;
|
||||||
|
float slaveLerp;
|
||||||
|
float masterPercentage;
|
||||||
|
snd_enveffect envEffects[5];
|
||||||
|
snd_enveffect* effect;
|
||||||
|
snd_listener listeners[2];
|
||||||
|
int time;
|
||||||
|
int looptime;
|
||||||
|
snd_amplifier amplifier;
|
||||||
|
snd_entchannel_info_t entchaninfo[64];
|
||||||
|
snd_entchan_overrides_t entchanOverrides;
|
||||||
|
int entchannel_count;
|
||||||
|
snd_channel_info_t chaninfo[52];
|
||||||
|
int max_2D_channels;
|
||||||
|
int max_3D_channels;
|
||||||
|
int max_stream_channels;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct SoundFile
|
struct SoundFile
|
||||||
{
|
{
|
||||||
char type;
|
char type;
|
||||||
@ -2504,12 +2687,6 @@ namespace Game
|
|||||||
SoundFileRef u;
|
SoundFileRef u;
|
||||||
};
|
};
|
||||||
|
|
||||||
union $C8D87EB0090687D323381DFB7A82089C
|
|
||||||
{
|
|
||||||
float slavePercentage;
|
|
||||||
float masterPercentage;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SndCurve
|
struct SndCurve
|
||||||
{
|
{
|
||||||
const char* filename;
|
const char* filename;
|
||||||
@ -2537,6 +2714,26 @@ namespace Game
|
|||||||
MSSChannelMap channelMaps[2][2];
|
MSSChannelMap channelMaps[2][2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union SoundAliasFlags
|
||||||
|
{
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4201)
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned int looping : 1; // & 1 / 0x1 / 0000 0000 0000 0001
|
||||||
|
unsigned int isMaster : 1; // & 2 / 0x2 / 0000 0000 0000 0010
|
||||||
|
unsigned int isSlave : 1; // & 4 / 0x4 / 0000 0000 0000 0100
|
||||||
|
unsigned int fullDryLevel : 1; // & 8 / 0x8 / 0000 0000 0000 1000
|
||||||
|
unsigned int noWetLevel : 1; // & 16 / 0x10 / 0000 0000 0001 0000
|
||||||
|
unsigned int unknown : 1; // & 32 / 0x20 / 0000 0000 0010 0000
|
||||||
|
unsigned int unk_is3D : 1; // & 64 / 0x40 / 0000 0000 0100 0000 // CONFIRMED IW4 IW5
|
||||||
|
unsigned int type : 2; // & 384 / 0x180 / 0000 0001 1000 0000 // CONFIRMED IW4 IW5
|
||||||
|
unsigned int channel : 6; // & 32256 / 0x7E00 / 0111 1110 0000 0000 // CONFIRMED IW4 IW5
|
||||||
|
};
|
||||||
|
#pragma warning(pop)
|
||||||
|
unsigned int intValue;
|
||||||
|
};
|
||||||
|
|
||||||
const struct snd_alias_t
|
const struct snd_alias_t
|
||||||
{
|
{
|
||||||
const char* aliasName;
|
const char* aliasName;
|
||||||
@ -2553,8 +2750,12 @@ namespace Game
|
|||||||
float distMin;
|
float distMin;
|
||||||
float distMax;
|
float distMax;
|
||||||
float velocityMin;
|
float velocityMin;
|
||||||
int flags;
|
SoundAliasFlags flags;
|
||||||
$C8D87EB0090687D323381DFB7A82089C ___u15;
|
union
|
||||||
|
{
|
||||||
|
float slavePercentage;
|
||||||
|
float masterPercentage;
|
||||||
|
} ___u15;
|
||||||
float probability;
|
float probability;
|
||||||
float lfePercentage;
|
float lfePercentage;
|
||||||
float centerPercentage;
|
float centerPercentage;
|
||||||
@ -2637,7 +2838,7 @@ namespace Game
|
|||||||
|
|
||||||
struct cLeafBrushNode_s
|
struct cLeafBrushNode_s
|
||||||
{
|
{
|
||||||
char axis;
|
unsigned char axis;
|
||||||
__int16 leafBrushCount;
|
__int16 leafBrushCount;
|
||||||
int contents;
|
int contents;
|
||||||
cLeafBrushNodeData_t data;
|
cLeafBrushNodeData_t data;
|
||||||
@ -2654,9 +2855,9 @@ namespace Game
|
|||||||
|
|
||||||
struct CollisionPartition
|
struct CollisionPartition
|
||||||
{
|
{
|
||||||
char triCount;
|
unsigned char triCount;
|
||||||
char borderCount;
|
unsigned char borderCount;
|
||||||
char firstVertSegment;
|
unsigned char firstVertSegment;
|
||||||
int firstTri;
|
int firstTri;
|
||||||
CollisionBorder* borders;
|
CollisionBorder* borders;
|
||||||
};
|
};
|
||||||
@ -2993,7 +3194,7 @@ namespace Game
|
|||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
int isInUse;
|
int isInUse;
|
||||||
int planeCount;
|
unsigned int planeCount;
|
||||||
cplane_s* planes;
|
cplane_s* planes;
|
||||||
unsigned int numStaticModels;
|
unsigned int numStaticModels;
|
||||||
cStaticModel_s* staticModelList;
|
cStaticModel_s* staticModelList;
|
||||||
@ -3002,7 +3203,7 @@ namespace Game
|
|||||||
unsigned int numBrushSides;
|
unsigned int numBrushSides;
|
||||||
cbrushside_t* brushsides;
|
cbrushside_t* brushsides;
|
||||||
unsigned int numBrushEdges;
|
unsigned int numBrushEdges;
|
||||||
char* brushEdges;
|
unsigned char* brushEdges;
|
||||||
unsigned int numNodes;
|
unsigned int numNodes;
|
||||||
cNode_t* nodes;
|
cNode_t* nodes;
|
||||||
unsigned int numLeafs;
|
unsigned int numLeafs;
|
||||||
@ -3014,15 +3215,15 @@ namespace Game
|
|||||||
unsigned int numLeafSurfaces;
|
unsigned int numLeafSurfaces;
|
||||||
unsigned int* leafsurfaces;
|
unsigned int* leafsurfaces;
|
||||||
unsigned int vertCount;
|
unsigned int vertCount;
|
||||||
float(*verts)[3];
|
vec3_t* verts;
|
||||||
int triCount;
|
unsigned int triCount;
|
||||||
unsigned __int16* triIndices;
|
unsigned __int16* triIndices;
|
||||||
char* triEdgeIsWalkable;
|
unsigned char* triEdgeIsWalkable;
|
||||||
int borderCount;
|
unsigned int borderCount;
|
||||||
CollisionBorder* borders;
|
CollisionBorder* borders;
|
||||||
int partitionCount;
|
int partitionCount;
|
||||||
CollisionPartition* partitions;
|
CollisionPartition* partitions;
|
||||||
int aabbTreeCount;
|
unsigned int aabbTreeCount;
|
||||||
CollisionAabbTree* aabbTrees;
|
CollisionAabbTree* aabbTrees;
|
||||||
unsigned int numSubModels;
|
unsigned int numSubModels;
|
||||||
cmodel_t* cmodels;
|
cmodel_t* cmodels;
|
||||||
@ -3394,9 +3595,9 @@ namespace Game
|
|||||||
float texCoordOrigin[2];
|
float texCoordOrigin[2];
|
||||||
unsigned int supportMask;
|
unsigned int supportMask;
|
||||||
float areaX2;
|
float areaX2;
|
||||||
char defIndex;
|
unsigned char defIndex;
|
||||||
char vertCount;
|
unsigned char vertCount;
|
||||||
char fanDataCount;
|
unsigned char fanDataCount;
|
||||||
char pad[1];
|
char pad[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -8654,6 +8855,12 @@ namespace Game
|
|||||||
unsigned __int16 children;
|
unsigned __int16 children;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ClientEntSound
|
||||||
|
{
|
||||||
|
float origin[3];
|
||||||
|
snd_alias_list_t* aliasList;
|
||||||
|
};
|
||||||
|
|
||||||
struct FxEffect
|
struct FxEffect
|
||||||
{
|
{
|
||||||
const FxEffectDef* def;
|
const FxEffectDef* def;
|
||||||
@ -10672,6 +10879,124 @@ namespace Game
|
|||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FxCamera
|
||||||
|
{
|
||||||
|
float origin[3];
|
||||||
|
volatile int isValid;
|
||||||
|
float frustum[6][4];
|
||||||
|
float axis[3][3];
|
||||||
|
unsigned int frustumPlaneCount;
|
||||||
|
float viewOffset[3];
|
||||||
|
bool thermal;
|
||||||
|
unsigned int pad[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct r_double_index_t
|
||||||
|
{
|
||||||
|
unsigned __int16 value[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FxSpriteInfo
|
||||||
|
{
|
||||||
|
r_double_index_t* indices;
|
||||||
|
unsigned int indexCount;
|
||||||
|
Material* material;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FxVisBlocker
|
||||||
|
{
|
||||||
|
float origin[3];
|
||||||
|
unsigned __int16 radius;
|
||||||
|
unsigned __int16 visibility;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FxVisState
|
||||||
|
{
|
||||||
|
FxVisBlocker blocker[256];
|
||||||
|
volatile int blockerCount;
|
||||||
|
unsigned int pad[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FxElem
|
||||||
|
{
|
||||||
|
char defIndex;
|
||||||
|
char sequence;
|
||||||
|
char atRestFraction;
|
||||||
|
char emitResidual;
|
||||||
|
unsigned __int16 nextElemHandleInEffect;
|
||||||
|
unsigned __int16 prevElemHandleInEffect;
|
||||||
|
int msecBegin;
|
||||||
|
float baseVel[3];
|
||||||
|
union
|
||||||
|
{
|
||||||
|
int physObjId;
|
||||||
|
float origin[3];
|
||||||
|
} ___u8;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
unsigned __int16 lightingHandle;
|
||||||
|
unsigned __int16 sparkCloudHandle;
|
||||||
|
unsigned __int16 sparkFountainHandle;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FxSystem
|
||||||
|
{
|
||||||
|
FxCamera camera;
|
||||||
|
FxCamera cameraPrev;
|
||||||
|
FxSpriteInfo sprite;
|
||||||
|
FxEffect* effects;
|
||||||
|
FxElem *elems;
|
||||||
|
void* trails;
|
||||||
|
void* trailElems;
|
||||||
|
void* bolts;
|
||||||
|
void* sparkClouds;
|
||||||
|
void* sparkFountains;
|
||||||
|
void* sparkFountainClusters;
|
||||||
|
unsigned __int16* deferredElems;
|
||||||
|
volatile int firstFreeElem;
|
||||||
|
volatile int firstFreeTrailElem;
|
||||||
|
volatile int firstFreeTrail;
|
||||||
|
volatile int firstFreeBolt;
|
||||||
|
volatile int firstFreeSparkCloud;
|
||||||
|
volatile int firstFreeSparkFountain;
|
||||||
|
volatile int firstFreeSparkFountainCluster;
|
||||||
|
volatile int deferredElemCount;
|
||||||
|
volatile int activeElemCount;
|
||||||
|
volatile int activeTrailElemCount;
|
||||||
|
volatile int activeTrailCount;
|
||||||
|
volatile int activeBoltCount;
|
||||||
|
volatile int activeSparkCloudCount;
|
||||||
|
volatile int activeSparkFountainCount;
|
||||||
|
volatile int activeSparkFountainClusterCount;
|
||||||
|
volatile int gfxCloudCount;
|
||||||
|
FxVisState* visState;
|
||||||
|
FxVisState* visStateBufferRead;
|
||||||
|
FxVisState* visStateBufferWrite;
|
||||||
|
volatile int firstActiveEffect;
|
||||||
|
volatile int firstNewEffect;
|
||||||
|
volatile int firstFreeEffect;
|
||||||
|
unsigned __int16 allEffectHandles[1024];
|
||||||
|
volatile int activeSpotLightEffectCount;
|
||||||
|
volatile int activeSpotLightElemCount;
|
||||||
|
unsigned __int16 activeSpotLightEffectHandle;
|
||||||
|
unsigned __int16 activeSpotLightElemHandle;
|
||||||
|
__int16 activeSpotLightBoltDobj;
|
||||||
|
volatile int iteratorCount;
|
||||||
|
int msecNow;
|
||||||
|
volatile int msecDraw;
|
||||||
|
int frameCount;
|
||||||
|
bool isInitialized;
|
||||||
|
bool needsGarbageCollection;
|
||||||
|
bool isArchiving;
|
||||||
|
char localClientNum;
|
||||||
|
unsigned int restartList[32];
|
||||||
|
FxEffect** restartEffectsList;
|
||||||
|
unsigned int restartCount;
|
||||||
|
unsigned int pad1[14];
|
||||||
|
};
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#ifndef IDA
|
#ifndef IDA
|
||||||
|
@ -62,4 +62,12 @@ namespace Utils::Json
|
|||||||
return input.to_ulong();
|
return input.to_ulong();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Game::Bounds ReadBounds(const nlohmann::json_abi_v3_11_2::json value)
|
||||||
|
{
|
||||||
|
Game::Bounds bounds{};
|
||||||
|
Utils::Json::CopyArray(bounds.midPoint, value["midPoint"]);
|
||||||
|
Utils::Json::CopyArray(bounds.halfSize, value["halfSize"]);
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <json.hpp>
|
#include <json.hpp>
|
||||||
|
|
||||||
namespace Utils::Json
|
namespace Utils::Json
|
||||||
{
|
{
|
||||||
std::string TypeToString(nlohmann::json::value_t type);
|
std::string TypeToString(nlohmann::json::value_t type);
|
||||||
|
|
||||||
unsigned long ReadFlags(std::string binaryFlags, size_t size);
|
unsigned long ReadFlags(const std::string binaryFlags, size_t size);
|
||||||
|
|
||||||
|
Game::Bounds ReadBounds(const nlohmann::json_abi_v3_11_2::json value);
|
||||||
|
|
||||||
|
template <typename T> void CopyArray(T* destination, const nlohmann::json_abi_v3_11_2::json& json_member, size_t count = 0)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
count = json_member.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
destination[i] = json_member[i].get<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ namespace Utils::Maths
|
|||||||
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
|
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorSubtract(float va[3], float vb[3], float out[3])
|
void VectorSubtract(const float va[3], const float vb[3], float out[3])
|
||||||
{
|
{
|
||||||
out[0] = va[0] - vb[0];
|
out[0] = va[0] - vb[0];
|
||||||
out[1] = va[1] - vb[1];
|
out[1] = va[1] - vb[1];
|
||||||
@ -35,7 +35,7 @@ namespace Utils::Maths
|
|||||||
out[2] = v[2] * scale;
|
out[2] = v[2] * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Vec3SqrDistance(float v1[3], float v2[3])
|
float Vec3SqrDistance(const float v1[3], const float v2[3])
|
||||||
{
|
{
|
||||||
float out[3];
|
float out[3];
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@ namespace Utils::Maths
|
|||||||
constexpr auto VectorNegate(float x[3]) { x[0] = -x[0]; x[1] = -x[1]; x[2] = -x[2]; }
|
constexpr auto VectorNegate(float x[3]) { x[0] = -x[0]; x[1] = -x[1]; x[2] = -x[2]; }
|
||||||
|
|
||||||
float DotProduct(float v1[3], float v2[3]);
|
float DotProduct(float v1[3], float v2[3]);
|
||||||
void VectorSubtract(float va[3], float vb[3], float out[3]);
|
void VectorSubtract(const float va[3], const float vb[3], float out[3]);
|
||||||
void VectorAdd(float va[3], float vb[3], float out[3]);
|
void VectorAdd(float va[3], float vb[3], float out[3]);
|
||||||
void VectorCopy(float in[3], float out[3]);
|
void VectorCopy(float in[3], float out[3]);
|
||||||
void VectorScale(float v[3], float scale, float out[3]);
|
void VectorScale(float v[3], float scale, float out[3]);
|
||||||
float Vec3SqrDistance(float v1[3], float v2[3]);
|
float Vec3SqrDistance(const float v1[3], const float v2[3]);
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,14 @@ namespace Utils
|
|||||||
|
|
||||||
const char* Stream::Reader::readCString()
|
const char* Stream::Reader::readCString()
|
||||||
{
|
{
|
||||||
return this->allocator->duplicateString(this->readString());
|
return this->allocator_->duplicateString(this->readString());
|
||||||
}
|
}
|
||||||
|
|
||||||
char Stream::Reader::readByte()
|
char Stream::Reader::readByte()
|
||||||
{
|
{
|
||||||
if ((this->position + 1) <= this->buffer.size())
|
if ((this->position_ + 1) <= this->buffer_.size())
|
||||||
{
|
{
|
||||||
return this->buffer[this->position++];
|
return this->buffer_[this->position_++];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Reading past the buffer");
|
throw std::runtime_error("Reading past the buffer");
|
||||||
@ -31,45 +31,45 @@ namespace Utils
|
|||||||
|
|
||||||
void* Stream::Reader::read(size_t size, std::size_t count)
|
void* Stream::Reader::read(size_t size, std::size_t count)
|
||||||
{
|
{
|
||||||
size_t bytes = size * count;
|
auto bytes = size * count;
|
||||||
|
|
||||||
if ((this->position + bytes) <= this->buffer.size())
|
if ((this->position_ + bytes) <= this->buffer_.size())
|
||||||
{
|
{
|
||||||
void* _buffer = this->allocator->allocate(bytes);
|
auto* buffer = this->allocator_->allocate(bytes);
|
||||||
|
|
||||||
std::memcpy(_buffer, this->buffer.data() + this->position, bytes);
|
std::memcpy(buffer, this->buffer_.data() + this->position_, bytes);
|
||||||
this->position += bytes;
|
this->position_ += bytes;
|
||||||
|
|
||||||
return _buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Reading past the buffer");
|
throw std::runtime_error("Reading past the buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::Reader::end()
|
bool Stream::Reader::end() const
|
||||||
{
|
{
|
||||||
return (this->buffer.size() == this->position);
|
return (this->buffer_.size() == this->position_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::Reader::seek(unsigned int _position)
|
void Stream::Reader::seek(unsigned int position)
|
||||||
{
|
{
|
||||||
if (this->buffer.size() >= _position)
|
if (this->buffer_.size() >= position)
|
||||||
{
|
{
|
||||||
this->position = _position;
|
this->position_ = position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::Reader::seekRelative(unsigned int _position)
|
void Stream::Reader::seekRelative(unsigned int position)
|
||||||
{
|
{
|
||||||
return this->seek(_position + this->position);
|
return this->seek(position + this->position_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Stream::Reader::readPointer()
|
void* Stream::Reader::readPointer()
|
||||||
{
|
{
|
||||||
void* pointer = this->read<void*>();
|
auto* pointer = this->read<void*>();
|
||||||
if (!this->hasPointer(pointer))
|
if (!this->hasPointer(pointer))
|
||||||
{
|
{
|
||||||
this->pointerMap[pointer] = nullptr;
|
this->pointerMap_[pointer] = nullptr;
|
||||||
}
|
}
|
||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
@ -78,18 +78,18 @@ namespace Utils
|
|||||||
{
|
{
|
||||||
if (this->hasPointer(oldPointer))
|
if (this->hasPointer(oldPointer))
|
||||||
{
|
{
|
||||||
this->pointerMap[oldPointer] = newPointer;
|
this->pointerMap_[oldPointer] = newPointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stream::Reader::hasPointer(void* pointer)
|
bool Stream::Reader::hasPointer(void* pointer) const
|
||||||
{
|
{
|
||||||
return this->pointerMap.find(pointer) != this->pointerMap.end();
|
return this->pointerMap_.contains(pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Stream() : ptrAssertion(false), criticalSectionState(0)
|
Stream::Stream() : ptrAssertion(false), criticalSectionState(0)
|
||||||
{
|
{
|
||||||
memset(this->blockSize, 0, sizeof(this->blockSize));
|
std::memset(this->blockSize, 0, sizeof(this->blockSize));
|
||||||
|
|
||||||
#ifdef WRITE_LOGS
|
#ifdef WRITE_LOGS
|
||||||
this->structLevel = 0;
|
this->structLevel = 0;
|
||||||
@ -99,12 +99,12 @@ namespace Utils
|
|||||||
|
|
||||||
Stream::Stream(size_t size) : Stream()
|
Stream::Stream(size_t size) : Stream()
|
||||||
{
|
{
|
||||||
this->buffer.reserve(size);
|
this->buffer_.reserve(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::~Stream()
|
Stream::~Stream()
|
||||||
{
|
{
|
||||||
this->buffer.clear();
|
this->buffer_.clear();
|
||||||
|
|
||||||
if (this->criticalSectionState != 0)
|
if (this->criticalSectionState != 0)
|
||||||
{
|
{
|
||||||
@ -114,12 +114,12 @@ namespace Utils
|
|||||||
|
|
||||||
std::size_t Stream::length() const
|
std::size_t Stream::length() const
|
||||||
{
|
{
|
||||||
return this->buffer.length();
|
return this->buffer_.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t Stream::capacity() const
|
std::size_t Stream::capacity() const
|
||||||
{
|
{
|
||||||
return this->buffer.capacity();
|
return this->buffer_.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::assertPointer(const void* pointer, std::size_t length)
|
void Stream::assertPointer(const void* pointer, std::size_t length)
|
||||||
@ -159,7 +159,7 @@ namespace Utils
|
|||||||
return this->at();
|
return this->at();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = this->data();
|
auto* data = this->data();
|
||||||
|
|
||||||
if (this->isCriticalSection() && this->length() + (size * count) > this->capacity())
|
if (this->isCriticalSection() && this->length() + (size * count) > this->capacity())
|
||||||
{
|
{
|
||||||
@ -167,7 +167,7 @@ namespace Utils
|
|||||||
__debugbreak();
|
__debugbreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->buffer.append(static_cast<const char*>(_str), size * count);
|
this->buffer_.append(static_cast<const char*>(_str), size * count);
|
||||||
|
|
||||||
if (this->data() != data && this->isCriticalSection())
|
if (this->data() != data && this->isCriticalSection())
|
||||||
{
|
{
|
||||||
@ -319,7 +319,7 @@ namespace Utils
|
|||||||
|
|
||||||
char* Stream::data()
|
char* Stream::data()
|
||||||
{
|
{
|
||||||
return const_cast<char*>(this->buffer.data());
|
return const_cast<char*>(this->buffer_.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Stream::getBlockSize(Game::XFILE_BLOCK_TYPES stream)
|
unsigned int Stream::getBlockSize(Game::XFILE_BLOCK_TYPES stream)
|
||||||
|
@ -21,13 +21,13 @@ namespace Utils
|
|||||||
int criticalSectionState;
|
int criticalSectionState;
|
||||||
unsigned int blockSize[Game::MAX_XFILE_COUNT];
|
unsigned int blockSize[Game::MAX_XFILE_COUNT];
|
||||||
std::vector<Game::XFILE_BLOCK_TYPES> streamStack;
|
std::vector<Game::XFILE_BLOCK_TYPES> streamStack;
|
||||||
std::string buffer;
|
std::string buffer_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Reader
|
class Reader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Reader(Memory::Allocator* _allocator, const std::string& _buffer) : position(0), buffer(_buffer), allocator(_allocator) {}
|
Reader(Memory::Allocator* allocator, std::string& buffer) : position_(0), buffer_(std::move(buffer)), allocator_(allocator) {}
|
||||||
|
|
||||||
std::string readString();
|
std::string readString();
|
||||||
const char* readCString();
|
const char* readCString();
|
||||||
@ -53,18 +53,18 @@ namespace Utils
|
|||||||
auto ptr = read<int>();
|
auto ptr = read<int>();
|
||||||
auto* voidPtr = reinterpret_cast<void*>(ptr);
|
auto* voidPtr = reinterpret_cast<void*>(ptr);
|
||||||
|
|
||||||
if (allocator->isPointerMapped(voidPtr))
|
if (this->allocator_->isPointerMapped(voidPtr))
|
||||||
{
|
{
|
||||||
return allocator->getPointer<T>(voidPtr);
|
return this->allocator_->getPointer<T>(voidPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Bad data: missing ptr");
|
throw std::runtime_error("Bad data: missing ptr");
|
||||||
}
|
}
|
||||||
case FOLLOWING:
|
case FOLLOWING:
|
||||||
{
|
{
|
||||||
auto filePosition = position;
|
auto filePosition = this->position_;
|
||||||
auto data = readArray<T>(count);
|
auto data = readArray<T>(count);
|
||||||
allocator->mapPointer(reinterpret_cast<void*>(filePosition), data);
|
this->allocator_->mapPointer(reinterpret_cast<void*>(filePosition), data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -89,19 +89,19 @@ namespace Utils
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool end();
|
bool end() const;
|
||||||
void seek(unsigned int position);
|
void seek(unsigned int position);
|
||||||
void seekRelative(unsigned int position);
|
void seekRelative(unsigned int position);
|
||||||
|
|
||||||
void* readPointer();
|
void* readPointer();
|
||||||
void mapPointer(void* oldPointer, void* newPointer);
|
void mapPointer(void* oldPointer, void* newPointer);
|
||||||
bool hasPointer(void* pointer);
|
bool hasPointer(void* pointer) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int position;
|
unsigned int position_;
|
||||||
std::string buffer;
|
std::string buffer_;
|
||||||
std::map<void*, void*> pointerMap;
|
std::map<void*, void*> pointerMap_;
|
||||||
Memory::Allocator* allocator;
|
Memory::Allocator* allocator_;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Alignment
|
enum Alignment
|
||||||
@ -123,11 +123,13 @@ namespace Utils
|
|||||||
Stream(size_t size);
|
Stream(size_t size);
|
||||||
~Stream();
|
~Stream();
|
||||||
|
|
||||||
|
std::unordered_map<void*, size_t> dataPointers;
|
||||||
|
|
||||||
[[nodiscard]] std::size_t length() const;
|
[[nodiscard]] std::size_t length() const;
|
||||||
[[nodiscard]] std::size_t capacity() const;
|
[[nodiscard]] std::size_t capacity() const;
|
||||||
|
|
||||||
char* save(const void * _str, std::size_t size, std::size_t count = 1);
|
char* save(const void * str, std::size_t size, std::size_t count = 1);
|
||||||
char* save(Game::XFILE_BLOCK_TYPES stream, const void * _str, std::size_t size, std::size_t count);
|
char* save(Game::XFILE_BLOCK_TYPES stream, const void * str, std::size_t size, std::size_t count);
|
||||||
char* save(Game::XFILE_BLOCK_TYPES stream, int value, std::size_t count);
|
char* save(Game::XFILE_BLOCK_TYPES stream, int value, std::size_t count);
|
||||||
|
|
||||||
template <typename T> char* save(T* object)
|
template <typename T> char* save(T* object)
|
||||||
@ -135,6 +137,42 @@ namespace Utils
|
|||||||
return saveArray<T>(object, 1);
|
return saveArray<T>(object, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> char* saveObject(T value)
|
||||||
|
{
|
||||||
|
return saveArray(&value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void saveArrayIfNotExisting(T* data, size_t count)
|
||||||
|
{
|
||||||
|
#define POINTER 255
|
||||||
|
#define FOLLOWING 254
|
||||||
|
|
||||||
|
if (const auto itr = dataPointers.find(data); itr != dataPointers.end())
|
||||||
|
{
|
||||||
|
saveByte(POINTER);
|
||||||
|
saveObject(itr->second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
saveByte(FOLLOWING);
|
||||||
|
dataPointers.insert_or_assign(reinterpret_cast<void*>(data), length());
|
||||||
|
saveArray(data, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char* save(int value, size_t count = 1)
|
||||||
|
{
|
||||||
|
auto ret = this->length();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
this->save(&value, 4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->data() + ret;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T> char* saveArray(T* array, std::size_t count)
|
template <typename T> char* saveArray(T* array, std::size_t count)
|
||||||
{
|
{
|
||||||
return save(array, sizeof(T), count);
|
return save(array, sizeof(T), count);
|
||||||
|
Loading…
Reference in New Issue
Block a user