From 4d9d775cc89ba66c3a42abfb50475769fafa1da5 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Tue, 27 Oct 2026 08:51:12 +0000 Subject: [PATCH] Decompile 3 functions in Source/Contents/World/WorldSpatialTree.cpp, Source/Contents/World/WorldSpatialTree.h, ... Batch #995 by ragnarok-clanker: 0 byte-identical, 3 confirmed by peer review. - fn_17651 WorldScene::WorldScene: logic confirmed by peer review - fn_17654 WorldScene::~WorldScene: logic confirmed by peer review - fn_17704 WorldSpatialTree::RefreshModelBounds: logic confirmed by peer review Reviewed-by: ragnarok-clanker --- Source/Client/Session.h | 7 +- Source/Contents/World/WorldScene.h | 77 +++++++++++++++++++ Source/Contents/World/WorldSpatialTree.cpp | 89 ++++++++++++++++++++++ Source/Contents/World/WorldSpatialTree.h | 1 + 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 Source/Contents/World/WorldScene.h diff --git a/Source/Client/Session.h b/Source/Client/Session.h index 2487efd..a58fe20 100644 --- a/Source/Client/Session.h +++ b/Source/Client/Session.h @@ -11,7 +11,10 @@ public: /* 0000 */ unsigned char unknown_0000[0xF18]; /* 0F18 */ int m_playerX; /* 0F1C */ int m_playerY; - /* 0F20 */ unsigned char unknown_0F20[0x88]; + /* 0F20 */ unsigned char unknown_0F20[0x08]; + /* 0F28 */ int m_score1; + /* 0F2C */ int m_score2; + /* 0F30 */ unsigned char unknown_0F30[0x78]; /* 0FA8 */ const char* const* m_jobNamesBegin; /* 0FAC */ const char* const* m_jobNamesEnd; /* 0FB0 */ unsigned char unknown_0FB0[0x678]; @@ -29,6 +32,8 @@ extern CSession g_session; #if defined(_WIN32) && !defined(_WIN64) static_assert(offsetof(CSession, m_playerX) == 0xF18); static_assert(offsetof(CSession, m_playerY) == 0xF1C); +static_assert(offsetof(CSession, m_score1) == 0xF28); +static_assert(offsetof(CSession, m_score2) == 0xF2C); static_assert(offsetof(CSession, m_jobNamesBegin) == 0xFA8); static_assert(offsetof(CSession, m_jobNamesEnd) == 0xFAC); static_assert(offsetof(CSession, m_job) == 0x1628); diff --git a/Source/Contents/World/WorldScene.h b/Source/Contents/World/WorldScene.h new file mode 100644 index 0000000..9b6be6e --- /dev/null +++ b/Source/Contents/World/WorldScene.h @@ -0,0 +1,77 @@ +#ifndef RAGNAROK_SOURCE_CONTENTS_WORLD_WORLDSCENE_H +#define RAGNAROK_SOURCE_CONTENTS_WORLD_WORLDSCENE_H + +#include "Contents/World/WorldSpatialTree.h" + +#include +#include +#include +#include +#include + +class BinkMovies; +class CGameMode; +class CPlayer; +class CRenderObject; +class GroundGeometry; + +class WorldScene { +public: + WorldScene(); + virtual ~WorldScene(); + WorldScene(const WorldScene&) = delete; + WorldScene& operator=(const WorldScene&) = delete; + + /* 0004 */ CGameMode* gameMode; + /* 0008 */ std::list objects; + /* 0010 */ std::list actors; + /* 0018 */ std::list unknown_0018; + /* 0020 */ std::list unknown_0020; + /* 0028 */ GroundGeometry* ground; + /* 002C */ CPlayer* player; + /* 0030 */ C3dAttr* terrain; + /* 0034 */ std::vector models; + /* 0040 */ int published; + /* 0044 */ int pending; + /* 0048 */ int unknown_0048; + /* 004C */ int unknown_004C; + /* 0050 */ int unknown_0050; + /* 0054 */ int unknown_0054; + /* 0058 */ WorldSpatialTree spatial; + /* 00D4 */ const WorldSpatialTree* serializedSpatial; + /* 00D8 */ std::list pendingActorIds; + /* 00E0 */ BinkMovies* movies; + /* 00E4 */ std::map> actorCells; + /* 00EC */ std::list unindexedActorIds; + /* 00F4 */ bool unknown_00F4; + /* 00F8 */ int nearbyRange; + /* 00FC */ bool unknown_00FC; + /* 00FD */ bool unknown_00FD; +}; + +#if defined(_WIN32) && !defined(_WIN64) +static_assert(offsetof(WorldScene, gameMode) == 0x04); +static_assert(offsetof(WorldScene, objects) == 0x08); +static_assert(offsetof(WorldScene, actors) == 0x10); +static_assert(offsetof(WorldScene, unknown_0018) == 0x18); +static_assert(offsetof(WorldScene, unknown_0020) == 0x20); +static_assert(offsetof(WorldScene, ground) == 0x28); +static_assert(offsetof(WorldScene, player) == 0x2C); +static_assert(offsetof(WorldScene, terrain) == 0x30); +static_assert(offsetof(WorldScene, models) == 0x34); +static_assert(offsetof(WorldScene, published) == 0x40); +static_assert(offsetof(WorldScene, pending) == 0x44); +static_assert(offsetof(WorldScene, spatial) == 0x58); +static_assert(offsetof(WorldScene, serializedSpatial) == 0xD4); +static_assert(offsetof(WorldScene, pendingActorIds) == 0xD8); +static_assert(offsetof(WorldScene, movies) == 0xE0); +static_assert(offsetof(WorldScene, actorCells) == 0xE4); +static_assert(offsetof(WorldScene, unindexedActorIds) == 0xEC); +static_assert(offsetof(WorldScene, unknown_00F4) == 0xF4); +static_assert(offsetof(WorldScene, nearbyRange) == 0xF8); +static_assert(offsetof(WorldScene, unknown_00FC) == 0xFC); +static_assert(offsetof(WorldScene, unknown_00FD) == 0xFD); +static_assert(sizeof(WorldScene) == 0x100); +#endif + +#endif diff --git a/Source/Contents/World/WorldSpatialTree.cpp b/Source/Contents/World/WorldSpatialTree.cpp index 98453c1..d57eba3 100644 --- a/Source/Contents/World/WorldSpatialTree.cpp +++ b/Source/Contents/World/WorldSpatialTree.cpp @@ -1,9 +1,43 @@ +#include "Client/Session.h" +#include "Contents/Ground/GroundGeometry.h" #include "Contents/Ground/GroundSpatial.h" #include "Contents/Models/ModelActor.h" +#include "Contents/Movies/BinkMovies.h" +#include "Contents/World/WorldScene.h" #include "Contents/World/WorldSpatialTree.h" #include "Resource/ResourceByteReader.h" #include "Resource/World/TerrainResource.h" +// OFFSET: 0x00AC64F0 +// FUNCTION: fn_17651 +WorldScene::WorldScene() { + this->unknown_00FD = false; + this->serializedSpatial = nullptr; + this->pending = 0; + this->ground = nullptr; + this->player = nullptr; + this->unknown_0048 = 0; + this->unknown_004C = 0; + this->unknown_0050 = 0; + g_session.m_score1 = -1; + g_session.m_score2 = -1; + this->unknown_0054 = 0; + this->unknown_00F4 = false; + this->nearbyRange = 2; + this->unknown_00FC = false; +} + +// OFFSET: 0x00AC6FB0 +// FUNCTION: fn_17654 +WorldScene::~WorldScene() { + delete this->ground; + + if (this->movies) { + delete this->movies; + this->movies = nullptr; + } +} + // OFFSET: 0x00AC66F0 // FUNCTION: fn_17652 WorldSpatialTree::WorldSpatialTree() : parent(nullptr), children{}, minimum{}, maximum{}, center{}, halfSize{}, dirty(1) { @@ -286,3 +320,58 @@ std::vector& WorldSpatialTree::ModelsAt(float x, float z, int depth) return node->objects; } + +// OFFSET: 0x00ACB560 +// FUNCTION: fn_17704 +void WorldSpatialTree::RefreshModelBounds(int depth) { + this->dirty = 0; + + if (depth != 5) { + for (WorldSpatialTree* child : this->children) { + if (child->dirty) { + child->RefreshModelBounds(depth + 1); + } + } + + return; + } + + float groundMinimum; + float groundMaximum; + float terrainMinimum; + float terrainMaximum; + this->ground->HeightBounds(this->groundCells, groundMinimum, groundMaximum); + this->terrain->Grid().HeightBounds(this->terrainCells, terrainMinimum, terrainMaximum); + this->maximum[1] = terrainMaximum > groundMaximum ? terrainMaximum : groundMaximum; + this->minimum[1] = terrainMinimum < groundMinimum ? terrainMinimum : groundMinimum; + + for (C3dActor* model : this->objects) { + if (this->minimum[1] > model->minimum[1]) { + this->minimum[1] = model->minimum[1]; + } + + if (model->maximum[1] > this->maximum[1]) { + this->maximum[1] = model->maximum[1]; + } + } + + WorldSpatialTree* node = this; + + do { + if (node->minimum[1] > this->minimum[1]) { + node->minimum[1] = this->minimum[1]; + } + + if (this->maximum[1] > node->maximum[1]) { + node->maximum[1] = this->maximum[1]; + } + + node->halfSize[0] = node->maximum[0] - node->center[0]; + const float halfZ = node->maximum[2] - node->center[2]; + const float middleY = (node->maximum[1] + node->minimum[1]) * 0.5f; + node->center[1] = middleY; + node->halfSize[2] = halfZ; + node->halfSize[1] = node->maximum[1] - middleY; + node = node->parent; + } while (node); +} diff --git a/Source/Contents/World/WorldSpatialTree.h b/Source/Contents/World/WorldSpatialTree.h index c1b2cf0..69374fd 100644 --- a/Source/Contents/World/WorldSpatialTree.h +++ b/Source/Contents/World/WorldSpatialTree.h @@ -21,6 +21,7 @@ struct WorldSpatialTree { void BindGround(GroundSpatial& resource, int depth); void CopyBounds(int depth, const WorldSpatialTree& source); void RefreshBounds(int depth); + void RefreshModelBounds(int depth); void InsertModel(C3dActor& model, int depth); void RemoveModel(C3dActor* model, int depth); std::vector& ModelsAt(float x, float z, int depth);