From 2ee3dae5d52cf7d59158eb2eb4a1ff0196534fb9 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Thu, 26 Feb 2026 18:44:40 +0100 Subject: [PATCH] Make stage loading work somewhat BE & 64-bit support Most nodes haven't been fixed yet but this at least avoids an immediate crash. --- include/d/d_stage.h | 58 +++++++++++++++++++++++++++++++++++---------- src/d/d_stage.cpp | 24 +++++++++++++++++++ 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/include/d/d_stage.h b/include/d/d_stage.h index 9d9c1b3633..2575505291 100644 --- a/include/d/d_stage.h +++ b/include/d/d_stage.h @@ -7,6 +7,32 @@ #include "f_op/f_op_actor_mng.h" #include "global.h" +#if TARGET_PC +struct StageOffsetPtr { + // Top bit is used to store "already relocated" flag as a guard thing. + BE value; + + void setBase(void* base); + + template + explicit operator T*() const { + s32 swapped = value; + if (swapped == 0) { + // This shouldn't be able to happen but the original offsetting code has the safeguard. + return nullptr; + } + + // Because we use the top (31st) bit as an "already relocated" flag, + // we need to make sure to check the 30th bit to see if we're actually negative. + // And cut off the 31st bit if we're supposed to be positive. + // Effective range this gives us is still like a gigabyte in both directions, + // so we'll be fine on that front. + s32 realOffset = (swapped & 0x4000'0000) ? swapped : (swapped & 0x7FFF'FFFF); + return (T*)POINTER_ADD(this, realOffset); + } +}; +#endif + enum StageType { /* 0x0 */ ST_FIELD, /* 0x1 */ ST_DUNGEON, @@ -18,14 +44,20 @@ enum StageType { // made up name struct dStage_nodeHeader { + // m_tag is actually a 4-char string (like "STAG"), + // so keep it as big endian without conversion so matching it keeps working. /* 0x0 */ u32 m_tag; - /* 0x4 */ int m_entryNum; + /* 0x4 */ BE(int) m_entryNum; +#if TARGET_PC + /* 0x8 */ StageOffsetPtr m_offset; +#else /* 0x8 */ u32 m_offset; +#endif }; // made up name struct dStage_fileHeader { - /* 0x0 */ int m_chunkCount; + /* 0x0 */ BE(int) m_chunkCount; /* 0x4 */ dStage_nodeHeader m_nodes[1]; // Variable length }; @@ -61,21 +93,21 @@ struct stage_tresure_class { // STAG struct stage_stag_info_class { - /* 0x00 */ f32 mNear; - /* 0x04 */ f32 mFar; + /* 0x00 */ BE(f32) mNear; + /* 0x04 */ BE(f32) mFar; /* 0x08 */ u8 mCameraType; /* 0x09 */ u8 field_0x09; - /* 0x0A */ u16 field_0x0a; - /* 0x0C */ u32 field_0x0c; - /* 0x10 */ u32 field_0x10; + /* 0x0A */ BE(u16) field_0x0a; + /* 0x0C */ BE(u32) field_0x0c; + /* 0x10 */ BE(u32) field_0x10; /* 0x14 */ u8 field_0x14[6]; // usually all 0xFF - /* 0x1A */ s16 mGapLevel; - /* 0x1C */ s16 mRangeUp; - /* 0x1E */ s16 mRangeDown; - /* 0x20 */ f32 field_0x20; - /* 0x24 */ f32 field_0x24; + /* 0x1A */ BE(s16) mGapLevel; + /* 0x1C */ BE(s16) mRangeUp; + /* 0x1E */ BE(s16) mRangeDown; + /* 0x20 */ BE(f32) field_0x20; + /* 0x24 */ BE(f32) field_0x24; /* 0x28 */ u8 mMsgGroup; - /* 0x2A */ u16 mStageTitleNo; + /* 0x2A */ BE(u16) mStageTitleNo; /* 0x2C */ u8 mParticleNo[16]; }; // Size: 0x3C diff --git a/src/d/d_stage.cpp b/src/d/d_stage.cpp index 22d3b156fb..494a858752 100644 --- a/src/d/d_stage.cpp +++ b/src/d/d_stage.cpp @@ -2282,10 +2282,14 @@ static void dStage_dt_c_offsetToPtr(void* i_data) { dStage_nodeHeader* p_tno = file->m_nodes; for (int i = 0; i < file->m_chunkCount; i++) { +#if TARGET_PC + p_tno->m_offset.setBase(i_data); +#else JUT_ASSERT(3381, p_tno->m_offset != 0); if (p_tno->m_offset != 0 && p_tno->m_offset < 0x80000000) { p_tno->m_offset += (uintptr_t)i_data; } +#endif p_tno++; } } @@ -2905,3 +2909,23 @@ void dStage_escapeRestart() { dComIfGp_setNextStage(dComIfGp_getStartStageName(), -2, dComIfGs_getTurnRestartRoomNo(), -1, 0.0f, 0, 0, 9, 0, 1, 0); } #endif + +#if TARGET_PC +void StageOffsetPtr::setBase(void* base) { + JUT_ASSERT(__LINE__, value != 0); + + if (value & 0x8000'0000) { + // Already relocated, don't touch it again! + return; + } + + ptrdiff_t diff = (u8*)this - (u8*)base; + ptrdiff_t newDiff = value - diff; + // Check that it's in range given that we use the 31st bit as a flag. + if (newDiff < -0x4000'0000 || newDiff > 0x7FFF'FFFF) { + OSPanic(__FILE__, __LINE__, "Not enough space in StageOffsetPtr!"); + } + + value = newDiff | 0x8000'0000; +} +#endif