IW4Of Fixes (#775)

Co-authored-by: Louvenarde <louve@louve.systems>
Co-authored-by: FutureRave <edoardo.sanguineti222@gmail.com>
This commit is contained in:
Louve 2023-02-17 12:26:40 +01:00 committed by GitHub
parent d1f6f1db8b
commit 4103e4d174
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 87 additions and 24 deletions

@ -1 +1 @@
Subproject commit 2dde0c2103aab094f27b3c1daa790995df54faef
Subproject commit 6ef68c8535b60c681b179608f0c95fe0893e8937

View File

@ -17,7 +17,8 @@ end
function iw4_open_formats.project()
project "iw4-open-formats"
language "C++"
cppdialect "C++latest"
iw4_open_formats.includes()
pchheader "std_include.hpp"

View File

@ -22,7 +22,34 @@ namespace Assets
void IMaterialTechniqueSet::loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder)
{
header->techniqueSet = builder->getIW4OfApi()->read<Game::MaterialTechniqueSet>(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, name);
header->techniqueSet = builder->getIW4OfApi()->read<Game::MaterialTechniqueSet>(Game::ASSET_TYPE_TECHNIQUE_SET, name);
auto ptr = header->techniqueSet;
if (!ptr)
{
return;
}
while (ptr->remappedTechniqueSet && ptr->remappedTechniqueSet != ptr)
{
ptr = ptr->remappedTechniqueSet;
builder->loadAsset(Game::ASSET_TYPE_TECHNIQUE_SET, ptr, false);
for (size_t i = 0; i < Game::TECHNIQUE_COUNT; i++)
{
const auto technique = ptr->techniques[i];
if (technique)
{
for (size_t j = 0; j < technique->passCount; j++)
{
const auto pass = &technique->passArray[j];
builder->loadAsset(Game::ASSET_TYPE_VERTEXDECL, pass->vertexDecl, true);
builder->loadAsset(Game::ASSET_TYPE_PIXELSHADER, pass->pixelShader, true);
builder->loadAsset(Game::ASSET_TYPE_VERTEXSHADER, pass->vertexShader, true);
}
}
}
}
}
void IMaterialTechniqueSet::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)

View File

@ -572,7 +572,7 @@ namespace Assets
}
}
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MAP_ENTS, asset);
builder->loadAsset(Game::XAssetType::ASSET_TYPE_MAP_ENTS, asset->mapEnts);
}
void IclipMap_t::load(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder)

View File

@ -666,12 +666,25 @@ namespace Components
return Utils::Hook::Call<bool(Game::gentity_s*)>(0x5050C0)(ent);
}
int16 Maps::CM_TriggerModelBounds(int modelPointer, Game::Bounds* bounds) {
#ifdef DEBUG
Game::MapEnts* ents = *reinterpret_cast<Game::MapEnts**>(0x1AA651C); // Use me for debugging
(void)ents;
#endif
return Utils::Hook::Call<int16(int, Game::Bounds*)>(0x4416C0)(modelPointer, bounds);
unsigned short Maps::CM_TriggerModelBounds_Hk(unsigned int triggerIndex, Game::Bounds* bounds)
{
auto* ents = *reinterpret_cast<Game::MapEnts**>(0x1AA651C); // Use me for debugging
if (ents)
{
if (triggerIndex >= ents->trigger.count)
{
Logger::Error(Game::errorParm_t::ERR_DROP, "Invalid trigger index ({}) in entities exceeds the maximum trigger count ({}) defined in the clipmap. Check your map ents, or your clipmap!", triggerIndex, ents->trigger.count);
return 0;
}
else
{
return Utils::Hook::Call<unsigned short(int, Game::Bounds*)>(0x4416C0)(triggerIndex, bounds);
}
}
return 0;
}
Maps::Maps()
@ -714,11 +727,13 @@ namespace Components
Utils::Hook(0x5EE577, Maps::G_SpawnTurretHook, HOOK_CALL).install()->quick();
Utils::Hook(0x44A4D5, Maps::G_SpawnTurretHook, HOOK_CALL).install()->quick();
// Catch trigger errors before they're critical
Utils::Hook(0x5050D4, Maps::CM_TriggerModelBounds_Hk, HOOK_CALL).install()->quick();
#ifdef DEBUG
// Check trigger models
Utils::Hook(0x5FC0F1, Maps::SV_SetTriggerModelHook, HOOK_CALL).install()->quick();
Utils::Hook(0x5FC2671, Maps::SV_SetTriggerModelHook, HOOK_CALL).install()->quick();
Utils::Hook(0x5050D4, Maps::CM_TriggerModelBounds, HOOK_CALL).install()->quick();
#endif
//

View File

@ -121,6 +121,6 @@ namespace Components
static void G_SpawnTurretHook(Game::gentity_s* ent, int unk, int unk2);
static bool SV_SetTriggerModelHook(Game::gentity_s* ent);
static int16 CM_TriggerModelBounds(int brushModelPointer, Game::Bounds* bounds);
static unsigned short CM_TriggerModelBounds_Hk(unsigned int brushModelPointer, Game::Bounds* bounds);
};
}

View File

@ -29,9 +29,9 @@ namespace Components
zoneName(name),
dataMap("zone_source/" + name + ".csv"),
branding{nullptr},
assetDepth(0)
assetDepth(0),
iw4ofApi(getIW4OfApiParams())
{
this->initializeIW4OfApi();
}
ZoneBuilder::Zone::~Zone()
@ -535,18 +535,21 @@ namespace Components
// Add branding asset
void ZoneBuilder::Zone::addBranding()
{
constexpr auto* data = "Built using the IW4x Zone:B:uilder Version 4";
auto dataLen = std::strlen(data); // + 1 is added by the save code
static std::string zoneBranding;
this->branding = {this->zoneName.data(), 0, static_cast<int>(dataLen), data};
const auto now = std::chrono::system_clock::now();
zoneBranding = std::format("Built using the IW4x ZoneBuilder! {:%d-%m-%Y %H:%M:%OS}", now);
auto brandingLen = zoneBranding.size(); // + 1 is added by the save code
if (this->findAsset(Game::XAssetType::ASSET_TYPE_RAWFILE, this->branding.name) != -1)
this->branding = {this->zoneName.data(), 0, static_cast<int>(brandingLen), zoneBranding.data()};
if (this->findAsset(Game::ASSET_TYPE_RAWFILE, this->branding.name) != -1)
{
Logger::Error(Game::ERR_FATAL, "Unable to add branding. Asset '{}' already exists!", this->branding.name);
}
Game::XAssetHeader header = { &this->branding };
Game::XAsset brandingAsset = { Game::XAssetType::ASSET_TYPE_RAWFILE, header };
Game::XAsset brandingAsset = { Game::ASSET_TYPE_RAWFILE, header };
this->loadedAssets.push_back(brandingAsset);
}
@ -757,7 +760,7 @@ namespace Components
return header;
}
void ZoneBuilder::Zone::initializeIW4OfApi()
iw4of::params_t ZoneBuilder::Zone::getIW4OfApiParams()
{
iw4of::params_t params;
@ -787,7 +790,7 @@ namespace Components
switch (t)
{
case iw4of::params_t::P_ERR:
Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}", message);
Logger::Error(Game::ERR_FATAL, "{}", message);
break;
case iw4of::params_t::P_WARN:
Logger::Print("{}", message);
@ -795,9 +798,16 @@ namespace Components
}
};
params.work_directory = (*Game::fs_basepath)->current.string;
if (*Game::fs_basepath && *Game::fs_gameDirVar)
{
params.work_directory = std::format("{}/{}", (*Game::fs_basepath)->current.string, (*Game::fs_gameDirVar)->current.string);
}
else
{
Logger::Error(Game::ERR_FATAL, "Missing FS Game directory or basepath directory!");
}
this->iw4ofApi = iw4of::api{ params };
return params;
}
int ZoneBuilder::StoreTexture(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image)

View File

@ -90,7 +90,7 @@ namespace Components
void addBranding();
void initializeIW4OfApi();
iw4of::params_t getIW4OfApiParams();
uint32_t safeGetPointer(const void* pointer);

View File

@ -48,6 +48,9 @@ namespace Game
const char* DB_GetXAssetName(XAsset* asset)
{
if (!asset) return "";
assert(asset->header.data);
return DB_GetXAssetNameHandlers[asset->type](&asset->header);
}

View File

@ -7801,6 +7801,13 @@ namespace Game
R_RENDERTARGET_NONE = 0xD,
};
struct GfxDrawPrimArgs
{
int vertexCount;
int triCount;
int baseIndex;
};
struct GfxCmdBufState
{
char refSamplerState[16];