diff --git a/config/G2ME01/splits.txt b/config/G2ME01/splits.txt index cdc3d42..0db164f 100644 --- a/config/G2ME01/splits.txt +++ b/config/G2ME01/splits.txt @@ -1,3 +1,6 @@ +MetroidPrime/CEntity.cpp: + .text start:0x80047E5C end:0x800484D4 + MetroidPrime/Player/CPlayerState.cpp: .text start:0x80084864 end:0x80086410 diff --git a/config/G2ME01/symbols.txt b/config/G2ME01/symbols.txt index a896ee9..810945f 100644 --- a/config/G2ME01/symbols.txt +++ b/config/G2ME01/symbols.txt @@ -512,7 +512,7 @@ fn_8001C690 = .text:0x8001C690; // type:function size:0x54 fn_8001C6E4 = .text:0x8001C6E4; // type:function size:0x130 fn_8001C814 = .text:0x8001C814; // type:function size:0x68 align:0x4 fn_8001C87C = .text:0x8001C87C; // type:function size:0x58 -fn_8001C8D4 = .text:0x8001C8D4; // type:function size:0x54 +__dt__Q24rstl48vector<11SConnection,Q24rstl17rmemory_allocator>Fv = .text:0x8001C8D4; // type:function size:0x54 fn_8001C928 = .text:0x8001C928; // type:function size:0x34 align:0x4 fn_8001C95C = .text:0x8001C95C; // type:function size:0x178 fn_8001CAD4 = .text:0x8001CAD4; // type:function size:0x98 @@ -1340,16 +1340,16 @@ fn_800478D8 = .text:0x800478D8; // type:function size:0x1D8 align:0x4 fn_80047AB0 = .text:0x80047AB0; // type:function size:0x100 fn_80047BB0 = .text:0x80047BB0; // type:function size:0x1A4 fn_80047D54 = .text:0x80047D54; // type:function size:0x108 -fn_80047E5C = .text:0x80047E5C; // type:function size:0xD8 -fn_80047F34 = .text:0x80047F34; // type:function size:0x24 -fn_80047F58 = .text:0x80047F58; // type:function size:0x10 align:0x4 +SearchForSomething__7CEntityFR13CStateManager18EScriptObjectState20EScriptObjectMessage = .text:0x80047E5C; // type:function size:0xD8 +GetAreaId__7CEntityCFv = .text:0x80047F34; // type:function size:0x24 +SetActive__7CEntityFb = .text:0x80047F58; // type:function size:0x10 align:0x4 fn_80047F68 = .text:0x80047F68; // type:function size:0x80 align:0x4 -fn_80047FE8 = .text:0x80047FE8; // type:function size:0x4 -fn_80047FEC = .text:0x80047FEC; // type:function size:0x4 align:0x4 -fn_80047FF0 = .text:0x80047FF0; // type:function size:0x110 -fn_80048100 = .text:0x80048100; // type:function size:0x174 align:0x4 -fn_80048274 = .text:0x80048274; // type:function size:0x64 -fn_800482D8 = .text:0x800482D8; // type:function size:0xCC +Think__7CEntityFfR13CStateManager = .text:0x80047FE8; // type:function size:0x4 +PreThink__7CEntityFfR13CStateManager = .text:0x80047FEC; // type:function size:0x4 align:0x4 +SendScriptMsgs__7CEntityF18EScriptObjectStateR13CStateManager20EScriptObjectMessage = .text:0x80047FF0; // type:function size:0x110 +AcceptScriptMsg__7CEntityFR13CStateManagerR10CScriptMsg = .text:0x80048100; // type:function size:0x174 align:0x4 +__dt__7CEntityFv = .text:0x80048274; // type:function size:0x64 +__ct__7CEntityF9TUniqueIdRC11CEntityInfobRCQ24rstl66basic_string,Q24rstl17rmemory_allocator> = .text:0x800482D8; // type:function size:0xCC fn_800483A4 = .text:0x800483A4; // type:function size:0x130 fn_800484D4 = .text:0x800484D4; // type:function size:0x88 fn_8004855C = .text:0x8004855C; // type:function size:0x88 align:0x4 @@ -12989,7 +12989,7 @@ fn_802CE278 = .text:0x802CE278; // type:function size:0x54 fn_802CE2CC = .text:0x802CE2CC; // type:function size:0x34 fn_802CE300 = .text:0x802CE300; // type:function size:0x4C fn_802CE34C = .text:0x802CE34C; // type:function size:0x3C align:0x4 -fn_802CE388 = .text:0x802CE388; // type:function size:0x64 +Free__7CMemoryFPCv = .text:0x802CE388; // type:function size:0x64 fn_802CE3EC = .text:0x802CE3EC; // type:function size:0xD0 fn_802CE4BC = .text:0x802CE4BC; // type:function size:0x94 fn_802CE550 = .text:0x802CE550; // type:function size:0x3C align:0x4 @@ -17933,7 +17933,7 @@ lbl_803B1A40 = .data:0x803B1A40; // type:object size:0x90 jumptable_803B1AD0 = .data:0x803B1AD0; // type:object size:0x54 scope:local lbl_803B1B24 = .data:0x803B1B24; // type:object size:0xC lbl_803B1B30 = .data:0x803B1B30; // type:object size:0x10 -lbl_803B1B40 = .data:0x803B1B40; // type:object size:0x20 +__vt__7CEntity = .data:0x803B1B40; // type:object size:0x20 lbl_803B1B60 = .data:0x803B1B60; // type:object size:0x10 lbl_803B1B70 = .data:0x803B1B70; // type:object size:0x10 lbl_803B1B80 = .data:0x803B1B80; // type:object size:0x10 @@ -20295,7 +20295,7 @@ lbl_80419118 = .sbss:0x80419118; // type:object size:0x4 data:4byte lbl_8041911C = .sbss:0x8041911C; // type:object size:0x4 data:4byte lbl_80419120 = .sbss:0x80419120; // type:object size:0x4 data:4byte lbl_80419124 = .sbss:0x80419124; // type:object size:0x2 data:2byte -lbl_80419128 = .sbss:0x80419128; // type:object size:0x4 data:4byte +kInvalidAreaId = .sbss:0x80419128; // type:object size:0x4 data:4byte lbl_8041912C = .sbss:0x8041912C; // type:object size:0x4 data:4byte lbl_80419130 = .sbss:0x80419130; // type:object size:0x4 data:4byte lbl_80419134 = .sbss:0x80419134; // type:object size:0x4 data:4byte diff --git a/configure.py b/configure.py index 0d34528..f4cb732 100644 --- a/configure.py +++ b/configure.py @@ -18,6 +18,7 @@ LIBS = [ "mw_version": "1.3.2", "host": True, "objects": [ + ["MetroidPrime/CEntity.cpp", False], ["MetroidPrime/HUD/CHUDMemoParms.cpp", True], ["MetroidPrime/Player/CPlayerState.cpp", False], ], diff --git a/include/Kyoto/Streams/CInputStream.hpp b/include/Kyoto/Streams/CInputStream.hpp new file mode 100644 index 0000000..86eda00 --- /dev/null +++ b/include/Kyoto/Streams/CInputStream.hpp @@ -0,0 +1,138 @@ +#ifndef _CINPUTSTREAM +#define _CINPUTSTREAM + +#include "types.h" + +#include "stddef.h" + +class CInputStream; +template < typename T > +struct TType {}; +template < typename T > +T cinput_stream_helper(const TType< T >& type, CInputStream& in); + +template < typename T > +TType< T > TGetType() { + return TType< T >(); +} + +class CInputStream { +public: + CInputStream(int len); + CInputStream(const void* ptr, int len, bool owned); + virtual ~CInputStream(); + virtual size_t Read(void* dest, size_t len) = 0; + + float ReadFloat(); + u64 ReadLongLong(); + uint ReadLong(); + ushort ReadShort(); + bool ReadBool(); + uchar ReadChar(); + uint ReadBits(uint len); + size_t ReadBytes(void* dest, size_t len); + void Get(void* dest, unsigned long len); + + template < typename T > + inline T Get(const TType< T >& type = TType< T >()) { + return cinput_stream_helper(type, *this); + } + + bool ReadPackedBool() { return ReadBits(1) != 0; } + + // TODO: this cast to uint fixes regalloc in + // CIEKeyframeEmitter / rstl::vector(CInputStream&) + // why? + int ReadInt32() { return static_cast< uint >(Get(TType< int >())); } + u16 ReadUint16() { return Get(); } + + uint GetBlockOffset() const { return x4_blockOffset; } + +private: + bool GrabAnotherBlock(); + bool InternalReadNext(); + + uint x4_blockOffset; + uint x8_blockLen; + uint xc_len; + uchar* x10_ptr; + bool x14_owned; + uint x18_readPosition; + uint x1c_bitWord; + uint x20_bitOffset; +}; + +template < typename T > +inline T cinput_stream_helper(const TType< T >& type, CInputStream& in) { + return T(in); +} +template <> +inline bool cinput_stream_helper(const TType< bool >& type, CInputStream& in) { + return in.ReadBool(); +} +template <> +inline char cinput_stream_helper(const TType< char >& type, CInputStream& in) { + return in.ReadChar(); +} + +template <> +inline unsigned char cinput_stream_helper(const TType< unsigned char >& type, CInputStream& in) { + return in.ReadChar(); +} + +template <> +inline int cinput_stream_helper(const TType< int >& type, CInputStream& in) { + return in.ReadLong(); +} +template <> +inline uint cinput_stream_helper(const TType< uint >& type, CInputStream& in) { + return in.ReadLong(); +} +template <> +inline unsigned long cinput_stream_helper(const TType< unsigned long >& type, CInputStream& in) { + return in.ReadLong(); +} +template <> +inline float cinput_stream_helper(const TType< float >& type, CInputStream& in) { + return in.ReadFloat(); +} +template <> +inline short cinput_stream_helper(const TType< short >& type, CInputStream& in) { + return in.ReadShort(); +} +template <> +inline ushort cinput_stream_helper(const TType< ushort >& type, CInputStream& in) { + return in.ReadShort(); +} + +// rstl +#include "rstl/pair.hpp" +template < typename L, typename R > +inline rstl::pair< L, R > cinput_stream_helper(const TType< rstl::pair< L, R > >& type, + CInputStream& in) { + rstl::pair< L, R > result; + result.first = in.Get(TType< L >()); + result.second = in.Get(TType< R >()); + return result; +} + +#include "rstl/vector.hpp" +template < typename T, typename Alloc > +inline rstl::vector< T, Alloc >::vector(CInputStream& in, const Alloc& allocator) +: x4_count(0), x8_capacity(0), xc_items(nullptr) { + int count = in.ReadInt32(); + reserve(count); + for (int i = 0; i < count; i++) { + push_back(in.Get(TType< T >())); + } +} + +#include "rstl/reserved_vector.hpp" +template < typename T, int N > +inline rstl::reserved_vector< T, N >::reserved_vector(CInputStream& in) : x0_count(in.ReadInt32()) { + for (int i = 0; i < x0_count; i++) { + construct(&data()[i], in.Get(TType< T >())); + } +} + +#endif // _CINPUTSTREAM diff --git a/include/MetroidPrime/CEntity.hpp b/include/MetroidPrime/CEntity.hpp new file mode 100644 index 0000000..76a2961 --- /dev/null +++ b/include/MetroidPrime/CEntity.hpp @@ -0,0 +1,54 @@ +#ifndef _CENTITY +#define _CENTITY + +#include "MetroidPrime/TGameTypes.hpp" +#include "MetroidPrime/CEntityInfo.hpp" + +#include "rstl/string.hpp" +#include "rstl/vector.hpp" + +class CStateManager; + +class CEntity { +public: + virtual ~CEntity(); + virtual CEntity* TypesMatch(EEntityType); + virtual void PreThink(float dt, CStateManager& mgr); + virtual void Think(float dt, CStateManager& mgr); + virtual void AcceptScriptMsg(CStateManager& mgr, CScriptMsg&); + virtual void SetActive(const bool active); + + CEntity(TUniqueId id, const CEntityInfo& info, bool active, const rstl::string& name); + + void SendScriptMsgs(EScriptObjectState state, CStateManager& mgr, EScriptObjectMessage msg); + // static inline void SendScriptMsg(CStateManager& mgr, CEntity* to, TUniqueId sender, + // EScriptObjectMessage msg) { + // mgr.SendScriptMsg(to, sender, msg); + // } + TUniqueId GetUniqueId() const { return uid; } + TEditorId GetEditorId() const { return editorId; } + TAreaId GetAreaId() const; + TAreaId GetCurrentAreaId() const { return areaId; } + const bool GetActive() const { return active; } + // bool IsScriptingBlocked() const { return scriptingBlocked; } + + // might be fake? + rstl::vector< SConnection >& ConnectionList() { return conns; } + const rstl::vector< SConnection >& GetConnectionList() const { return conns; } + + static rstl::vector< SConnection > NullConnectionList; + + TUniqueId SearchForSomething(CStateManager&, EScriptObjectState, EScriptObjectMessage); + +private: + TAreaId areaId; + TUniqueId uid; + TEditorId editorId; + rstl::vector< SConnection > conns; + bool active : 1; + bool notInArea : 1; + bool inGraveyard : 1; + bool scriptingBlocked : 1; +}; + +#endif // _CENTITY diff --git a/include/MetroidPrime/CEntityInfo.hpp b/include/MetroidPrime/CEntityInfo.hpp new file mode 100644 index 0000000..49c6d7d --- /dev/null +++ b/include/MetroidPrime/CEntityInfo.hpp @@ -0,0 +1,95 @@ +#ifndef _CENTITYINFO +#define _CENTITYINFO + +#include "MetroidPrime/TGameTypes.hpp" + +#include "rstl/vector.hpp" + +enum EEntityType { + kET_Entity = 0, + kET_Actor = 1, + kET_PhysicsActor = 2, + kET_Ai = 3, + kET_Patterned = 4, + kET_Weapon = 6, + kET_Effect = 7, + kET_GameProjectile = 8, + kET_Bomb = 14, + kET_EnergyProjectile = 19, + kET_Explosion = 22, + kET_GameLight = 26, + kET_HUDBillboardEffect = 28, + kET_Player = 32, + kET_ScriptPlayerActor = 34, + kET_ScriptActorKeyframe = 35, + kET_ScriptCameraShaker = 41, + kET_ScriptCamera = 44, + kET_ScriptColorModulate = 45, + kET_DarkSamusBattleStage = 51, + kET_ScriptDock = 55, + kET_ScriptDoor = 56, + kET_ScriptLayerController = 64, + kET_ScriptPickup = 66, + kET_ScriptPlayerProxy = 69, + kET_ScriptPortalTransition = 72, + kET_Relay = 73, + kET_ScriptSpawnPoint = 79, + kET_ScriptSpecialFunction = 80, + kET_ScriptStreamedMusic = 84, + kET_ScriptTeamAi = 88, + kET_ScriptTrigger = 92, + kET_ScriptWorldTeleporter = 98, + kET_DarkSamus = 111, + kET_PowerBomb = 156, +}; + +enum EScriptObjectState { + kSS_Active = 0x41435456, + kSS_Inactive = 0x49435456, + kSS_InvalidState = 0xffffffff +}; + +enum EScriptObjectMessage { + kSM_Activate = 0x41435456, + kSM_Deactivate = 0x44435456, + kSM_ToggleActive = 0x54435456, + kSM_None = 0xffffffff, +}; + +struct SConnection { + EScriptObjectState state; + EScriptObjectMessage msg; + TEditorId objId; + SConnection(EScriptObjectState state, EScriptObjectMessage msg, TEditorId id) + : state(state), msg(msg), objId(id) {} +}; + +class CEntityInfo { + TAreaId areaId; + rstl::vector< SConnection > conns; + TEditorId editorId; + +public: + CEntityInfo(TAreaId aid, const rstl::vector< SConnection >& conns, + TEditorId eid = kInvalidEditorId); + TAreaId GetAreaId() const { return areaId; } + const rstl::vector< SConnection >& GetConnectionList() const { return conns; } + TEditorId GetEditorId() const { return editorId; } +}; + +class CScriptMsg { +public: + TUniqueId GetOriginator() { return originator; } + TUniqueId GetId() const { return id; } + EScriptObjectMessage GetMessage() const { return msg; } + EScriptObjectState GetState() const { return state; } + +public: + TUniqueId unk; + TUniqueId originator; + TUniqueId id; + EScriptObjectMessage msg; + EScriptObjectState state; +}; + +#endif // _CENTITYINFO diff --git a/include/MetroidPrime/TGameTypes.hpp b/include/MetroidPrime/TGameTypes.hpp new file mode 100644 index 0000000..44b2e4e --- /dev/null +++ b/include/MetroidPrime/TGameTypes.hpp @@ -0,0 +1,73 @@ +#ifndef _TGAMETYPES +#define _TGAMETYPES + +#include "types.h" + +class CInputStream; +class COutputStream; + +struct TAreaId; +struct TEditorId; +struct TUniqueId; + +extern const TAreaId kInvalidAreaId; +extern const TEditorId kInvalidEditorId; +extern const TUniqueId kInvalidUniqueId; + +struct TAreaId { + int value; + + TAreaId() : value(-1) {} + TAreaId(int value) : value(value) {} + int Value() const { return value; } + + bool operator==(const TAreaId& other) const { return value == other.value; } + bool operator!=(const TAreaId& other) const { return value != other.value; } +}; +CHECK_SIZEOF(TAreaId, 0x4) + +struct TEditorId { + uint value; + + TEditorId(uint value) : value(value) {} + TEditorId(CInputStream& in); + // TODO + uint Value() const { return value & 0x3FFFFFF; } + uint Id() const { return value & 0xffff; } + int AreaNum() const { return (value >> 16) & 0x3ff; } + + void PutTo(COutputStream&) const; + + bool operator==(const TEditorId& other) const { return Value() == other.Value(); } + bool operator!=(const TEditorId& other) const { return Value() != other.Value(); } +}; +CHECK_SIZEOF(TEditorId, 0x4) + +struct TUniqueId { + ushort value; + + TUniqueId(ushort version, ushort id) : value(((version & 0x3F) << 10) | (id & 0x3FF)) {} + + ushort Value() const { return value & 0x3FF; } + ushort Version() const { return (value >> 10) & 0x3F; } + + bool operator==(const TUniqueId& other) const { return value == other.value; } + bool operator!=(const TUniqueId& other) const { return value != other.value; } + bool operator<(const TUniqueId& other) const { return value < other.value; } + +private: +}; +CHECK_SIZEOF(TUniqueId, 0x2) + +// struct TGameScriptId { +// TEditorId editorId; +// bool b; +// }; +// CHECK_SIZEOF(TGameScriptId, 0x8) + +typedef ushort TSfxId; +static TSfxId InvalidSfxId = 0xFFFFu; + +#define ALIGN_UP(x, a) (((x) + (a - 1)) & ~(a - 1)) + +#endif // _TGAMETYPES diff --git a/include/rstl/vector.hpp b/include/rstl/vector.hpp index 074d822..1ae8c76 100644 --- a/include/rstl/vector.hpp +++ b/include/rstl/vector.hpp @@ -59,10 +59,10 @@ public: } } vector(CInputStream& in, const Alloc& alloc = Alloc()); - ~vector() { + ~vector(); /* { destroy(begin(), end()); x0_allocator.deallocate(xc_items); - } + }*/ void reserve(int size); void resize(int size, const T& in); diff --git a/src/MetroidPrime/CEntity.cpp b/src/MetroidPrime/CEntity.cpp new file mode 100644 index 0000000..a6ffc4f --- /dev/null +++ b/src/MetroidPrime/CEntity.cpp @@ -0,0 +1,65 @@ +#include "MetroidPrime/CEntity.hpp" + +rstl::vector< SConnection > CEntity::NullConnectionList; + +// CEntityInfo::CEntityInfo(TAreaId aid, const rstl::vector< SConnection >& conns, TEditorId eid) +// : x0_areaId(aid), x4_conns(conns), x14_editorId(eid) {} + +CEntity::CEntity(TUniqueId id, const CEntityInfo& info, bool active, const rstl::string& name) +: areaId(info.GetAreaId()) +, uid(id) +, editorId(info.GetEditorId()) +, conns(info.GetConnectionList()) +, active(active) +, inGraveyard(false) +// , scriptingBlocked(false) +, notInArea(areaId == kInvalidAreaId) {} + +CEntity::~CEntity() {} + +void CEntity::AcceptScriptMsg(CStateManager& mgr, CScriptMsg& msg) { + switch (msg.GetMessage()) { + case kSM_Activate: + if (!active) { + SetActive(true); + SendScriptMsgs(kSS_Active, mgr, kSM_None); + } + break; + case kSM_Deactivate: + if (active) { + SetActive(false); + SendScriptMsgs(kSS_Inactive, mgr, kSM_None); + } + break; + case kSM_ToggleActive: { + CScriptMsg newMsg(msg); + if (!active) { + newMsg.msg = kSM_Deactivate; + } + AcceptScriptMsg(mgr, newMsg); + break; + } + } +} + +void CEntity::SendScriptMsgs(EScriptObjectState state, CStateManager& mgr, + EScriptObjectMessage skipMsg) { + rstl::vector< SConnection >::const_iterator it = conns.begin(); + for (; it != conns.end(); ++it) { + // if (it->x0_state == state && it->x4_msg != skipMsg) { + // mgr.SendScriptMsg(GetUniqueId(), it->x8_objId, it->x4_msg, state); + // } + } +} + +void CEntity::PreThink(float dt, CStateManager& mgr) {} + +void CEntity::Think(float dt, CStateManager& mgr) {} + +void CEntity::SetActive(const bool active) { this->active = active; } + +TAreaId CEntity::GetAreaId() const { return notInArea ? kInvalidAreaId : areaId; } + +TUniqueId CEntity::SearchForSomething(CStateManager&, EScriptObjectState, EScriptObjectMessage) { + +}