From 1a4662a41fc54c33c88eba7ce00d18eaed9aaa79 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Sun, 1 Nov 2026 12:48:30 +0000 Subject: [PATCH] Decompile fn_17684 (CWorld::InitWorld) Batch #9400 by Lumen: 0 byte-identical, 1 confirmed by peer review. - fn_17684 CWorld::InitWorld: logic confirmed by peer review Peer-reviewed-by: ragnarok-clanker, gordaoprogramas, Toshiro Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes). --- Source/Contents/World/World.h | 1 + Source/Contents/World/WorldModelLoading.cpp | 225 ++++++++++++++++++++ Source/Contents/World/WorldModelLoading.h | 6 +- 3 files changed, 231 insertions(+), 1 deletion(-) diff --git a/Source/Contents/World/World.h b/Source/Contents/World/World.h index dd4cf168..b1c3e413 100644 --- a/Source/Contents/World/World.h +++ b/Source/Contents/World/World.h @@ -52,6 +52,7 @@ public: void AddPcPos(std::uint32_t aid, const CellFloatPos& cell); void AddPcPosFromCell(std::uint32_t aid, const int* cell); void AddPcPosUnindexed(std::uint32_t aid, const CellFloatPos& cell); + void InitWorld(); /* 0004 */ CGameMode* gameMode; /* 0008 */ std::list objects; diff --git a/Source/Contents/World/WorldModelLoading.cpp b/Source/Contents/World/WorldModelLoading.cpp index 0e196866..d1c93fa4 100644 --- a/Source/Contents/World/WorldModelLoading.cpp +++ b/Source/Contents/World/WorldModelLoading.cpp @@ -5,11 +5,45 @@ #include "Resource/ResourceMgr.h" #include "Resource/World/WorldResource.h" +#include "Client/Application/ErrorDialog.h" +#include "Client/Mode/CGameMode.h" +#include "Client/Mode/ModeMgr.h" +#include "Client/Session.h" +#include "Contents/Actors/Pc.h" +#include "Contents/Ground/GroundGeometry.h" +#include "Contents/Ground/GroundWaterState.h" +#include "Contents/Movies/BinkMovies.h" +#include "Contents/World/World.h" +#include "Render/Renderer.h" +#include "Resource/World/GroundResource.h" +#include "Resource/World/TerrainResource.h" +#include "UI/Window/UIWindowMgr.h" + #include #include #include #include #include +#include +#include + +void sub_E57380(); + +struct WindowLayerRenderer { + void sub_AA73B0(); +}; + +// GLOBAL: gl_24754 +float g_worldLightDirection[3]; + +// GLOBAL: gl_24755 +float g_worldDiffuse[3]; + +// GLOBAL: gl_24756 +float g_worldAmbient[3]; + +// GLOBAL: gl_24758 +float g_worldLoadCenter[3]; namespace { // INLINED @@ -62,6 +96,43 @@ namespace { return actor; } + + // INLINED + C3dActor* CreateInitWorldModel(const WorldModelRecord& placement, C3dModelRes& resource, BinkMovies& movies) { + resource.RegisterMovies(movies, placement.position); + + if (!resource.FindNode(placement.node) && resource.nodes.empty()) { + return nullptr; + } + + C3dActor* actor = nullptr; + + if (resource.major == 1) { + actor = new C3dActorV1; + } else if (resource.major == 2) { + actor = new C3dActorV2; + } + + actor->CopyVolumes(resource.volumes); + actor->SetSpeed(placement.animationSpeed); + actor->playback = placement.animation; + std::memcpy(actor->position, placement.position, sizeof(actor->position)); + actor->dirty = 1; + std::memcpy(actor->rotation, placement.rotation, sizeof(actor->rotation)); + actor->dirty = 1; + std::memcpy(actor->scale, placement.scale, sizeof(actor->scale)); + actor->dirty = 1; + actor->commandMode = placement.flag; + actor->color = static_cast(placement.index); + actor->Assign(resource); + actor->occlusionEnabled = 0; + void** actorVtbl = *reinterpret_cast(actor); + reinterpret_cast(actorVtbl[4])( + actor, g_worldLightDirection, g_worldDiffuse, g_worldAmbient + ); + + return actor; + } } // INLINED @@ -147,3 +218,157 @@ void WorldModelLoading::Finish() { this->deferred.clear(); std::atomic_ref(this->pending).store(0, std::memory_order_release); } + +// OFFSET: 0x00AC94C0 +// FUNCTION: fn_17684 +void CWorld::InitWorld() { + const auto ErrorDialog = reinterpret_cast( + static_cast(&ShowErrorDialog) + ); + + const char* rawMapName = reinterpret_cast(this->gameMode->SendMsg(9, 0, 0, 0, 0)); + std::string mapName(rawMapName ? rawMapName : ""); + + auto* worldRes = static_cast(ResourceMgr::Instance().Load(mapName.c_str())); + if (!worldRes) { + ErrorDialog("world\xbf\xa1 NULL\xb0\xaa\xc0\xcc \xb5\xe9\xbe\xee\xbf\xd4\xbd\xc0\xb4\xcf\xb4\xd9", 0); + return; + } + + this->movies = new BinkMovies(); + this->serializedSpatial = worldRes->spatial; + + int* modeBounds = reinterpret_cast(this->gameMode->unknown_0058); + modeBounds[0] = worldRes->bounds[2]; + modeBounds[1] = worldRes->bounds[3]; + modeBounds[2] = worldRes->bounds[0]; + modeBounds[3] = worldRes->bounds[1]; + + g_worldLightDirection[0] = worldRes->lightDirection[0]; + g_worldLightDirection[1] = worldRes->lightDirection[1]; + g_worldLightDirection[2] = worldRes->lightDirection[2]; + g_worldDiffuse[0] = worldRes->diffuse[0]; + g_worldDiffuse[1] = worldRes->diffuse[1]; + g_worldDiffuse[2] = worldRes->diffuse[2]; + g_worldAmbient[0] = worldRes->ambient[0]; + g_worldAmbient[1] = worldRes->ambient[1]; + g_worldAmbient[2] = worldRes->ambient[2]; + + g_renderer->twoPass = worldRes->flag; + g_renderer->SetLighting(g_worldLightDirection, g_worldDiffuse, g_worldAmbient); + + if (worldRes->terrainName.empty()) { + ErrorDialog("attr \xc6\xc4\xc0\xcf\xc0\xcc rsw \xb3\xbb\xbf\xa1 \xc1\xf6\xc1\xa4\xb5\xc7\xbe\xee \xc0\xd6\xc1\xf6 \xbe\xca\xbd\xc0\xb4\xcf\xb4\xd9", 0); + return; + } + + this->terrain = static_cast(ResourceMgr::Instance().Load(worldRes->terrainName.c_str())); + if (!this->terrain) { + ErrorDialog("attr \xc6\xc4\xc0\xcf \xc0\xd0\xb1\xe2\xbf\xa1 \xbd\xc7\xc6\xd0", 0); + return; + } + + this->terrain->cellSize = 5; + this->nearbyRange = this->terrain->cellSize * this->nearbyRange; + + if (worldRes->groundName.empty()) { + ErrorDialog("gnd \xc6\xc4\xc0\xcf\xc0\xcc rsw \xb3\xbb\xbf\xa1 \xc1\xf6\xc1\xa4\xb5\xc7\xbe\xee \xc0\xd6\xc1\xf6 \xbe\xca\xbd\xc0\xb4\xcf\xb4\xd9", 0); + return; + } + + auto* groundRes = static_cast(ResourceMgr::Instance().Load(worldRes->groundName.c_str())); + if (!groundRes) { + ErrorDialog("ground\xbf\xa1 NULL\xc0\xcc \xb5\xe9\xbe\xee\xbf\xd4\xbd\xc0\xb4\xcf\xb4\xd9.", 0); + return; + } + + if (groundRes->loaded == 0) { + ErrorDialog("\xb8\xca\xc0\xcc \xbf\xbe \xb9\xf6\xc1\xaf\xc0\xd4\xb4\xcf\xb4\xd9", 0); + return; + } + + this->ground = new GroundGeometry(); + void** groundVtbl = *reinterpret_cast(this->ground); + reinterpret_cast(groundVtbl[2])( + this->ground, groundRes, g_worldLightDirection, g_worldDiffuse, g_worldAmbient + ); + *reinterpret_cast(reinterpret_cast(this->ground) + 4) = this->terrain; + + reinterpret_cast(this->ground)->Set( + worldRes->waterLevel, + worldRes->waterType, + worldRes->waterAnimation, + static_cast(worldRes->wavePitch), + static_cast(worldRes->waveSpeed), + worldRes->waveHeight + ); + + reinterpret_cast(groundVtbl[13])(this->ground, groundRes); + + ResourceMgr::Instance().Remove(groundRes); + + const std::size_t modelCount = worldRes->models.size(); + this->models.clear(); + if (this->models.capacity() < modelCount) { + this->models.reserve(modelCount); + } + + DWORD lastNoticeTime = 0; + int lastPercent = -1; + int progress = 0; + + for (const WorldModelRecord* placement : worldRes->models) { + progress += 100; + DWORD now = timeGetTime(); + int percent = static_cast(progress / modelCount); + if ((percent != lastPercent && now - lastNoticeTime > 15) || percent == 100) { + lastPercent = percent; + lastNoticeTime = now; + g_windowMgr.SendNotice(4, percent, 0, 0, 0, 0); + g_windowMgr.CenterSurface0478(); + reinterpret_cast(&g_windowMgr)->sub_AA73B0(); + if (g_renderer->Draw()) { + g_renderer->Present(0); + } + sub_E57380(); + } + + reinterpret_cast(g_modeMgr.GetGameMode()) + ->CellCenter(g_session.m_playerX, g_session.m_playerY, g_worldLoadCenter[0], g_worldLoadCenter[2]); + + const float dx = placement->position[0] - g_worldLoadCenter[0]; + const float dy = placement->position[1] - g_worldLoadCenter[1]; + const float dz = placement->position[2] - g_worldLoadCenter[2]; + const float squared = dy * dy + dx * dx + dz * dz; + const float distance = std::sqrt(squared); + + if (distance > 200.0f) { + g_deferredWorldModels.push_back({distance, placement}); + } else { + auto* modelRes = static_cast(ResourceMgr::Instance().Load(placement->model)); + if (modelRes) { + if (C3dActor* actor = CreateInitWorldModel(*placement, *modelRes, *this->movies)) { + this->models.push_back(actor); + } + } + } + } + + InitializeWorldSpatial(this->spatial, reinterpret_cast(*this->ground), *this->terrain, this->models, this->serializedSpatial); + this->LoadMapEffects(); + + reinterpret_cast(groundVtbl[11])(this->ground); + + this->published = static_cast(this->models.size()); + + DWORD threadId = 0; + hObject = CreateThread(nullptr, 0, &WorldModelLoading::ThreadEntry, this, 0, &threadId); + if (!hObject) { + WorldModelLoading::ThreadEntry(this); + reinterpret_cast(this)->Finish(); + } + + this->player = new CPlayer(); + this->objects.push_back(this->player); + g_partyEffectNoticePending = 0; +} diff --git a/Source/Contents/World/WorldModelLoading.h b/Source/Contents/World/WorldModelLoading.h index 130df133..501f71c1 100644 --- a/Source/Contents/World/WorldModelLoading.h +++ b/Source/Contents/World/WorldModelLoading.h @@ -25,6 +25,11 @@ static_assert(offsetof(DeferredWorldModel, placement) == 4); extern HANDLE hObject; extern std::vector g_deferredWorldModels; +extern float g_worldLightDirection[3]; +extern float g_worldDiffuse[3]; +extern float g_worldAmbient[3]; +extern float g_worldLoadCenter[3]; +extern int g_partyEffectNoticePending; struct WorldModelLoading { ResourceMgr& resources; @@ -42,7 +47,6 @@ struct WorldModelLoading { void Publish(WorldSpatialTree& root); void Finish(); -private: static DWORD WINAPI ThreadEntry(void* context); };