diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index 4170255d..a121848e 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -132,6 +132,11 @@ namespace Components } } + if (type == 5 && name == "wc/codo_ui_viewer_black_decal3"s) + { + std::memcpy(&asset->material->gameFlags, &(*reinterpret_cast(0xA7FFE8))->gameFlags, sizeof(Game::Material) - 4); + } + if (Flags::HasFlag("entries")) { OutputDebugStringA(Utils::String::VA("%s: %d: %s\n", FastFiles::Current().data(), type, name)); @@ -275,7 +280,7 @@ namespace Components void AssetHandler::StoreEmptyAsset(Game::XAssetType type, const char* name) { - AssetHandler::EmptyAssets.push_back({ type,name }); + AssetHandler::EmptyAssets.push_back({ type, name }); } __declspec(naked) void AssetHandler::StoreEmptyAssetStub() @@ -313,6 +318,7 @@ namespace Components // Store empty assets Utils::Hook(0x5BB6EC, AssetHandler::StoreEmptyAssetStub, HOOK_CALL).Install()->Quick(); + // Log missing empty assets QuickPatch::OnFrame([] () { if (Game::Sys_IsDatabaseReady() && Game::Sys_IsDatabaseReady2() && !AssetHandler::EmptyAssets.empty()) diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index 4979ad8e..eb3badcf 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -180,6 +180,94 @@ namespace Components return (Utils::String::StartsWith(entity, "dyn_") || Utils::String::StartsWith(entity, "node_") || Utils::String::StartsWith(entity, "actor_")); } +#ifdef DEBUG + // Credit to SE2Dev, as we shouldn't share the code, keep that in debug mode! + void Maps::ExportMap(Game::GfxWorld* world) + { + Utils::Memory::Allocator allocator; + + std::string mtl; + mtl.append("# SE2Dev MTL File: \n"); + mtl.append("# Material Count: 0"); + + std::string map; + map.append("# Generated by SE2Dev's D3DBSP Tool\n"); + map.append(fmt::sprintf("o %s\n", world->baseName)); + map.append(fmt::sprintf("mtllib %s.mtl\n", world->baseName)); + + for (unsigned int i = 0; i < world->worldDraw.vertexCount; i++) + { + // Y/Z need to be inverted + float x = world->worldDraw.vd.vertices[i].xyz[0]; + float y = world->worldDraw.vd.vertices[i].xyz[2]; + float z = world->worldDraw.vd.vertices[i].xyz[1]; + + map.append(fmt::sprintf("v %.6f %.6f %.6f\n", x,y, z)); + } + + for (unsigned int i = 0; i < world->worldDraw.vertexCount; i++) + { + map.append(fmt::sprintf("vt %.6f %.6f\n", world->worldDraw.vd.vertices[i].texCoord[0], world->worldDraw.vd.vertices[i].texCoord[1])); + } + + int materialCount = 0; + Game::Material** materials = allocator.AllocateArray(world->dpvs.staticSurfaceCount); + + for (unsigned int i = 0; i < world->dpvs.staticSurfaceCount; i++) + { + bool isNewMat = true; + + for (int j = 0; j < materialCount; j++) + { + if (world->dpvs.surfaces[i].material == materials[j]) + { + isNewMat = false; + break; + } + } + + if (isNewMat) + { + materials[materialCount++] = world->dpvs.surfaces[i].material; + } + } + + for (int m = 0; m < materialCount; m++) + { + std::string name = materials[m]->name; + + auto pos = name.find_last_of("/"); + if (pos != std::string::npos) + { + name = name.substr(pos + 1); + } + + map.append(fmt::sprintf("usemtl %s\n", name.data())); + map.append("s off\n"); + + for (unsigned int i = 0; i < world->dpvs.staticSurfaceCount; i++) + { + if (world->dpvs.surfaces[i].material != materials[m]) + continue; + + int vertOffset = world->dpvs.surfaces[i].tris.firstVertex + 1;//+1 cus obj starts at 1 + int indexOffset = world->dpvs.surfaces[i].tris.baseIndex; + for (unsigned short j = 0; j < world->dpvs.surfaces[i].tris.triCount; j++) + { + int a = world->worldDraw.indices[indexOffset + j * 3 + 0] + vertOffset; + int b = world->worldDraw.indices[indexOffset + j * 3 + 1] + vertOffset; + int c = world->worldDraw.indices[indexOffset + j * 3 + 2] + vertOffset; + + map.append(fmt::sprintf("f %d/%d %d/%d %d/%d\n", a, a, b, b, c, c)); + } + } + } + + Utils::IO::WriteFile(fmt::sprintf("raw/mapdump/%s.mtl", world->baseName), mtl); + Utils::IO::WriteFile(fmt::sprintf("raw/mapdump/%s.obj", world->baseName), map); + } +#endif + void Maps::ReallocateEntryPool() { Assert_Size(Game::XAssetEntry, 16); @@ -277,6 +365,29 @@ namespace Components Maps::AddDependency("mp_cargoship_sh", "iw4x_dependencies_mp"); Maps::AddDependency("mp_firingrange", "iw4x_dependencies_mp"); Maps::AddDependency("mp_shipment_long", "iw4x_dependencies_mp"); + +#ifdef DEBUG + Command::Add("dumpmap", [] (Command::Params) + { + Game::GfxWorld* world = nullptr; + + Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_GFX_MAP, [] (Game::XAssetHeader header, void* world) + { + *reinterpret_cast(world) = header.gfxMap; + }, &world, false); + + if (world) + { + Maps::ExportMap(world); + Logger::Print("Map '%s' exported!\n", world->baseName); + } + else + { + Logger::Print("No map loaded, unable to dump anything!\n"); + } + }); + +#endif } Maps::~Maps() diff --git a/src/Components/Modules/Maps.hpp b/src/Components/Modules/Maps.hpp index 730e60b5..10bbdb03 100644 --- a/src/Components/Modules/Maps.hpp +++ b/src/Components/Modules/Maps.hpp @@ -26,6 +26,10 @@ namespace Components static int IgnoreEntityStub(const char* entity); +#ifdef DEBUG + static void ExportMap(Game::GfxWorld* world); +#endif + void ReallocateEntryPool(); }; } diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index 87bbdf72..88319978 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -1136,8 +1136,8 @@ namespace Components struct material339_s { - char drawSurfBegin[4]; // Probably wrong - int surfaceTypeBits; + char drawSurfBegin[8]; // 4 + //int surfaceTypeBits; const char *name; char drawSurf[6]; char gameFlags; @@ -1163,20 +1163,16 @@ namespace Components material->gameFlags = material359.gameFlags; // Probably wrong - material->surfaceTypeBits = material359.surfaceTypeBits; + material->surfaceTypeBits = 0;//material359.surfaceTypeBits; // Pretty sure that's wrong - memcpy(material->drawSurf, material359.drawSurfBegin, 4); + // Actually, it's not + memcpy(material->drawSurf, material359.drawSurfBegin, 8); - material->drawSurf[4] = 0; - material->drawSurf[5] = 0; - material->drawSurf[6] = 0; - - material->drawSurf[7] = material359.drawSurf[0]; - material->drawSurf[8] = material359.drawSurf[1]; - material->drawSurf[9] = material359.drawSurf[2]; - material->drawSurf[10] = material359.drawSurf[3]; - material->drawSurf[11] = material359.drawSurf[4]; + material->drawSurf[8] = material359.drawSurf[0]; + material->drawSurf[9] = material359.drawSurf[1]; + material->drawSurf[10] = material359.drawSurf[2]; + material->drawSurf[11] = material359.drawSurf[3]; return result; } @@ -1256,6 +1252,9 @@ namespace Components // Change block for image load defs Utils::Hook::Set(0x4D3224, ((Zones::ZoneVersion >= 332) ? 3 : 0)); + // This is needed if we want the original lightning on cargoship_sh, but original maps are darker + //Utils::Hook::Set(0x525333, 61); + if (patch) { Zones::LoadFxElemDefArrayHook.Install(); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index e1680cb7..acf1d4b3 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -2464,6 +2464,7 @@ namespace Game { float mins[3]; float maxs[3]; + int pad; unsigned __int16 childCount; unsigned __int16 surfaceCount; unsigned __int16 startSurfIndex; @@ -2507,7 +2508,7 @@ namespace Game char lightmapIndex; char reflectionProbeIndex; char primaryLightIndex; - bool castsSunShadow; + char castsSunShadow; }; struct GfxCullGroup @@ -2537,13 +2538,14 @@ namespace Game unsigned int staticSurfaceCount; unsigned int litSurfsBegin; unsigned int litSurfsEnd; - char unknown1[0x20]; + char unknown1[0x24]; char *smodelVisData[3]; char *surfaceVisData[3]; unsigned __int16 *sortedSurfIndex; + GfxStaticModelInst *smodelInsts; GfxSurface *surfaces; - GfxCullGroup *cullGroups; + GfxCullGroup *cullGroups; // actually GfxSurfaceBounds (24), but not important right now GfxStaticModelDrawInst *smodelDrawInsts; GfxDrawSurf *surfaceMaterials; unsigned int *surfaceCastsSunShadow; @@ -2757,18 +2759,16 @@ namespace Game GfxWorldVertexLayerData vld; int indexCount; unsigned __int16 *indices; - void/*IDirect3DIndexBuffer9*/* indexBuffer; }; - struct unknownGfxWorldStruct2 + struct GfxSky { - int unknownCount; - int * unknownArray; - GfxImage * unknownImage; - int unknown; + int skySurfCount; + int * skyStartSurfs; + GfxImage * skyImage; + int skySamplerState; }; - // That shit is wrong! struct GfxWorld { const char *name; @@ -2776,12 +2776,12 @@ namespace Game int planeCount; int nodeCount; int unknown2; - unsigned int unknownCount1; - unknownGfxWorldStruct2 * unknownStructs1; //Count = unknownCount1; + unsigned int skyCount; + GfxSky* skies; char unknown1[0x18]; GfxWorldDpvsPlanes dpvsPlanes; //The following rely on the count in this char *unknown4; - GfxAabbTree *aabbTree; + GfxAabbTree *aabbTree; // Actually GfxCellTree GfxCell *cells; GfxWorldDraw worldDraw; GfxLightGrid lightGrid; @@ -2801,17 +2801,73 @@ namespace Game char *primaryLightForModelDynEnt; GfxShadowGeometry *shadowGeom; GfxLightRegion *lightRegion; + + char pad[68]; + GfxWorldDpvsStatic dpvs; GfxWorldDpvsDynamic dpvsDyn; - unsigned int unknownCount3; - char * unknown3; //Size = unknownCount2 * 0x38 + + char pad2[4]; + + unsigned int heroOnlyLightCount; + char * heroOnlyLight; + int unknown5; + }; + + struct GfxWorld_new + { + const char *name; + const char *baseName; + int planeCount; + int nodeCount; + int unknown2; + unsigned int skyCount; + GfxSky* skies; + char unknown1[0x18]; + GfxWorldDpvsPlanes dpvsPlanes; //The following rely on the count in this + char *unknown4; + GfxAabbTree *aabbTree; // Actually GfxCellTree + GfxCell *cells; + GfxWorldDraw worldDraw; + GfxLightGrid lightGrid; + int modelCount; + GfxBrushModel *models; + float mins[3]; + float maxs[3]; + unsigned int checksum; + int materialMemoryCount; + MaterialMemory *materialMemory; + sunflare_t sun; + + char whatIsThat[968]; + + unsigned int *cellCasterBits[2]; + GfxSceneDynModel *sceneDynModel; + GfxSceneDynBrush *sceneDynBrush; + unsigned int *primaryLightEntityShadowVis; + unsigned int *primaryLightDynEntShadowVis[2]; + char *primaryLightForModelDynEnt; + GfxShadowGeometry *shadowGeom; + GfxLightRegion *lightRegion; + + char pad[68]; + + GfxWorldDpvsStatic dpvs; + GfxWorldDpvsDynamic dpvsDyn; + + char pad2[4]; + + unsigned int heroOnlyLightCount; + char * heroOnlyLight; int unknown5; }; #pragma pack(pop) -#ifdef __cplusplus - static_assert(offsetof(GfxWorld, worldDraw) == 80, ""); -#endif + struct rgpStruct + { + int pad[2117]; + GfxWorld* world; + }; union XAssetHeader { diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index 70df4e60..e37b628c 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -39,6 +39,12 @@ #include #include +// Usefull for debugging +template class Sizer { }; +#define BindNum(x, y) Sizer y; +#define SizeOf(x, y) BindNum(sizeof(x), y) +#define OffsetOf(x, y, z) BindNum(offsetof(x, y), z) + // Submodules // Ignore the warnings, it's no our code! #pragma warning(push)