Make stage loading work somewhat

BE & 64-bit support

Most nodes haven't been fixed yet but this at least avoids an immediate crash.
This commit is contained in:
PJB3005
2026-02-26 18:44:40 +01:00
parent c582d01cf7
commit 2ee3dae5d5
2 changed files with 69 additions and 13 deletions
+45 -13
View File
@@ -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<s32> value;
void setBase(void* base);
template<typename T>
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
+24
View File
@@ -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