From 6382ad9b74ab889029073917cb6e705e6f016da1 Mon Sep 17 00:00:00 2001 From: alvaroms97 Date: Sun, 13 Sep 2026 16:18:22 +0200 Subject: [PATCH] Decompile `dWmConnect_c` Adds the world map point-connection graph builder: `dWmConnect_c` and its nested `dPnt_c` point struct, used to link CSV-defined world map points into a directed 6-way (up/down/front/back/left/right) graph consumed by the world map enemy pathing code. --- include/game/bases/d_wm_connect.hpp | 34 +++- include/game/bases/d_wm_csvdata.hpp | 2 + include/game/bases/d_wm_lib.hpp | 2 + slices/wiimj2d.json | 12 ++ source/dol/bases/d_wm_connect.cpp | 239 ++++++++++++++++++++++++++++ source/dol/bases/d_wm_enemy.cpp | 6 +- syms.txt | 3 +- 7 files changed, 289 insertions(+), 9 deletions(-) create mode 100644 source/dol/bases/d_wm_connect.cpp diff --git a/include/game/bases/d_wm_connect.hpp b/include/game/bases/d_wm_connect.hpp index 81676604b..69c761559 100644 --- a/include/game/bases/d_wm_connect.hpp +++ b/include/game/bases/d_wm_connect.hpp @@ -1,17 +1,41 @@ #pragma once #include #include +#include +#include class dWmConnect_c { public: /// @unofficial - struct Point_s { - u32 m_00; - char name[8]; + class dPnt_c { + public: + void SetInfo(const char *pointName, nw4r::math::VEC3 &pointPos, int index); + void init(); + dPnt_c *GetLink(int dir); + + u32 m_00; ///< @unofficial Unknown. Never read/written by any decompiled code so far. + char name[8]; ///< @unofficial Only the first MAX_POINT_NAME_LEN bytes are used. nw4r::math::VEC3 pos; + dPnt_c *mLink[6]; + s32 mActionLabel[6]; ///< @unofficial dCsvData_c::ActionType_e per link direction. + s32 mCourseNo; + s32 mPointIndex; + s32 mIsValid; ///< @unofficial Whether the point is usable for pathing (not a special/hidden node). }; - Point_s *GetPointFromIndex(int); + void SetInfo(dCsvData_c &csvData, const m3d::mdl_c &model); + void initialize(dCsvData_c &csvData, const m3d::mdl_c &model); + void calcConnect(dCsvData_c &csvData); + int GetPointNo(const char *name); + bool __connect(int a, int b); ///< @unofficial + void initAnimation(dCsvData_c &csvData); + void SetCourseNo(int index); + int GetCourseNoFromName(const char *name); + dPnt_c *GetConnect(const char *name, int dir); + dPnt_c *GetPointFromIndex(int index); + int GetDir(int indexA, int indexB); - u8 mPad[0x3f08]; + u32 m_00; ///< @unofficial Unknown. Never read/written by any decompiled code so far. + dPnt_c mPoints[MAX_POINT_COUNT]; + s32 mWorld; ///< @unofficial Copied from dCsvData_c::mWorld during initialize(). }; diff --git a/include/game/bases/d_wm_csvdata.hpp b/include/game/bases/d_wm_csvdata.hpp index 96e62da7e..fd5fbc2bf 100644 --- a/include/game/bases/d_wm_csvdata.hpp +++ b/include/game/bases/d_wm_csvdata.hpp @@ -21,6 +21,8 @@ /// @brief Loader for world map point / route data. /// @ingroup bases class dCsvData_c { + friend class dWmConnect_c; + public: /// @unofficial enum PointFlag_e { diff --git a/include/game/bases/d_wm_lib.hpp b/include/game/bases/d_wm_lib.hpp index 45b335005..521c967ed 100644 --- a/include/game/bases/d_wm_lib.hpp +++ b/include/game/bases/d_wm_lib.hpp @@ -50,6 +50,8 @@ namespace dWmLib { int GetCourseTypeFromCourseNo(int courseNo); int GetCourseNoFromPointName(const char *pointName); + TypePoint_e GetPointTypeFromPointName(const char *pointName); + void MakeRouteName(char *out, const char *pointA, const char *pointB); bool isKoopaShipAnchor(); u8 getStartPointKinokoHouseKindNum(); bool isStartPointKinokoHouseStar(); diff --git a/slices/wiimj2d.json b/slices/wiimj2d.json index af7affb16..d069458f8 100644 --- a/slices/wiimj2d.json +++ b/slices/wiimj2d.json @@ -538,6 +538,18 @@ ".sdata2": "0x1eb0-0x1ec8" } }, + { + "source": "dol/bases/d_wm_connect.cpp", + "memoryRanges": { + ".text": "0xec480-0xecdf0", + ".ctors": "0x16c-0x170", + ".data": "0x1d938-0x1d960", + ".bss": "0x22640-0x22650", + ".sdata": "0x1288-0x1298", + ".sbss": "0x570-0x578", + ".sdata2": "0x1ec8-0x1ee0" + } + }, { "source": "dol/bases/d_wm_csvdata.cpp", "memoryRanges": { diff --git a/source/dol/bases/d_wm_connect.cpp b/source/dol/bases/d_wm_connect.cpp new file mode 100644 index 000000000..d13f5a3a2 --- /dev/null +++ b/source/dol/bases/d_wm_connect.cpp @@ -0,0 +1,239 @@ +#include +#include +#include +#include + +void dWmConnect_c::dPnt_c::SetInfo(const char *pointName, nw4r::math::VEC3 &pointPos, int index) { + strncpy(name, pointName, 5); + pos.x = pointPos.x; + pos.y = pointPos.y; + pos.z = pointPos.z; + mPointIndex = index; +} + +void dWmConnect_c::dPnt_c::init() { + name[0] = 0; + name[1] = 0; + name[2] = 0; + name[3] = 0; + name[4] = 0; + + for (int i = 0; i < 6; i++) { + mLink[i] = nullptr; + mActionLabel[i] = dCsvData_c::ACTION_TYPE_NONE; + } + + mCourseNo = -1; + mPointIndex = -1; +} + +void dWmConnect_c::SetInfo(dCsvData_c &csvData, const m3d::mdl_c &model) { + nw4r::g3d::ResMdl resMdl = model.getResMdl(); + + for (int i = 0; i < csvData.mPointCount; i++) { + nw4r::math::VEC3 pos; + int nodeId = m3d::getNodeID(resMdl, csvData.GetPointName(i)); + model.getNodeWorldMtxMultVecZero(nodeId, pos); + + const char *pointName = csvData.GetPointName(i); + mPoints[i].SetInfo(pointName, pos, i); + + if (pointName[0] == 'K') { + mPoints[i].mIsValid = 1; + } else if (dWmLib::GetPointTypeFromPointName(pointName) == dWmLib::POINT_TYPE_START_NODE + || dWmLib::GetCourseNoFromPointName(pointName) >= 0 + || csvData.GetPointFlags(i, dCsvData_c::POINT_STOP) + || csvData.GetPointFlags(i, dCsvData_c::POINT_DOKAN) + || csvData.GetEnemyPointFlags(i, dCsvData_c::ENEMY_TRAP1) + || csvData.GetEnemyPointFlags(i, dCsvData_c::ENEMY_TRAP2) + || csvData.GetPointFlags(i, dCsvData_c::POINT_SWITCH)) { + mPoints[i].mIsValid = 0; + } else { + mPoints[i].mIsValid = 1; + } + } +} + +void dWmConnect_c::initialize(dCsvData_c &csvData, const m3d::mdl_c &model) { + mWorld = csvData.mWorld; + + for (int i = 0; i < MAX_POINT_COUNT; i++) { + mPoints[i].init(); + } + + SetInfo(csvData, model); + + for (int i = 0; i < MAX_POINT_COUNT; i++) { + SetCourseNo(i); + } + + calcConnect(csvData); + initAnimation(csvData); +} + +void dWmConnect_c::calcConnect(dCsvData_c &csvData) { + for (int i = 0; i < csvData.mSubrouteCount; i++) { + char startPointName[8]; + char endPointName[8]; + dWmLib::GetStartPointNameFromRouteName(csvData.GetSubRouteName(i), startPointName); + dWmLib::GetEndPointNameFromRouteName(csvData.GetSubRouteName(i), endPointName); + + if (startPointName[0]) { + __connect(GetPointNo(startPointName), GetPointNo(endPointName)); + } + } +} + +/// @unofficial +static inline dWmConnect_c::dPnt_c *getPnt(dWmConnect_c::dPnt_c *points, int index) { + return &points[index]; +} + +/// @unofficial +static inline char *getName(dWmConnect_c::dPnt_c *point) { + return point->name; +} + +int dWmConnect_c::GetPointNo(const char *name) { + dPnt_c *p = mPoints; + for (int i = 0; i < MAX_POINT_COUNT; i++, p++) { + if (strcmp(p->name, name) == 0) { + return i; + } + } + + return -1; +} + +bool dWmConnect_c::__connect(int a, int b) { + dPnt_c *pointB = getPnt(mPoints, b); + dPnt_c *pointA = getPnt(mPoints, a); + + float dx = pointA->pos.x - pointB->pos.x; + float dy = pointA->pos.y - pointB->pos.y; + float dz = pointA->pos.z - pointB->pos.z; + + bool xSmall = (float)std::fabs(dx) < 3.0f; + bool zSmall = (float)std::fabs(dz) < 3.0f; + + if (xSmall && zSmall) { + if (dy > 0.0f) { + mPoints[a].mLink[1] = pointB; + mPoints[b].mLink[0] = pointA; + } else { + mPoints[b].mLink[1] = pointA; + mPoints[a].mLink[0] = pointB; + } + } else if (xSmall) { + if (dz > 0.0f) { + mPoints[a].mLink[3] = pointB; + mPoints[b].mLink[2] = pointA; + } else { + mPoints[b].mLink[3] = pointA; + mPoints[a].mLink[2] = pointB; + } + } else if (zSmall) { + if (dx > 0.0f) { + mPoints[a].mLink[4] = pointB; + mPoints[b].mLink[5] = pointA; + } else { + mPoints[b].mLink[4] = pointA; + mPoints[a].mLink[5] = pointB; + } + } else if ((float)std::fabs(dz) >= 3.0f) { + if (dz > 0.0f) { + mPoints[a].mLink[3] = pointB; + mPoints[b].mLink[2] = pointA; + } else { + mPoints[b].mLink[3] = pointA; + mPoints[a].mLink[2] = pointB; + } + } else { + if (dx > 0.0f) { + mPoints[a].mLink[4] = pointB; + mPoints[b].mLink[5] = pointA; + } else { + mPoints[b].mLink[4] = pointA; + mPoints[a].mLink[5] = pointB; + } + } + + return true; +} + +void dWmConnect_c::initAnimation(dCsvData_c &csvData) { + char *ownName; + char *neighborName; + for (int i = 0; i < MAX_POINT_COUNT; i++) { + for (int dir = 0; dir < 6; dir++) { + dPnt_c *link = getPnt(mPoints, i)->GetLink(dir); + if (link != nullptr) { + ownName = getName(getPnt(mPoints, i)); + neighborName = getName(link); + char routeName[32]; + dWmLib::MakeRouteName(routeName, ownName, neighborName); + int label = csvData.GetActionLabel(routeName); + if (label == -1) { + dWmLib::MakeRouteName(routeName, neighborName, ownName); + label = csvData.GetActionLabel(routeName); + } + + mPoints[i].mActionLabel[dir] = label; + } + } + } +} + +void dWmConnect_c::SetCourseNo(int index) { + mPoints[index].mCourseNo = dWmLib::GetCourseNoFromPointName(mPoints[index].name); +} + +int dWmConnect_c::GetCourseNoFromName(const char *name) { + dPnt_c *p = mPoints; + for (int i = 0; i < MAX_POINT_COUNT; i++, p++) { + if (strcmp(p->name, name) == 0) { + return mPoints[i].mCourseNo; + } + } + + return -1; +} + +dWmConnect_c::dPnt_c *dWmConnect_c::GetConnect(const char *name, int dir) { + dPnt_c *p = mPoints; + for (int i = 0; i < MAX_POINT_COUNT; i++, p++) { + if (strcmp(p->name, name) == 0) { + return mPoints[i].GetLink(dir); + } + } + + return nullptr; +} + +dWmConnect_c::dPnt_c *dWmConnect_c::GetPointFromIndex(int index) { + for (int i = 0; i < MAX_POINT_COUNT; i++) { + if (mPoints[i].mPointIndex == index) { + return &mPoints[i]; + } + } + + return nullptr; +} + +int dWmConnect_c::GetDir(int indexA, int indexB) { + dPnt_c *pointA = GetPointFromIndex(indexA); + dPnt_c *pointB = GetPointFromIndex(indexB); + + for (int dir = 0; dir < 6; dir++) { + dPnt_c *link = pointA->GetLink(dir); + if (link != nullptr && link == pointB) { + return dir; + } + } + + return 6; +} + +dWmConnect_c::dPnt_c *dWmConnect_c::dPnt_c::GetLink(int dir) { + return mLink[dir]; +} diff --git a/source/dol/bases/d_wm_enemy.cpp b/source/dol/bases/d_wm_enemy.cpp index d7d70d484..ad7197ebc 100644 --- a/source/dol/bases/d_wm_enemy.cpp +++ b/source/dol/bases/d_wm_enemy.cpp @@ -67,7 +67,7 @@ void dWmEnemy_c::initializeBase(const char **names, int count, bool cyclic) { } mPath.init(names, count, connect, cyclic, enData.mWalkDirection); mPath.SetStartPoint(getStartPoint()); - dWmConnect_c::Point_s *point = connect->GetPointFromIndex(mPath.mpCurrentPoint->mPointIndex); + dWmConnect_c::dPnt_c *point = connect->GetPointFromIndex(mPath.mpCurrentPoint->mPointIndex); mPos = point->pos + getPointOffset(mPath.mpCurrentPoint->mIndex); bool enWalk = false; if (dWmEnemy::isEnemyWalk() && dWmLib::getEnemyRevivalCount(dScWMap_c::m_WorldNo, ACTOR_PARAM(enemyNo)) == 0) { @@ -300,7 +300,7 @@ bool dWmEnemy_c::doWalk() { mVec3_c dWmEnemy_c::getNextPointInfo() { daWmMap_c *wmMap = daWmMap_c::m_instance; dWmConnect_c *connect = &wmMap->mWmConnect[wmMap->currIdx]; - dWmConnect_c::Point_s *point = connect->GetPointFromIndex(mPath.GetNextPointIdx()); + dWmConnect_c::dPnt_c *point = connect->GetPointFromIndex(mPath.GetNextPointIdx()); int idx = mPath.GetNextPointInfo(false)->mIndex; return point->pos + getPointOffset(idx); } @@ -308,7 +308,7 @@ mVec3_c dWmEnemy_c::getNextPointInfo() { mVec3_c dWmEnemy_c::getCurrentPointInfo() { daWmMap_c *wmMap = daWmMap_c::m_instance; dWmConnect_c *connect = &wmMap->mWmConnect[wmMap->currIdx]; - dWmConnect_c::Point_s *point = connect->GetPointFromIndex(mPath.mpCurrentPoint->mPointIndex); + dWmConnect_c::dPnt_c *point = connect->GetPointFromIndex(mPath.mpCurrentPoint->mPointIndex); return point->pos + getPointOffset(mPath.mpCurrentPoint->mIndex); } diff --git a/syms.txt b/syms.txt index 388660173..7514e1b05 100644 --- a/syms.txt +++ b/syms.txt @@ -321,10 +321,11 @@ __ct__14TagProcessor_cFv=0x800E5510 __dt__14TagProcessor_cFv=0x800E5590 preProcess__14TagProcessor_cFPCwPwUlPilP16__va_list_structP8MsgRes_c=0x800E72D0 create__6mVideoFv=0x800E8BC0 -GetPointFromIndex__12dWmConnect_cFi=0x800F3400 GetStartPointNameFromRouteName__6dWmLibFPCcPc=0x800F9380 GetEndPointNameFromRouteName__6dWmLibFPCcPc=0x800F93D0 +MakeRouteName__6dWmLibFPcPCcPCc=0x800F9420 GetCourseNoFromPointName__6dWmLibFPCc=0x800F9640 +GetPointTypeFromPointName__6dWmLibFPCc=0x800F9A80 GetCourseTypeFromCourseNo__6dWmLibFi=0x800F9950 GetOpenStatus__6dWmLibFii=0x800FA440 GetClearStatus__6dWmLibFii=0x800FA9D0