Start CWorld

This commit is contained in:
Luke Street 2024-10-16 23:02:14 -06:00
parent 0036cf3c07
commit dcb0f4465b
16 changed files with 827 additions and 39 deletions

View File

@ -1356,7 +1356,7 @@ LoadRelays__FR12CInputStreamRQ24rstl44vector<Q26SRelay,Q24rstl17rmemory_allocato
__dt__11CDummyWorldFv = .text:0x800572D0; // type:function size:0xDC scope:global
fn_800573AC = .text:0x800573AC; // type:function size:0xD0
__ct__11CDummyWorldFUi = .text:0x8005747C; // type:function size:0x138 scope:global
IGetGameAreas__6CWorldCFv = .text:0x800575B4; // type:function size:0x8 scope:global
IGetAreaCount__6CWorldCFv = .text:0x800575B4; // type:function size:0x8 scope:global
IGetDefaultAudioTrack__6CWorldCFv = .text:0x800575BC; // type:function size:0x24 scope:global
ICheckWorldComplete__6CWorldFv = .text:0x800575E0; // type:function size:0x34 scope:global
IGetCurrentAreaId__6CWorldCFv = .text:0x80057614; // type:function size:0xC scope:global

View File

@ -1356,7 +1356,7 @@ LoadRelays__FR12CInputStreamRQ24rstl44vector<Q26SRelay,Q24rstl17rmemory_allocato
__dt__11CDummyWorldFv = .text:0x8005734C; // type:function size:0xDC scope:global
fn_800573AC = .text:0x80057428; // type:function size:0xD0 scope:global
__ct__11CDummyWorldFUi = .text:0x800574F8; // type:function size:0x138 scope:global
IGetGameAreas__6CWorldCFv = .text:0x80057630; // type:function size:0x8 scope:global
IGetAreaCount__6CWorldCFv = .text:0x80057630; // type:function size:0x8 scope:global
IGetDefaultAudioTrack__6CWorldCFv = .text:0x80057638; // type:function size:0x24 scope:global
ICheckWorldComplete__6CWorldFv = .text:0x8005765C; // type:function size:0x34 scope:global
IGetCurrentAreaId__6CWorldCFv = .text:0x80057690; // type:function size:0xC scope:global

View File

@ -12,6 +12,7 @@
#include "Kyoto/Math/CVector3f.hpp"
class CAudioGroupSet;
class CSimplePool;
enum ETRKSampleRate {
kTSR_Zero,
@ -70,6 +71,12 @@ public:
static void SysSetVolume(uchar, uint, uchar);
static void SysSetSfxVolume(uchar, ushort, uchar, uchar);
static bool SysLoadGroupSet(CSimplePool*, uint);
static const rstl::string& SysGetGroupSetName(uint);
static bool SysPushGroupIntoARAM(const rstl::string& name, uchar);
static void SysPopGroupFromARAM();
static void SysUnloadGroupSet(const rstl::string& name);
static void SysUnloadSampleData(const rstl::string& name);
static void SetDefaultVolumeScale(short);
static void SetVolumeScale(short);
@ -100,7 +107,6 @@ public:
static void S3dAddEmitter(SND_FXID fxid, const CVector3f& pos, const CVector3f& dir,
const bool b1, const bool b2, short, int);
static u32 SeqPlayEx(unsigned short, unsigned short, void*, SND_PLAYPARA*, unsigned char);
static void SeqStop(u32);
static void SeqVolume(u8, u16, u32, u8);

View File

@ -28,6 +28,7 @@ public:
short x8_songId;
bool xa_available;
};
class CMidiData {
public:
CMidiData(CInputStream& in);
@ -36,6 +37,7 @@ public:
const short GetGroupId() const { return x2_groupId; }
const int GetSetupId() const { return x4_setupId; }
uchar* GetData() const { return x8_data.get(); }
private:
short x0_songId;
short x2_groupId;

View File

@ -9,6 +9,7 @@ class CStreamAudioManager {
public:
static void Update(float dt);
static void StopAll();
static void StopOneShot();
static void SetMusicVolume(uint);
static void SetSfxVolume(uint);

View File

@ -3,25 +3,71 @@
#include "types.h"
#include "MetroidPrime/CStateManager.hpp"
#include "MetroidPrime/TGameTypes.hpp"
#include "Kyoto/Graphics/CColor.hpp"
#include "Kyoto/Graphics/CGraphics.hpp"
#include "Kyoto/IObjectStore.hpp"
#include "Kyoto/Math/CAABox.hpp"
#include "Kyoto/Math/CTransform4f.hpp"
#include "Kyoto/Math/CVector2f.hpp"
#include "WorldFormat/CMetroidModelInstance.hpp"
#include "WorldFormat/CWorldLight.hpp"
#include "rstl/auto_ptr.hpp"
#include "rstl/list.hpp"
#include "rstl/optional_object.hpp"
#include "rstl/pair.hpp"
#include "rstl/rc_ptr.hpp"
#include "rstl/reserved_vector.hpp"
#include "rstl/single_ptr.hpp"
#include "rstl/vector.hpp"
class CAreaOctTree;
class CDvdRequest;
class CPVSAreaSet;
class CScriptAreaAttributes;
class CToken;
class IGameArea {
public:
class Dock {
public:
struct SDockReference {
uint x0_area;
s16 x4_dock;
bool x6_loadOther;
SDockReference();
};
private:
int x0_referenceCount;
rstl::vector< SDockReference > x4_dockReferences;
rstl::reserved_vector< CVector3f, 4 > x14_planeVertices;
bool x48_isReferenced;
public:
const rstl::reserved_vector< CVector3f, 4 >& GetPlaneVertices() const {
return x14_planeVertices;
}
int GetReferenceCount() const { return x0_referenceCount; }
const rstl::vector< SDockReference >& GetDockRefs() const { return x4_dockReferences; }
Dock(CInputStream& in, const CTransform4f& xf);
TAreaId GetConnectedAreaId(int other) const;
s16 GetOtherDockNumber(int other) const;
bool GetShouldLoadOther(int other) const;
void SetShouldLoadOther(int other, bool should);
bool ShouldLoadOtherArea(int other) const;
CVector3f GetPoint(int idx) const;
bool IsReferenced() const { return x48_isReferenced; }
void SetReferenceCount(int v) {
x0_referenceCount = v;
x48_isReferenced = true;
}
};
virtual ~IGameArea();
virtual const CTransform4f& IGetTM() const = 0;
virtual CAssetId IGetStringTableAssetId() const = 0;
@ -33,21 +79,36 @@ public:
virtual rstl::pair< rstl::auto_ptr< uchar >, int > IGetScriptingMemoryAlways() const = 0;
};
enum EChain {
kC_Invalid = -1,
kC_ToDeallocate,
kC_Deallocated,
kC_Loading,
kC_Alive,
kC_AliveJudgement,
struct CAreaRenderOctTree {
struct Node {
ushort x0_bitmapIdx;
ushort x2_flags;
ushort x4_children[1];
uint GetChildCount() const;
CAABox GetNodeBounds(const CAABox& curAABB, int idx) const;
void RecursiveBuildOverlaps(u32* out, const CAreaRenderOctTree& parent, const CAABox& curAABB,
const CAABox& testAABB) const;
};
class Dock;
class CToken;
class CDvdRequest;
class CScriptAreaAttributes;
class CWorldLight;
class CPVSAreaSet;
const u8* x0_buf;
int x4_; // TODO
uint x8_bitmapCount;
uint xc_meshCount;
uint x10_nodeCount;
uint x14_bitmapWordCount;
CAABox x18_aabb;
const u32* x30_bitmaps;
const u32* x34_indirectionTable;
const u8* x38_entries;
explicit CAreaRenderOctTree(const u8* buf);
void FindOverlappingModels(rstl::vector< u32 >& out, const CAABox& testAABB) const;
void FindOverlappingModels(u32* out, const CAABox& testAABB) const;
};
CHECK_SIZEOF(CAreaRenderOctTree, 0x3c);
class CGameArea : public IGameArea {
public:
@ -96,7 +157,15 @@ public:
enum EOcclusionState { kOS_Occluded, kOS_Visible };
struct CPostConstructed {
uchar x0_pad[0xa0];
rstl::optional_object< CAreaOctTree* > x0_collision;
int x8_; // TODO
rstl::optional_object< CAreaRenderOctTree > xc_octTree;
rstl::vector< CMetroidModelInstance > x4c_insts;
rstl::single_ptr< int > x5c_; // TODO
rstl::vector< CWorldLight > x60_lightsA;
rstl::vector< CLight > x70_gfxLightsA;
rstl::vector< CWorldLight > x80_lightsB;
rstl::vector< CLight > x90_gfxLightsB;
CPVSAreaSet* xa0_pvs;
uchar xa4_pad[0x1020];
rstl::single_ptr< CAreaFog > x10c4_areaFog;
@ -136,8 +205,16 @@ public:
bool TryTakingOutOfARAM();
bool StartStreamingMainArea();
bool Invalidate(CStateManager* mgr);
void Validate(CStateManager& mgr);
void SetOcclusionState(EOcclusionState state);
void RemoveStaticGeometry();
void StartStreamIn(CStateManager& mgr);
void SetChain(CGameArea* next, int chain);
CAssetId GetAreaAssetId() const { return x84_mrea; }
const Dock& GetDock(int idx) const { return xcc_docks[idx]; }
int GetDockCount() const { return xcc_docks.size(); }
const CAreaFog* GetAreaFog() const { return x12c_postConstructed->x10c4_areaFog.get(); }
CAreaFog* AreaFog() { return x12c_postConstructed->x10c4_areaFog.get(); }
EOcclusionState GetOcclusionState() const { return x12c_postConstructed->x10dc_occlusionState; }
@ -147,6 +224,9 @@ public:
bool IsPostConstructed() const { return xf0_24_postConstructed; } // name?
CPostConstructed* GetPostConstructed() { return x12c_postConstructed.get(); } // name?
const CPostConstructed* GetPostConstructed() const { return x12c_postConstructed.get(); } // name?
CGameArea* GetNext() { return x130_next; } // name?
CGameArea* GetPrev() { return x134_prev; } // name?
int GetCurChain() const { return x138_curChain; } // name?
private:
void AllocNewAreaData(int, int);
@ -187,10 +267,36 @@ private:
int x124_secCount;
int x128_mreaDataOffset;
rstl::single_ptr< CPostConstructed > x12c_postConstructed;
CGameArea* x130_next;
CGameArea* x134_prev;
int x138_curChain;
};
NESTED_CHECK_SIZEOF(CGameArea, CPostConstructed, 0x1140)
CHECK_SIZEOF(CGameArea, 0x13c)
// CHECK_SIZEOF(CGamearea::CAreaFog, 0x38)
class CDummyGameArea final : public IGameArea {
friend class CDummyWorld;
public:
CDummyGameArea(CInputStream& in, int idx, int mlvlVersion);
rstl::pair< rstl::auto_ptr< uchar >, int > IGetScriptingMemoryAlways() const override;
int IGetAreaSaveId() const override;
CAssetId IGetAreaAssetId() const override;
bool IIsActive() const override;
TAreaId IGetAttachedAreaId(int) const override;
uint IGetNumAttachedAreas() const override;
CAssetId IGetStringTableAssetId() const override;
const CTransform4f& IGetTM() const override;
private:
int x4_mlvlVersion;
CAssetId x8_nameSTRG;
CAssetId xc_mrea;
int x10_areaId;
CTransform4f x14_transform;
rstl::vector< u16 > x44_attachedAreaIndices;
rstl::vector< Dock > x54_docks;
};
CHECK_SIZEOF(CDummyGameArea, 0x64)
#endif // _CGAMEAREA

View File

@ -1,6 +1,7 @@
#ifndef _CINGAMETWEAKMANAGER
#define _CINGAMETWEAKMANAGER
#include "Kyoto/SObjectTag.hpp"
#include "types.h"
#include "rstl/string.hpp"
@ -61,6 +62,7 @@ public:
bool HasTweakValue(const rstl::string& name) const;
const CTweakValue* GetTweakValue(const rstl::string& name) const;
bool ReadFromMemoryCard(const rstl::string&);
rstl::vector< CAssetId > GetSongAssetsInWorld(CAssetId world) const;
static rstl::string sub_8021cb38(CAssetId, const rstl::string&);

View File

@ -0,0 +1,171 @@
#ifndef _CMAPWORLD
#define _CMAPWORLD
#include "Kyoto/Graphics/CColor.hpp"
#include "MetroidPrime/CMapArea.hpp"
class CStateManager;
class CMapWorld {
public:
/* skDrawProfileItemNames; */
enum EMapAreaList { kMAL_Loaded, kMAL_Loading, kMAL_Unloaded };
class CMapAreaBFSInfo {
int x0_areaIdx;
int x4_depth;
float x8_surfDrawDepth;
float xc_outlineDrawDepth;
public:
CMapAreaBFSInfo(int areaIdx, int depth, float a, float b)
: x0_areaIdx(areaIdx), x4_depth(depth), x8_surfDrawDepth(a), xc_outlineDrawDepth(b) {}
int GetAreaIndex() const { return x0_areaIdx; }
int GetDepth() const { return x4_depth; }
float GetOutlineDrawDepth() const { return x8_surfDrawDepth; }
float GetSurfaceDrawDepth() const { return xc_outlineDrawDepth; }
};
class CMapObjectSortInfo {
float x0_zDist;
int x4_areaIdx;
int x8_typeAndIdx;
CColor xc_surfColor;
CColor x10_outlineColor;
public:
enum EObjectCode {
kOC_Invalid = -1,
kOC_Object = 1 << 16,
kOC_DoorSurface = 2 << 16,
kOC_Door = 3 << 16,
kOC_Surface = 4 << 16
};
CMapObjectSortInfo(float zDist, int areaIdx, EObjectCode type, int idx, const CColor& surfColor,
const CColor& outlineColor)
: x0_zDist(zDist)
, x4_areaIdx(areaIdx)
, x8_typeAndIdx(int(type) | idx)
, xc_surfColor(surfColor)
, x10_outlineColor(outlineColor) {}
const CColor& GetOutlineColor() const { return x10_outlineColor; }
const CColor& GetSurfaceColor() const { return xc_surfColor; }
uint GetLocalObjectIndex() const { return x8_typeAndIdx & 0xffff; }
EObjectCode GetObjectCode() const { return EObjectCode(x8_typeAndIdx & 0xffff0000); }
uint GetAreaIndex() const { return x4_areaIdx; }
float GetZDistance() const { return x0_zDist; }
};
class CMapAreaData {
int x0_areaIdx;
TCachedToken< CMapArea > x4_area;
EMapAreaList x10_list;
CMapAreaData* x14_next;
public:
CMapAreaData(CAssetId areaRes, EMapAreaList list, CMapAreaData* next);
void Lock() { x4_area.Lock(); }
void Unlock() { x4_area.Unlock(); }
bool IsLoaded() const { return x4_area.IsLoaded(); }
CMapArea* MapArea() { return x4_area.GetT(); }
const CMapArea* GetMapArea() const { return x4_area.GetObject(); }
CMapAreaData* GetNextMapAreaData() { return x14_next; }
const CMapAreaData* GetNextMapAreaData() const { return x14_next; }
EMapAreaList GetContainingList() const { return x10_list; }
void SetContainingList(EMapAreaList list) { x10_list = list; }
void SetNextMapArea(CMapAreaData* next) { x14_next = next; }
};
class CMapWorldDrawParms {
float x0_alphaSurfVisited;
float x4_alphaOlVisited;
float x8_alphaSurfUnvisited;
float xc_alphaOlUnvisited;
float x10_alpha;
float x14_outlineWidthScale;
const CStateManager& x18_mgr;
const CTransform4f& x1c_modelXf;
const CTransform4f& x20_viewXf;
const IWorld& x24_wld;
const CMapWorldInfo& x28_mwInfo;
float x2c_playerFlashIntensity;
float x30_hintFlashIntensity;
float x34_objectScale;
bool x38_sortDoorSurfs;
public:
CMapWorldDrawParms(float alphaSurfVisited, float alphaOlVisited, float alphaSurfUnvisited,
float alphaOlUnvisited, float alpha, float outlineWidthScale,
const CStateManager& mgr, const CTransform4f& modelXf,
const CTransform4f& viewXf, const IWorld& wld, const CMapWorldInfo& mwInfo,
float playerFlash, float hintFlash, float objectScale, bool sortDoorSurfs)
: x0_alphaSurfVisited(alphaSurfVisited)
, x4_alphaOlVisited(alphaOlVisited)
, x8_alphaSurfUnvisited(alphaSurfUnvisited)
, xc_alphaOlUnvisited(alphaOlUnvisited)
, x10_alpha(alpha)
, x14_outlineWidthScale(outlineWidthScale)
, x18_mgr(mgr)
, x1c_modelXf(modelXf)
, x20_viewXf(viewXf)
, x24_wld(wld)
, x28_mwInfo(mwInfo)
, x2c_playerFlashIntensity(playerFlash)
, x30_hintFlashIntensity(hintFlash)
, x34_objectScale(objectScale)
, x38_sortDoorSurfs(sortDoorSurfs) {}
const IWorld& GetWorld() const { return x24_wld; }
float GetOutlineWidthScale() const { return x14_outlineWidthScale; }
const CTransform4f& GetPlaneProjectionTransform() const { return x1c_modelXf; }
float GetHintAreaFlashIntensity() const { return x30_hintFlashIntensity; }
float GetPlayerAreaFlashIntensity() const { return x2c_playerFlashIntensity; }
const CTransform4f& GetCameraTransform() const { return x20_viewXf; }
float GetAlphaOutlineUnvisited() const { return xc_alphaOlUnvisited; }
float GetAlphaSurfaceUnvisited() const { return x8_alphaSurfUnvisited; }
float GetAlphaOutlineVisited() const { return x4_alphaOlVisited; }
float GetAlphaSurfaceVisited() const { return x0_alphaSurfVisited; }
float GetAlpha() const { return x10_alpha; }
const CMapWorldInfo& GetMapWorldInfo() const { return x28_mwInfo; }
const CStateManager& GetStateManager() const { return x18_mgr; }
bool GetIsSortDoorSurfaces() const { return x38_sortDoorSurfs; }
float GetObjectScale() const { return x34_objectScale; }
};
private:
rstl::vector< CMapAreaData > x0_areas;
rstl::reserved_vector< CMapAreaData*, 3 > x10_listHeads;
rstl::vector< bool > x20_traversed;
CVector3f x30_worldSpherePoint;
float x3c_worldSphereRadius;
float x40_worldSphereHalfDepth;
public:
explicit CMapWorld(CInputStream& in);
uint GetNumAreas() const { return x0_areas.size(); }
CMapArea* GetMapArea(int aid) { return x0_areas[aid].MapArea(); }
const CMapArea* GetMapArea(int aid) const { return x0_areas[aid].GetMapArea(); }
bool IsMapAreaInBFSInfoVector(const CMapAreaData* area,
const rstl::vector< CMapAreaBFSInfo >& vec) const;
void SetWhichMapAreasLoaded(const IWorld& wld, int start, int count);
bool IsMapAreasStreaming();
void MoveMapAreaToList(CMapAreaData* data, EMapAreaList list);
int GetCurrentMapAreaDepth(const IWorld& wld, TAreaId aid);
rstl::vector< int > GetVisibleAreas(const IWorld& wld, const CMapWorldInfo& mwInfo) const;
void Draw(const CMapWorldDrawParms& parms, int curArea, int otherArea, float depth1, float depth2,
bool inMapScreen);
void DoBFS(const IWorld& wld, int startArea, int areaCount, float surfDepth, float outlineDepth,
bool checkLoad, rstl::vector< CMapAreaBFSInfo >& bfsInfos);
bool IsMapAreaValid(const IWorld& wld, int areaIdx, bool checkLoad) const;
void DrawAreas(const CMapWorldDrawParms& parms, int selArea,
const rstl::vector< CMapAreaBFSInfo >& bfsInfos, bool inMapScreen);
void RecalculateWorldSphere(const CMapWorldInfo& mwInfo, const IWorld& wld);
CVector3f ConstrainToWorldVolume(const CVector3f& point, const CVector3f& lookVec) const;
void ClearTraversedFlags();
void SetWhichMapAreasLoaded(const IWorld& wld, int start, int count, bool load);
bool IsMapAreasStreaming() const;
};
NESTED_CHECK_SIZEOF(CMapWorld, CMapAreaData, 0x18)
CHECK_SIZEOF(CMapWorld, 0x44)
#endif // _CMAPWORLD

View File

@ -1,6 +1,7 @@
#ifndef _CWORLD
#define _CWORLD
#include "Kyoto/SObjectTag.hpp"
#include "types.h"
#include "MetroidPrime/CGameArea.hpp"
@ -10,16 +11,23 @@
#include "Kyoto/IObjectStore.hpp"
#include "Kyoto/TToken.hpp"
#include "rstl/string.hpp"
#include "rstl/reserved_vector.hpp"
#include "rstl/string.hpp"
#include "rstl/vector.hpp"
class CAudioGroupSet;
class CDvdRequest;
class CGameArea;
class CMapWorld;
class CModel;
class CRelay;
class CStateManager;
class IGameArea;
class CResFactory;
class IWorld {
public:
virtual ~IWorld();
virtual ~IWorld() {}
virtual CAssetId IGetWorldAssetId() const = 0;
virtual CAssetId IGetStringTableAssetId() const = 0;
virtual CAssetId IGetSaveWorldAssetId() const = 0;
@ -33,19 +41,16 @@ public:
virtual int IGetAreaCount() const = 0;
};
class CGameArea;
class CRelay;
class CSoundGroupData;
class CDvdRequest;
class IFactory;
class CRelay {
class CRelay /* name? */ {
public:
explicit CRelay(CInputStream& in);
const TEditorId& GetRelayId() const { return x0_relay; }
const TEditorId& GetTargetId() const { return x4_target; }
ushort GetMessage() const { return x8_msg; }
bool GetActive() const { return xa_active; }
static rstl::vector< CRelay > ReadMemoryRelays(CInputStream& in); // name?
private:
TEditorId x0_relay;
TEditorId x4_target;
@ -61,8 +66,35 @@ enum EEnvFxType {
kEFX_UnderwaterFlake,
};
class CWorld : public IWorld {
class CWorld final : public IWorld {
public:
struct CSoundGroupData {
int x0_groupId;
CAssetId x4_agscId;
bool x8_24_loadedIntoAram : 1;
bool x8_25_loaded : 1;
rstl::string xc_name;
TCachedToken< CAudioGroupSet > x1c_groupData;
public:
CSoundGroupData(int grpId, CAssetId agsc);
};
enum EAreaTravelType {
kATT_Zero,
kATT_One,
};
enum EChain {
kC_Invalid = -1,
kC_ToDeallocate,
kC_Deallocated,
kC_Loading,
kC_Alive,
kC_AliveJudgement,
};
CWorld(IObjectStore& objStore, CResFactory& resFactory, CAssetId mlvlId);
~CWorld();
CAssetId IGetWorldAssetId() const override;
CAssetId IGetStringTableAssetId() const override;
@ -75,9 +107,18 @@ public:
bool ICheckWorldComplete() override;
rstl::string IGetDefaultAudioTrack() const override;
int IGetAreaCount() const override;
bool CheckWorldComplete(CStateManager* mgr, TAreaId aid, CAssetId mreaId);
void SetLoadPauseState(bool);
void TouchSky() const;
void StopSounds();
void UnloadSoundGroups();
bool ScheduleAreaToLoad(CGameArea* area, CStateManager& mgr);
void MoveToChain(CGameArea* area, EChain chain);
void TravelToArea(TAreaId aid, CStateManager& mgr, EAreaTravelType type);
CMapWorld* GetMapWorld() const;
void LoadSoundGroups();
void LoadSoundGroup(uchar groupId, CAssetId agscId, CSoundGroupData& data);
const CGameArea& GetAreaAlways(TAreaId id) const { return *x18_areas[id.Value()]; }
CGameArea* Area(TAreaId id) { return x18_areas[id.Value()].get(); }
@ -114,10 +155,10 @@ private:
CAssetId x10_savwId;
rstl::vector< rstl::auto_ptr< CGameArea > > x18_areas;
CAssetId x24_mapwId;
CMapWorld* x28_mapWorld;
rstl::single_ptr< TCachedToken< CMapWorld > > x28_mapWorld;
rstl::vector< CRelay > x2c_relays;
rstl::rc_ptr< CDvdRequest > x3c_loadToken;
rstl::single_ptr< uchar > x40_loadBuf;
rstl::single_ptr< CDvdRequest > x3c_loadToken;
rstl::single_ptr< char > x40_loadBuf;
uint x44_bufSz;
uint x48_chainCount;
CGameArea* x4c_chainHeads[5];
@ -139,4 +180,45 @@ private:
};
CHECK_SIZEOF(CWorld, 0xf4)
struct SWorldLayers /* name? */ {
static SWorldLayers ReadWorldLayers(CInputStream& in, int version, CAssetId mlvlId);
};
class CDummyWorld : public IWorld {
enum Phase {
kP_Loading,
kP_LoadingMap,
kP_LoadingMapAreas,
kP_Done,
};
bool x4_loadMap;
Phase x8_phase;
CAssetId xc_mlvlId;
CAssetId x10_strgId;
CAssetId x14_savwId;
rstl::vector< rstl::auto_ptr< CDummyGameArea > > x18_areas;
CAssetId x28_mapWorldId;
rstl::single_ptr< TCachedToken< CMapWorld > > x2c_mapWorld;
rstl::single_ptr< CDvdRequest > x30_loadToken;
rstl::single_ptr< char > x34_loadBuf;
uint x38_bufSz;
TAreaId x3c_curAreaId;
public:
CDummyWorld(CAssetId mlvlId, bool loadMap);
~CDummyWorld() override;
CAssetId IGetWorldAssetId() const override;
CAssetId IGetStringTableAssetId() const override;
CAssetId IGetSaveWorldAssetId() const override;
const CMapWorld* IGetMapWorld() const override;
CMapWorld* IMapWorld() override;
const IGameArea* IGetAreaAlways(TAreaId id) const override;
TAreaId IGetCurrentAreaId() const override;
TAreaId IGetAreaId(CAssetId id) const override;
bool ICheckWorldComplete() override;
rstl::string IGetDefaultAudioTrack() const override;
int IGetAreaCount() const override;
};
#endif // _CWORLD

View File

@ -75,13 +75,17 @@ typedef int BOOL;
#if defined(__cplusplus) && __cplusplus < 201103L
#if defined(__clang__)
// Allow override in < C++11 mode with clangd
// Allow override/final in < C++11 mode with clangd
#pragma clang diagnostic ignored "-Wc++11-extensions"
#else
// Define override as nothing
#ifndef override
#define override
#endif
// Define final as nothing
#ifndef final
#define final
#endif
#endif // defined(__clang__)
#endif // defined(__cplusplus) && __cplusplus < 201103L

View File

@ -27,6 +27,7 @@ typedef unsigned long size_t;
#define CHECK_OFFSETOF(cls, member, offset) \
extern int cls##_check_offset##[_n_is_equal< offsetof(cls, member), offset >::value];
#elif defined(__clang__) && defined(__powerpc__) // Enable for clangd
#pragma clang diagnostic ignored "-Wc11-extensions" // Allow _Static_assert
#pragma clang diagnostic ignored "-Wc++17-extensions" // Allow _Static_assert without message
#define CHECK_SIZEOF(cls, size) _Static_assert(sizeof(cls) == size);
#define NESTED_CHECK_SIZEOF(parent, cls, size) _Static_assert(sizeof(parent::cls) == size);

View File

@ -404,7 +404,7 @@ void CStateManager::DrawWorld() const {
int areaCount = 0;
const CGameArea* areaArr[10];
CGameArea::CConstChainIterator it = x850_world->GetChainHead(kC_Alive);
CGameArea::CConstChainIterator it = x850_world->GetChainHead(CWorld::kC_Alive);
CGameArea::CConstChainIterator end = x850_world->GetAliveAreasEnd();
for (; it != end; ++it) {
if (areaCount == 10) {

408
src/MetroidPrime/CWorld.cpp Normal file
View File

@ -0,0 +1,408 @@
#include "MetroidPrime/CWorld.hpp"
#include "Kyoto/Alloc/IAllocator.hpp"
#include "Kyoto/Audio/CAudioSys.hpp"
#include "Kyoto/Audio/CMidiManager.hpp"
#include "Kyoto/Audio/CStreamAudioManager.hpp"
#include "Kyoto/CDvdRequest.hpp" // IWYU pragma: keep
#include "Kyoto/CResFactory.hpp"
#include "Kyoto/CSimplePool.hpp"
#include "Kyoto/SObjectTag.hpp"
#include "Kyoto/Streams/CMemoryInStream.hpp"
#include "MetroidPrime/CGameArea.hpp"
#include "MetroidPrime/CInGameTweakManager.hpp"
#include "MetroidPrime/CMain.hpp"
#include "MetroidPrime/CMapWorld.hpp"
#include "MetroidPrime/Player/CGameState.hpp"
#include "MetroidPrime/Player/CWorldTransManager.hpp"
#include "MetroidPrime/ScriptObjects/CScriptRoomAcoustics.hpp"
#include "MetroidPrime/TCastTo.hpp"
#include "MetroidPrime/TGameTypes.hpp"
#include "rstl/vector.hpp"
CWorld::CWorld(IObjectStore& objStore, CResFactory& resFactory, CAssetId mlvlId)
: x4_phase(kP_Loading)
, x8_mlvlId(mlvlId)
, xc_strgId(kInvalidAssetId)
, x10_savwId(kInvalidAssetId)
, x18_areas()
, x24_mapwId(kInvalidAssetId)
, x28_mapWorld()
, x2c_relays()
, x3c_loadToken()
, x40_loadBuf()
, x44_bufSz(0)
, x48_chainCount(0)
, x60_objectStore(&objStore)
, x64_resFactory(&resFactory)
, x68_curAreaId(kInvalidAreaId)
, x6c_loadedAudioGrpCount(0)
, x70_24_currentAreaNeedsAllocation(true)
, x70_25_loadPaused(false)
, x70_26_skyboxActive(false)
, x70_27_skyboxVisible(false)
, x74_soundGroupData()
, x84_defAudioTrack()
, x94_skyboxWorld()
, xa4_skyboxWorldLoaded()
, xb4_skyboxOverride()
, xc4_neededFx(kEFX_None)
, xc8_globalSfxHandles() {
SObjectTag mlvl('MLVL', mlvlId);
x44_bufSz = gpResourceFactory->ResourceSize(mlvl);
x40_loadBuf = static_cast< char* >(CMemory::Alloc(x44_bufSz, IAllocator::kHI_RoundUpLen));
x3c_loadToken = resFactory.GetResLoader().LoadResourceAsync(mlvl, x40_loadBuf.get());
}
CWorld::~CWorld() {
StopSounds();
CWorldTransManager* transManager = gpGameState->WorldTransitionManager().GetPtr();
if (transManager->GetTransType() != CWorldTransManager::kTT_Disabled &&
gpMain->GetRestartMode() == CMain::kRM_None) {
CStreamAudioManager::StopOneShot();
} else {
CStreamAudioManager::StopAll();
}
UnloadSoundGroups();
CScriptRoomAcoustics::DisableAuxCallbacks();
}
bool CWorld::ScheduleAreaToLoad(CGameArea* area, CStateManager& mgr) {
if (!area->IsPostConstructed()) {
MoveToChain(area, kC_Loading);
return true;
} else {
if (area->GetCurChain() != kC_Alive) {
if (area->GetCurChain() != kC_AliveJudgement) {
x70_24_currentAreaNeedsAllocation = true;
}
MoveToChain(area, kC_Alive);
}
return false;
}
}
// TOOD nonmatching
void CWorld::TravelToArea(TAreaId aid, CStateManager& mgr, EAreaTravelType type) {
if (aid.Value() < 0 || aid.Value() >= x18_areas.size())
return;
x70_24_currentAreaNeedsAllocation = false;
x68_curAreaId = aid;
CGameArea* toDeallocateAreas = x4c_chainHeads[0];
while (toDeallocateAreas) {
if (toDeallocateAreas->Invalidate(&mgr)) {
MoveToChain(toDeallocateAreas, kC_Deallocated);
break;
}
toDeallocateAreas = toDeallocateAreas->GetNext();
}
CGameArea* aliveAreas = x4c_chainHeads[3];
while (aliveAreas) {
CGameArea* aliveArea = aliveAreas;
aliveAreas = aliveAreas->GetNext();
MoveToChain(aliveArea, kC_AliveJudgement);
}
CGameArea* loadingAreas = x4c_chainHeads[2];
while (loadingAreas) {
CGameArea* loadingArea = loadingAreas;
loadingAreas = loadingAreas->GetNext();
MoveToChain(loadingArea, kC_ToDeallocate);
}
CGameArea* area = Area(aid);
if (area->GetCurChain() != kC_AliveJudgement)
x70_24_currentAreaNeedsAllocation = true;
area->Validate(mgr);
MoveToChain(area, kC_Alive);
area->SetOcclusionState(CGameArea::kOS_Visible);
CGameArea* otherLoadArea = nullptr;
if (type == kATT_Zero) {
bool otherLoading = false;
for (int i = 0; i < area->GetDockCount(); ++i) {
const CGameArea::Dock& dock = area->GetDock(i);
int dockRefCount = dock.GetDockRefs().size();
for (int i = 0; i < dockRefCount; ++i) {
if (!dock.ShouldLoadOtherArea(i))
continue;
TAreaId connArea = dock.GetConnectedAreaId(i);
CGameArea* cArea = Area(connArea);
if (!cArea->IsActive())
continue;
if (!otherLoading) {
otherLoading = ScheduleAreaToLoad(cArea, mgr);
if (!otherLoading)
continue;
otherLoadArea = cArea;
} else
ScheduleAreaToLoad(cArea, mgr);
}
}
}
CGameArea* judgementAreas = x4c_chainHeads[4];
while (judgementAreas) {
CGameArea* judgementArea = judgementAreas;
judgementAreas = judgementArea->GetNext();
MoveToChain(judgementArea, kC_ToDeallocate);
}
int toStreamCount = 0;
toDeallocateAreas = x4c_chainHeads[0];
while (toDeallocateAreas) {
toDeallocateAreas->RemoveStaticGeometry();
toDeallocateAreas = toDeallocateAreas->GetNext();
++toStreamCount;
}
if (!toStreamCount && otherLoadArea && !x70_25_loadPaused)
otherLoadArea->StartStreamIn(mgr);
GetMapWorld()->SetWhichMapAreasLoaded(*this, aid.Value(), 3);
}
// TOOD nonmatching
void CWorld::MoveToChain(CGameArea* area, EChain chain) {
if (area->GetCurChain() == chain) {
return;
}
if (area->GetCurChain() != kC_Invalid) {
if (x4c_chainHeads[area->GetCurChain()] == area) {
x4c_chainHeads[area->GetCurChain()] = area->GetNext();
}
}
area->SetChain(x4c_chainHeads[int(chain)], int(chain));
x4c_chainHeads[int(chain)] = area;
}
void CWorld::LoadSoundGroups() {
rstl::vector< CAssetId > songAssets = gpTweakManager->GetSongAssetsInWorld(IGetWorldAssetId());
if (songAssets.empty()) {
return;
}
x74_soundGroupData.reserve(songAssets.size());
for (rstl::vector< CAssetId >::iterator it = songAssets.begin(); it != songAssets.end(); ++it) {
TToken< CMidiManager::CMidiData > token = gpSimplePool->GetObj(SObjectTag('CSNG', *it));
x74_soundGroupData.push_back(
CSoundGroupData(token.GetT()->GetGroupId(), token.GetT()->GetSongId()));
}
for (rstl::vector< CSoundGroupData >::iterator it = x74_soundGroupData.begin();
it != x74_soundGroupData.end(); ++it) {
if (!it->x8_25_loaded) {
LoadSoundGroup(it->x0_groupId, it->x4_agscId, *it);
}
}
}
void CWorld::LoadSoundGroup(uchar groupId, CAssetId agscId, CSoundGroupData& data) {
data.x8_25_loaded = true;
if (!CAudioSys::SysLoadGroupSet(gpSimplePool, agscId)) {
rstl::string name = CAudioSys::SysGetGroupSetName(agscId);
if (CAudioSys::SysPushGroupIntoARAM(name, groupId)) {
data.x8_24_loadedIntoAram = true;
data.xc_name = name;
++x6c_loadedAudioGrpCount;
CAudioSys::SysUnloadSampleData(name);
} else {
CAudioSys::SysUnloadGroupSet(name);
}
}
}
void CWorld::UnloadSoundGroups() {
for (int i = 0; i < x6c_loadedAudioGrpCount; ++i) {
CAudioSys::SysPopGroupFromARAM();
}
for (rstl::vector< CSoundGroupData >::iterator it = x74_soundGroupData.begin();
it != x74_soundGroupData.end(); ++it) {
if (it->x8_24_loadedIntoAram) {
CAudioSys::SysUnloadGroupSet(it->xc_name);
}
}
}
CMapWorld* CWorld::GetMapWorld() const { return x28_mapWorld->GetObject(); }
CAssetId CWorld::IGetWorldAssetId() const { return GetWorldAssetId(); }
CAssetId CWorld::IGetStringTableAssetId() const { return xc_strgId; }
CAssetId CWorld::IGetSaveWorldAssetId() const { return x10_savwId; }
const CMapWorld* CWorld::IGetMapWorld() const { return GetMapWorld(); }
CMapWorld* CWorld::IMapWorld() { return GetMapWorld(); }
const IGameArea* CWorld::IGetAreaAlways(TAreaId id) const { return &GetAreaAlways(id); }
TAreaId CWorld::IGetCurrentAreaId() const { return x68_curAreaId; }
bool CWorld::ICheckWorldComplete() {
return CheckWorldComplete(nullptr, kInvalidAreaId, kInvalidAssetId);
}
rstl::string CWorld::IGetDefaultAudioTrack() const { return x84_defAudioTrack; }
int CWorld::IGetAreaCount() const { return x18_areas.size(); }
CDummyWorld::CDummyWorld(CAssetId mlvlId, bool loadMap)
: x4_loadMap(loadMap)
, x8_phase(kP_Loading)
, xc_mlvlId(mlvlId)
#if NONMATCHING
, x10_strgId(kInvalidAssetId)
#endif
, x14_savwId(kInvalidAssetId)
, x18_areas()
, x28_mapWorldId(kInvalidAssetId)
, x2c_mapWorld()
, x30_loadToken()
, x34_loadBuf()
, x38_bufSz(0)
, x3c_curAreaId(kInvalidAreaId) {
SObjectTag mlvl('MLVL', mlvlId);
x38_bufSz = gpResourceFactory->ResourceSize(mlvl);
x34_loadBuf = static_cast< char* >(CMemory::Alloc(x38_bufSz, IAllocator::kHI_RoundUpLen));
x30_loadToken = gpResourceFactory->GetResLoader().LoadResourceAsync(mlvl, x34_loadBuf.get());
}
class CMemoryRelays {
public:
CMemoryRelays(CInputStream& in /*, const int& unk*/);
private:
rstl::vector< CRelay > x0_relayList;
};
CMemoryRelays::CMemoryRelays(CInputStream& in /*, const int& unk*/) {
int count = in.Get< int >();
x0_relayList.reserve(count);
for (int i = 0; i < count; ++i) {
x0_relayList.push_back(CRelay(in));
}
}
CDummyWorld::~CDummyWorld() {}
// TOOD nonmatching
bool CDummyWorld::ICheckWorldComplete() {
switch (x8_phase) {
case kP_Loading: {
if (!x30_loadToken->IsComplete()) {
return false;
}
CMemoryInStream r(x34_loadBuf.get(), x38_bufSz);
r.ReadLong();
uint version = r.Get< uint >();
x10_strgId = r.Get< CAssetId >();
if (version >= 15) {
x14_savwId = r.Get< CAssetId >();
}
if (version >= 12) {
r.ReadLong();
}
if (version >= 17) {
// TOOD: this class takes some stack argument in r5
// but I can't figure out what it is
// int unk;
CMemoryRelays relays(r /*, unk*/);
}
int areaCount = r.Get< int >();
r.ReadLong();
x18_areas.reserve(areaCount);
for (int i = 0; i < areaCount; ++i) {
x18_areas.push_back(rs_new CDummyGameArea(r, i, version));
}
x28_mapWorldId = r.Get< CAssetId >();
if (x4_loadMap) {
x2c_mapWorld = rs_new TCachedToken< CMapWorld >(
gpSimplePool->GetObj(SObjectTag('MAPW', x28_mapWorldId)));
x2c_mapWorld->Lock();
}
r.ReadChar();
r.ReadLong();
if (version > 10) {
int audioGroupCount = r.ReadLong();
for (int i = 0; i < audioGroupCount; ++i) {
r.ReadLong();
r.ReadLong();
}
}
if (version > 12) {
rstl::string s(r);
}
SWorldLayers::ReadWorldLayers(r, version, xc_mlvlId);
x30_loadToken = nullptr;
x34_loadBuf = nullptr;
x38_bufSz = 0;
if (!x4_loadMap) {
x8_phase = kP_Done;
break;
} else {
x8_phase = kP_LoadingMap;
}
}
case kP_LoadingMap: {
if (!x2c_mapWorld->TryCache()) {
return false;
}
IMapWorld()->SetWhichMapAreasLoaded(*this, 0, 9999);
x8_phase = kP_LoadingMapAreas;
}
case kP_LoadingMapAreas: {
if (x2c_mapWorld->GetObject()->IsMapAreasStreaming()) {
return false;
}
x8_phase = kP_Done;
}
case kP_Done:
return true;
default:
break;
}
return false;
}
CAssetId CDummyWorld::IGetWorldAssetId() const { return xc_mlvlId; }
CAssetId CDummyWorld::IGetSaveWorldAssetId() const { return x14_savwId; }
CAssetId CDummyWorld::IGetStringTableAssetId() const { return x10_strgId; }
const CMapWorld* CDummyWorld::IGetMapWorld() const { return x2c_mapWorld->GetObject(); }
CMapWorld* CDummyWorld::IMapWorld() { return x2c_mapWorld->GetObject(); }
const IGameArea* CDummyWorld::IGetAreaAlways(TAreaId id) const { return &*x18_areas[id.Value()]; }
TAreaId CDummyWorld::IGetCurrentAreaId() const { return x3c_curAreaId; }
TAreaId CDummyWorld::IGetAreaId(CAssetId id) const {
if (id != kInvalidAssetId) {
for (int i = 0; i < x18_areas.size(); ++i) {
TAreaId aid(i);
if (IGetAreaAlways(aid)->IGetAreaAssetId() == id) {
return aid;
}
}
}
#if NONMATCHING
return kInvalidAreaId;
#else
return TAreaId(-1);
#endif
}

View File

@ -1669,7 +1669,7 @@ void CPlayer::Think(float dt, CStateManager& mgr) {
x794_lastVelocity = GetVelocityWR();
}
void CPlayer::SetFrozenState(CStateManager& stateMgr, CAssetId steamTxtr, ushort sfx,
void CPlayer::SetFrozenState(CStateManager& stateMgr, CAssetId steamTxtr, const ushort sfx,
CAssetId iceTxtr) {
if (!stateMgr.GetCameraManager()->IsInCinematicCamera() && !GetFrozenState()) {
bool showMsg;

View File

@ -4,6 +4,7 @@ from pathlib import Path
_LITERAL_REPLACEMENTS = [
("std::string_view", "const rstl::string&"),
("std::string", "rstl::string"),
("std::vector", "rstl::vector"),
("std::list", "rstl::list"),
("std::pair", "rstl::pair"),
@ -102,6 +103,8 @@ _LITERAL_REPLACEMENTS = [
("EWeaponType::", "kWT_"),
("EFluidState::", "kFS_"),
("EPhazonType::", "kPT_"),
("EChain::", "kC_"),
("EPhase::", "kP_"),
# CActor
("x34_transform.origin", "GetTranslation()"),
@ -125,6 +128,8 @@ _LITERAL_REPLACEMENTS = [
("std::fabs", "fabsf"),
("std::sqrt", "sqrtf"),
("clamp(", "CMath::Clamp("),
("[[fallthrough]];", ""),
]
_RE_REPLACEMENTS = [
# SObjectTag{FOURCC('...'), ...} -> SObjectTag('...', ...)