diff --git a/PrimeAPI/include/PrimeAPI.h b/PrimeAPI/include/PrimeAPI.h index 39f601a..cdcf51c 100644 --- a/PrimeAPI/include/PrimeAPI.h +++ b/PrimeAPI/include/PrimeAPI.h @@ -1,7 +1,7 @@ #ifndef PRIMEAPI_H #define PRIMEAPI_H -#include +#include "gccore.h" // Add this macro at the beginning of _prolog #define MODULE_INIT \ diff --git a/PrimeAPI/include/rstl/rc_ptr.h b/PrimeAPI/include/rstl/rc_ptr.h index 401edbb..013660c 100644 --- a/PrimeAPI/include/rstl/rc_ptr.h +++ b/PrimeAPI/include/rstl/rc_ptr.h @@ -7,24 +7,51 @@ RSTL_BEGIN /** Reference counting pointer. Needs to be fixed so it actually counts references */ template -class rc_ptr +class rc_ptr_prime1 { - T** mpRawPtr; + struct rc_data + { + T* ptr; + int refCount; + }; + rc_data* data; public: - inline T* RawPointer() const { - if (mpRawPtr == nullptr) { - return nullptr; - } - return *mpRawPtr; - } - inline T& operator*() { return **mpRawPtr; } - inline const T& operator*() const { return **mpRawPtr; } - inline T& operator->() { return **mpRawPtr; } - inline const T& operator->() const { return **mpRawPtr; } - inline operator bool() const { return mpRawPtr != NULL && *mpRawPtr != NULL; } + inline T* RawPointer() const { + if (data) { + return data->ptr; + } + return nullptr; + } + inline T& operator*() { return *data->ptr; } + inline const T& operator*() const { return *data->ptr; } + inline T* operator->() { return data->ptr; } + inline const T* operator->() const { return data->ptr; } + inline operator bool() const { return data != nullptr && data->ptr != nullptr; } }; +template +class rc_ptr_prime2 +{ + T* rawPtr; + int* refCount; + +public: + inline T* RawPointer() const { return rawPtr; } + inline T& operator*() { return *rawPtr; } + inline const T& operator*() const { return *rawPtr; } + inline T* operator->() { return rawPtr; } + inline const T* operator->() const { return rawPtr; } + inline operator bool() const { return rawPtr != nullptr; } +}; + + +#if PRIME == 1 +#define rc_ptr rc_ptr_prime1 +#elif PRIME == 2 +#define rc_ptr rc_ptr_prime2 +#endif + RSTL_END #endif \ No newline at end of file diff --git a/PrimeAPI2/PrimeAPI.cmake b/PrimeAPI2/PrimeAPI.cmake index a9ef9ec..e51119a 100644 --- a/PrimeAPI2/PrimeAPI.cmake +++ b/PrimeAPI2/PrimeAPI.cmake @@ -1,29 +1,38 @@ set(PRIMEAPI2_PATH "${CMAKE_CURRENT_LIST_DIR}") +if (NOT DEFINED LLVM_DIR) + message(FATAL_ERROR "Must specify LLVM_DIR") +endif() set(CMAKE_TOOLCHAIN_FILE "${PRIMEAPI2_PATH}/PrimeToolchain.cmake") set(DEVKITPRO "/opt/devkitpro") set(DEVKITPPC "/opt/devkitpro/devkitPPC") -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -nostdlib") -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib") +set(DEVKIT_PATHS + "${DEVKITPRO}/libogc/include" + "${DEVKITPPC}/lib/gcc/powerpc-eabi/10.2.0/include" + "${DEVKITPPC}/powerpc-eabi/include" +) + +foreach(P IN LISTS DEVKIT_PATHS) + if(NOT EXISTS "${P}") + message(FATAL_ERROR "${P} does not exist") + endif() +endforeach() + set(CMAKE_PRIME_C_FLAGS_LIST -target powerpc-unknown-eabi -mllvm --relocation-model=static -nostdlib -nostdinc -ffreestanding - -isystem "${DEVKITPPC}/lib/gcc/powerpc-eabi/10.2.0/include" - -isystem "${DEVKITPPC}/powerpc-eabi/include" -fno-function-sections -fno-data-sections -fno-exceptions -fno-asynchronous-unwind-tables -# -fPIC -fvisibility=hidden -flto=thin -# -mno-sdata ) set(CMAKE_PRIME_CXX_FLAGS_LIST @@ -34,17 +43,6 @@ set(CMAKE_PRIME_CXX_FLAGS_LIST set(CMAKE_PRIME_LINK_FLAGS_LIST -nostdlib -# -nodefaultlibs -# -flto -# -Os -# -lgcc -# -lsysbase -# -d -# -x -# "-z nocopyreloc" -# "-z combreloc" -# -call_shared -# --strip-discarded --gc-sections "-e __rel_prolog" "--unresolved-symbols=report-all" @@ -52,7 +50,6 @@ set(CMAKE_PRIME_LINK_FLAGS_LIST --no-allow-shlib-undefined --no-undefined -r -# -shared "-T ${PRIMEAPI2_PATH}/eppc.ld" ) @@ -63,86 +60,95 @@ list(JOIN CMAKE_PRIME_LINK_FLAGS_LIST " " CMAKE_PRIME_LINK_FLAGS) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_PRIME_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_PRIME_CXX_FLAGS}") -include_directories("${DEVKITPRO}/libogc/include/") - # Macro to get the required link arguments in place -macro(add_prime_library name symbol_list base_dol) +macro(add_prime_library_common name symbol_list base_dol) add_executable(${name} ${ARGN} - "${CMAKE_CURRENT_BINARY_DIR}/ApplyCodePatches.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/dol_symbols.o" + "${CMAKE_CURRENT_BINARY_DIR}/ApplyCodePatches-${name}.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/dol_symbols-${name}.o" ) set_target_properties(${name} PROPERTIES LINK_FLAGS - "${CMAKE_PRIME_LINK_FLAGS} -Map ${CMAKE_CURRENT_BINARY_DIR}/${name}.map" + "${CMAKE_PRIME_LINK_FLAGS} -Map ${CMAKE_CURRENT_BINARY_DIR}/${name}.map" ) + target_include_directories(${name} SYSTEM PUBLIC ${DEVKIT_PATHS}) # Create the ApplyCodePatches.cpp add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ApplyCodePatches.cpp" - COMMAND python3 "parse_and_generate_patch.py" - -i "${CMAKE_CURRENT_SOURCE_DIR}/${base_dol}" - -o "${CMAKE_CURRENT_BINARY_DIR}/ApplyCodePatches.cpp" - ${PRIME_PATCH_FUNCTIONS} - WORKING_DIRECTORY "${PRIMEAPI2_PATH}/python/" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ApplyCodePatches-${name}.cpp" + COMMAND python3 "parse_and_generate_patch.py" + -i "${CMAKE_CURRENT_SOURCE_DIR}/${base_dol}" + -o "${CMAKE_CURRENT_BINARY_DIR}/ApplyCodePatches-${name}.cpp" + ${PRIME_PATCH_FUNCTIONS} + WORKING_DIRECTORY "${PRIMEAPI2_PATH}/python/" ) # Create the dol_symbols.o get_filename_component(absolute_symbol_list "${symbol_list}" REALPATH) add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dol_symbols.o" - COMMAND python3 "symbols_to_yaml2obj_file.py" - --llvm-dir "${LLVM_DIR}" - "${absolute_symbol_list}" - "${CMAKE_CURRENT_BINARY_DIR}/dol_symbols.o" - MAIN_DEPENDENCY "${absolute_symbol_list}" - WORKING_DIRECTORY "${PRIMEAPI2_PATH}/python/" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/dol_symbols-${name}.o" + COMMAND python3 "symbols_to_yaml2obj_file.py" + --llvm-dir "${LLVM_DIR}" + "${absolute_symbol_list}" + "${CMAKE_CURRENT_BINARY_DIR}/dol_symbols-${name}.o" + MAIN_DEPENDENCY "${absolute_symbol_list}" + WORKING_DIRECTORY "${PRIMEAPI2_PATH}/python/" ) # Create the patched dol add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/default_mod.dol" - COMMAND python3 "patch_dol_file.py" - -i "${CMAKE_CURRENT_SOURCE_DIR}/${base_dol}" - -o "${CMAKE_CURRENT_BINARY_DIR}/default_mod.dol" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${base_dol}" - WORKING_DIRECTORY "${PRIMEAPI2_PATH}/python/" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}-default-mod.dol" + COMMAND python3 "patch_dol_file.py" + -i "${CMAKE_CURRENT_SOURCE_DIR}/${base_dol}" + -o "${CMAKE_CURRENT_BINARY_DIR}/${name}-default-mod.dol" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${base_dol}" + WORKING_DIRECTORY "${PRIMEAPI2_PATH}/python/" ) add_custom_target( - patch_dol - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/default_mod.dol" - SOURCES "${base_dol}" + ${name}-patch-dol + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}-default-mod.dol" + SOURCES "${base_dol}" ) - add_dependencies(${name} patch_dol) - + add_dependencies(${name} ${name}-patch-dol) # Create the Mod.rel add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Mod.rel" - COMMAND cargo run -p dol_linker -- - rel - -o "${CMAKE_CURRENT_BINARY_DIR}/Mod.rel" - -s "${PRIMEAPI2_PATH}/empty.lst" - "${CMAKE_CURRENT_BINARY_DIR}/${name}" - WORKING_DIRECTORY "${PRIMEAPI2_PATH}/randomprime/" - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${name}-Mod.rel" + COMMAND cargo run -p dol_linker -- + rel + -o "${CMAKE_CURRENT_BINARY_DIR}/${name}-Mod.rel" + -s "${PRIMEAPI2_PATH}/empty.lst" + "${CMAKE_CURRENT_BINARY_DIR}/${name}" + WORKING_DIRECTORY "${PRIMEAPI2_PATH}/randomprime/" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}" ) add_custom_target( - build_mod ALL - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/Mod.rel" + ${name}-build-mod ALL + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}-Mod.rel" ) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Mod.rel" - DESTINATION "files/") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/default_mod.dol" + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${name}-Mod.rel" + DESTINATION "files/" + RENAME "Mod.rel") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${name}-default-mod.dol" DESTINATION "files/" RENAME "default.dol") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/default_mod.dol" + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${name}-default-mod.dol" DESTINATION "sys/" RENAME "main.dol") endmacro() +macro(add_prime_library name symbol_list base_dol) + add_prime_library_common("${name}" "${symbol_list}" "${base_dol}" ${ARGN}) + target_compile_definitions(${name} PUBLIC -DPRIME=1) +endmacro() + +macro(add_echoes_library name symbol_list base_dol) + add_prime_library_common("${name}" "${symbol_list}" "${base_dol}" ${ARGN}) + target_compile_definitions(${name} PUBLIC -DPRIME=2) +endmacro() + macro(patch_function orig dest) list(APPEND PRIME_PATCH_FUNCTIONS -p "'${orig}'" "'${dest}'" - ) + ) endmacro() diff --git a/PrimeAPI2/PrimeToolchain.cmake b/PrimeAPI2/PrimeToolchain.cmake index e76a555..18c7a87 100644 --- a/PrimeAPI2/PrimeToolchain.cmake +++ b/PrimeAPI2/PrimeToolchain.cmake @@ -1,34 +1,19 @@ # Hanafuda toolchain set(CMAKE_SYSTEM_NAME powerpc-elf-prime) -if (NOT DEFINED LLVM_DIR) - message(FATAL_ERROR "Must specify LLVM_DIR") -endif() - # Set toolchain programs -set(CMAKE_C_COMPILER "${LLVM_DIR}/bin/clang") -set(CMAKE_CXX_COMPILER "${LLVM_DIR}/bin/clang++") +set(CMAKE_C_COMPILER "${LLVM_DIR}/bin/clang" CACHE FILEPATH "" FORCE) +set(CMAKE_CXX_COMPILER "${LLVM_DIR}/bin/clang++" CACHE FILEPATH "" FORCE) # Set triple for CMake's identification set(triple powerpc-none-unknown-elf) set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_CXX_COMPILER_TARGET ${triple}) -# Sysroont -#set(CMAKE_SYSROOT "${CMAKE_SOURCE_DIR}") - # Skip test compile (hanafuda has a somewhat unorthodox compiler workflow) set(CMAKE_C_COMPILER_FORCED TRUE) set(CMAKE_CXX_COMPILER_FORCED TRUE) -# Compile a C file into an object file -set(CMAKE_C_COMPILE_OBJECT " -c -o ") -set(CMAKE_CXX_COMPILE_OBJECT " -c -o ") - # Link object files to an executable set(CMAKE_C_LINK_EXECUTABLE "${LLVM_DIR}/bin/ld.lld -o ") set(CMAKE_CXX_LINK_EXECUTABLE "${LLVM_DIR}/bin/ld.lld -o ") - -# Thing that doesn't work -set(CMAKE_C_OUTPUT_EXTENSION ".o") -set(CMAKE_CXX_OUTPUT_EXTENSION ".o") diff --git a/PrimeAPI2/python/symbols/v1.028.lst b/PrimeAPI2/python/symbols/v1.028.lst new file mode 100644 index 0000000..7219a14 --- /dev/null +++ b/PrimeAPI2/python/symbols/v1.028.lst @@ -0,0 +1,28 @@ +0x8036fcf8 OSReport +0x8036017c DVDOpen +0x8036048c DVDReadAsyncPrio +0x80360244 DVDClose +0x8037333c OSLink +0x8035712c PPCSetFpIEEEMode +0x802ce224 __nwa__FUlPCcPCc +0x802ce278 __nw__FUlPCcPCc +0x80372f8c __OSLinkHandleREL14 +0x8001de68 AdvanceGameState__9CMainFlowFR18CArchitectureQueue +0x800401d8 InitializeState__13CStateManagerFUi7TAreaIdUi +0x8005926c StartStreamIn__9CGameAreaFR13CStateManager +0x800031e8 memcpy +0x80142590 _ZN10CGameState17SetCurrentWorldIdEj +0x801425e0 _ZN10CGameState17CurrentWorldStateEv +0x80144f70 _ZN11CWorldState21SetDesiredAreaAssetIdEj +0x8001db54 _ZN9CMainFlow12SetGameStateE17EClientFlowStatesR18CArchitectureQueue +0x8001de68 _ZN9CMainFlow16AdvanceGameStateER18CArchitectureQueue +0x800401d8 _ZN13CStateManager15InitializeStateEj7TAreaIdj +0x80186534 _ZN7CPlayer8TeleportERK12CTransform4fR13CStateManagerb +0x800859d8 _ZN12CPlayerState19ReInitializePowerUpENS_9EItemTypeEi +0x80085760 _ZN12CPlayerState10IncrPickUpENS_9EItemTypeEi +0x8005926c _ZN9CGameArea13StartStreamInER13CStateManager +0x8004ebe4 _ZN6CWorld12AuxGetAreaIdEP7TAreaIdPS_j +0x80144f68 _ZN11CWorldState13GetLayerStateEv +0x80418eb8 g_GameState +0x803a7288 gkPowerUpMaxValues +0x803a743c gkPowerUpShouldPersist \ No newline at end of file diff --git a/src/include/VersionSelector.hpp b/src/include/VersionSelector.hpp new file mode 100644 index 0000000..7498feb --- /dev/null +++ b/src/include/VersionSelector.hpp @@ -0,0 +1,16 @@ +#ifndef PRIMEAPI_GETFIELD_HPP +#define PRIMEAPI_GETFIELD_HPP + +#include "types.h" + +constexpr inline u32 ByVersion(u32 prime1, u32 prime2) { + static_assert(1 <= PRIME && PRIME <= 2, "Unknown game"); + + if constexpr (PRIME == 1) { + return prime1; + } else { + return prime2; + } +} + +#endif \ No newline at end of file diff --git a/src/include/prime/CGameState.hpp b/src/include/prime/CGameState.hpp index 871adc5..e4cf3af 100755 --- a/src/include/prime/CGameState.hpp +++ b/src/include/prime/CGameState.hpp @@ -1,6 +1,8 @@ #ifndef CGAMESTATE_HPP #define CGAMESTATE_HPP +#include "types.h" + class CWorldState; class CGameState { diff --git a/src/include/prime/CMainFlow.hpp b/src/include/prime/CMainFlow.hpp index 9d8d009..f20d5a0 100644 --- a/src/include/prime/CMainFlow.hpp +++ b/src/include/prime/CMainFlow.hpp @@ -3,19 +3,19 @@ #include "prime/CIOWin.hpp" -enum EClientFlowStates { - kCFS_Unspecified = -1, - kCFS_PreFrontEnd = 7, - kCFS_FrontEnd = 8, - kCFS_Game = 14, - kCFS_GameExit = 15 +enum class EClientFlowStates { + Unspecified = -1, + PreFrontEnd = 7, + FrontEnd = 8, + Game = 14, + GameExit = 15 }; class CMainFlow { public: CIOWin::EMessageReturn OnMessage(const CArchitectureMessage &msg, CArchitectureQueue &queue); - int GetGameState() { return *GetField(this, 0x14); } + EClientFlowStates GetGameState() { return *GetField(this, 0x14); } void SetGameState(EClientFlowStates state, CArchitectureQueue &queue); void AdvanceGameState(CArchitectureQueue &queue); diff --git a/src/include/prime/CPlayerState.hpp b/src/include/prime/CPlayerState.hpp index cdf7d47..0cbd24a 100755 --- a/src/include/prime/CPlayerState.hpp +++ b/src/include/prime/CPlayerState.hpp @@ -2,6 +2,7 @@ #define CPLAYERSTATE_H #include +#include "rstl/vector.h" #include class CInputStream; @@ -10,60 +11,173 @@ class CStateManager; class CPlayerState { public: - enum EItemType { - kItem_PowerBeam = 0, - kItem_IceBeam = 1, - kItem_WaveBeam = 2, - kItem_PlasmaBeam = 3, - kItem_Missile = 4, - kItem_ScanVisor = 5, - kItem_MorphBallBomb = 6, - kItem_PowerBomb = 7, - kItem_Flamethrower = 8, - kItem_ThermalVisor = 9, - kItem_ChargeBeam = 10, - kItem_SuperMissile = 11, - kItem_GrappleBeam = 12, - kItem_XRayVisor = 13, - kItem_IceSpreader = 14, - kItem_SpaceJump = 15, - kItem_MorphBall = 16, - kItem_CombatVisor = 17, - kItem_BoostBall = 18, - kItem_SpiderBall = 19, - kItem_PowerSuit = 20, - kItem_GravitySuit = 21, - kItem_VariaSuit = 22, - kItem_PhazonSuit = 23, - kItem_EnergyTank = 24, - kItem_Unknown1 = 25, - kItem_HealthRefill = 26, - kItem_Unknown2 = 27, - kItem_Wavebuster = 28, - kItem_ArtifactOfTruth = 29, - kItem_ArtifactOfStrength = 30, - kItem_ArtifactOfElder = 31, - kItem_ArtifactOfWild = 32, - kItem_ArtifactOfLifegiver = 33, - kItem_ArtifactOfWarrior = 34, - kItem_ArtifactOfChozo = 35, - kItem_ArtifactOfNature = 36, - kItem_ArtifactOfSun = 37, - kItem_ArtifactOfWorld = 38, - kItem_ArtifactOfSpirit = 39, - kItem_ArtifactOfNewborn = 40, - kItem_Max + enum class EItemType : size_t { +#if PRIME == 1 + PowerBeam = 0, + IceBeam = 1, + WaveBeam = 2, + PlasmaBeam = 3, + Missile = 4, + ScanVisor = 5, + MorphBallBomb = 6, + PowerBomb = 7, + Flamethrower = 8, + ThermalVisor = 9, + ChargeBeam = 10, + SuperMissile = 11, + GrappleBeam = 12, + XRayVisor = 13, + IceSpreader = 14, + SpaceJump = 15, + MorphBall = 16, + CombatVisor = 17, + BoostBall = 18, + SpiderBall = 19, + PowerSuit = 20, + GravitySuit = 21, + VariaSuit = 22, + PhazonSuit = 23, + EnergyTank = 24, + Unknown1 = 25, + HealthRefill = 26, + Unknown2 = 27, + Wavebuster = 28, + ArtifactOfTruth = 29, + ArtifactOfStrength = 30, + ArtifactOfElder = 31, + ArtifactOfWild = 32, + ArtifactOfLifegiver = 33, + ArtifactOfWarrior = 34, + ArtifactOfChozo = 35, + ArtifactOfNature = 36, + ArtifactOfSun = 37, + ArtifactOfWorld = 38, + ArtifactOfSpirit = 39, + ArtifactOfNewborn = 40, +#elif PRIME == 2 + PowerBeam = 0x0, + DarkBeam = 0x1, + LightBeam = 0x2, + AnnihilatorBeam = 0x3, + SuperMissile = 0x4, + Darkburst = 0x5, + Sunburst = 0x6, + SonicBoom = 0x7, + CombatVisor = 0x8, + ScanVisor = 0x9, + DarkVisor = 0xa, + EchoVisor = 0xb, + VariaSuit = 0xc, + DarkSuit = 0xd, + LightSuit = 0xe, + MorphBall = 0xf, + BoostBall = 0x10, + SpiderBall = 0x11, + MorphBallBombs = 0x12, + Unknown01 = 0x13, + Unknown02 = 0x14, + Unknown03 = 0x15, + ChargeBeam = 0x16, + GrappleBeam = 0x17, + SpaceJumpBoots = 0x18, + GravityBoost = 0x19, + SeekerLauncher = 0x1a, + ScrewAttack = 0x1b, + Unknown04 = 0x1c, + TempleKey1 = 0x1d, + TempleKey2 = 0x1e, + TempleKey3 = 0x1f, + AgonKey1 = 0x20, + AgonKey2 = 0x21, + AgonKey3 = 0x22, + TorvusKey1 = 0x23, + TorvusKey2 = 0x24, + TorvusKey3 = 0x25, + HiveKey1 = 0x26, + HiveKey2 = 0x27, + HiveKey3 = 0x28, + HealthRefill = 0x29, + EnergyTank = 0x2a, + Powerbomb = 0x2b, + Missile = 0x2c, + DarkAmmo = 0x2d, + LightAmmo = 0x2e, + ItemPercentage = 0x2f, + Unknown_48 = 0x30, + Unknown_49 = 0x31, + Unknown_50 = 0x32, + Unknown_51 = 0x33, + Unknown_52 = 0x34, + Unknown_53 = 0x35, + Unknown_54 = 0x36, + Unknown_55 = 0x37, + Unknown_56 = 0x38, + Invisibility = 0x39, + DoubleDamage = 0x3a, + Invincibility = 0x3b, + Unknown_60 = 0x3c, + Unknown_61 = 0x3d, + Unknown_62 = 0x3e, + Unknown_63 = 0x3f, + Unknown_64 = 0x40, + Unknown_65 = 0x41, + Unknown_66 = 0x42, + Unknown_67 = 0x43, + Unknown_68 = 0x44, + Unknown_69 = 0x45, + Unknown_70 = 0x46, + Unused1 = 0x47, + Unused2 = 0x48, + Unused3 = 0x49, + Unused4 = 0x4a, + Unknown_76 = 0x4b, + Unknown_77 = 0x4c, + Unknown_78 = 0x4d, + Unknown_79 = 0x4e, + Unknown_80 = 0x4f, + Unknown_81 = 0x50, + UnlimitedMissiles = 0x51, + UnlimitedBeamAmmo = 0x52, + DarkShield = 0x53, + LightShield = 0x54, + AbsorbAttack = 0x55, + DeathBall = 0x56, + ScanVirus = 0x57, + Unknown_88 = 0x58, + DisableBeamAmmo = 0x59, + DisableMissiles = 0x5a, + Unknown_91 = 0x5b, + DisableBall = 0x5c, + DisableSpaceJump = 0x5d, + Unknown_94 = 0x5e, + HackedEffect = 0x5f, + CannonBall = 0x60, + VioletTranslator = 0x61, + AmberTranslator = 0x62, + EmeraldTranslator = 0x63, + CobaltTranslator = 0x64, + TempleKey4 = 0x65, + TempleKey5 = 0x66, + TempleKey6 = 0x67, + TempleKey7 = 0x68, + TempleKey8 = 0x69, + TempleKey9 = 0x6a, + EnergyTransferModule = 0x6b, + ChargeCombo = 0x6c, +#endif + Max }; enum EPlayerVisor { kVisor_Combat = 0, - kVisor_XRay = 1, + kVisor_XRay_Echo = 1, kVisor_Scan = 2, - kVisor_Thermal = 3, + kVisor_Thermal_Dark = 3, kVisor_Max }; enum EPlayerSuit { + #if PRIME == 1 kSuit_Power = 0, kSuit_Gravity = 1, kSuit_Varia = 2, @@ -72,15 +186,26 @@ class CPlayerState { kSuit_FusionGravity = 5, kSuit_FusionVaria = 6, kSuit_FusionPhazon = 7, + #elif PRIME == 2 + kSuit_Varia = 0, + kSuit_Dark = 1, + kSuit_Light = 2, + #endif kSuit_Max }; enum EBeamId { kBeam_Power = 0, + #if PRIME == 1 kBeam_Ice = 1, kBeam_Plasma = 2, kBeam_Wave = 3, kBeam_Phazon = 4, + #elif PRIME == 2 + kBeam_Dark = 1, + kBeam_Light = 2, + kBeam_Annihilator = 3, + #endif kBeam_Max }; @@ -88,21 +213,36 @@ class CPlayerState { public: int amount; int capacity; + #if PRIME > 1 + float timeLeft; + #endif CPowerUp() {} + #if PRIME < 2 CPowerUp(int, int); + #else + CPowerUp(int, int, float); + #endif CPowerUp(CInputStream&); }; + #if PRIME == 2 + int playerIndex; + #endif /* 0x000 */ int flags; /* 0x004 */ int unknown0; /* 0x008 */ EBeamId currentBeam; /* 0x00C */ CHealthInfo healthInfo; /* 0x014 */ EPlayerVisor currentVisor; /* 0x018 */ EPlayerVisor transitionVisor; + #if PRIME == 2 + rstl::vector vector; + float relatedToCharge; + float unk; + #endif /* 0x01C */ float visorTransitionFactor; /* 0x020 */ EPlayerSuit currentSuit; - /* 0x024 */ CPowerUp powerUps[kItem_Max]; + /* 0x024 */ CPowerUp powerUps[static_cast(CPlayerState::EItemType::Max)]; CPlayerState(); CPlayerState(CInputStream&); @@ -125,10 +265,14 @@ class CPlayerState { bool ItemEnabled(CPlayerState::EItemType) const; void DisableItem(CPlayerState::EItemType); void EnableItem(CPlayerState::EItemType); - inline CPowerUp *GetPowerUp(EItemType Item) { return &GetField(this, 0x24)[Item]; } + inline CPowerUp *GetPowerUp(EItemType Item) { return &GetField(this, 0x24)[static_cast(Item)]; } bool HasPowerUp(CPlayerState::EItemType) const; uint GetItemCapacity(CPlayerState::EItemType) const; - uint GetItemAmount(CPlayerState::EItemType) const; + #if PRIME < 2 + uint GetItemAmount(CPlayerState::EItemType itemType) const; + #else + uint GetItemAmount(CPlayerState::EItemType itemType, bool respectFieldToQuery) const; + #endif void DecrPickUp(CPlayerState::EItemType, int); void IncrPickUp(CPlayerState::EItemType, int); void AddPowerUp(CPlayerState::EItemType, int); @@ -137,6 +281,9 @@ class CPlayerState { }; // Max inventory capacity values, indexed by EItemType -extern const uint32 gkPowerUpMaxValues[CPlayerState::EItemType::kItem_Max]; +extern const uint32 gkPowerUpMaxValues[static_cast(CPlayerState::EItemType::Max)]; +#if PRIME > 1 +extern const char gkPowerUpShouldPersist[static_cast(CPlayerState::EItemType::Max)]; +#endif #endif \ No newline at end of file diff --git a/src/include/prime/CStateManager.hpp b/src/include/prime/CStateManager.hpp index 1c18aee..5341335 100644 --- a/src/include/prime/CStateManager.hpp +++ b/src/include/prime/CStateManager.hpp @@ -6,10 +6,11 @@ #include "rstl/rc_ptr.h" #include "rstl/vector.h" #include "GetField.hpp" +#include "VersionSelector.hpp" #include "CObjectList.hpp" #include "CGraphics.hpp" -#define CStateManager_INSTANCE ((CStateManager *) 0x8045A1A8) +#define CStateManager_INSTANCE ((CStateManager *) ByVersion(0x8045A1A8, 0x0)) class CPlayerState; @@ -42,31 +43,39 @@ class CStateManager { rstl::rc_ptr worldLayerState; public: -enum EInitPhase + enum class EInitPhase { - kInit_LoadWorld = 0, - kInit_LoadFirstArea = 1, - kInit_Done = 2 + LoadWorld = 0, + LoadFirstArea = 1, + #if PRIME == 2 + Unknown, + #endif + Done }; void InitializeState(uint WorldAssetId, TAreaId AreaId, uint AreaAssetId); - inline CPlayer* GetPlayer() const { return *GetField(this, 0x84C); } - inline EInitPhase GetInitPhase() const { return *GetField(this, 0xB3C); } - - inline CPlayerState *GetPlayerState() const { return mpPlayerState.RawPointer(); } + inline CPlayer* GetPlayer() const { return *GetField(this, ByVersion(0x84C, 0x14FC)); } + inline EInitPhase GetInitPhase() const { return *GetField(this, ByVersion(0xB3C, 0x16f0)); } + + inline CPlayerState *GetPlayerState() const { + static_assert(1 <= PRIME && PRIME <= 2, "Unknown game"); + if constexpr (PRIME == 1) { + return GetField>(this, 0x8b8)->RawPointer(); + } else { + return *GetField(this, 0x150c); + } + } inline CWorldLayerState *GetWorldLayerState() const { return worldLayerState.RawPointer(); } - CWorld *GetWorld() const { return *GetField(this, 0x850); }; - - CWorldTransManager *WorldTransManager() const { return GetField(this, 0x8c4); } + CWorld *GetWorld() const { return *GetField(this, ByVersion(0x850, 0x1604)); }; - CPlayer *Player() const { return *GetField(this, 0x84C); }; + CWorldTransManager *WorldTransManager() const { return GetField(this, ByVersion(0x8c4, 0x168C)); } - CObjectList *GetAllObjs() { return *GetField(this, 0x810); }; + CObjectList *GetAllObjs() { return *GetField(this, ByVersion(0x810, 2064)); }; - void SetShouldQuitGame(bool should) { GetField(this, 0xf94)->xf94_25_quitGame = should; } + void SetShouldQuitGame(bool should) { GetField(this, ByVersion(0xf94, 0x0))->xf94_25_quitGame = should; } void DrawWorld() const; void DrawDebugStuff() const; diff --git a/src/include/prime/CWorld.hpp b/src/include/prime/CWorld.hpp index 3967f6f..5e1c97f 100644 --- a/src/include/prime/CWorld.hpp +++ b/src/include/prime/CWorld.hpp @@ -3,6 +3,7 @@ #include "types.h" #include "GetField.hpp" +#include "VersionSelector.hpp" class CWorld { public: @@ -14,7 +15,7 @@ class CWorld { static void AuxGetAreaId(TAreaId* out, CWorld* obj, CAssetId areaAssetId); - TAreaId GetCurrentAreaId() const { return *(GetField(this, 0x68)); }; + TAreaId GetCurrentAreaId() const { return *GetField(this, ByVersion(0x68, 0x5c)); }; void SetPauseState(bool paused); }; diff --git a/src/include/prime/CWorldState.hpp b/src/include/prime/CWorldState.hpp index 400b459..de53872 100755 --- a/src/include/prime/CWorldState.hpp +++ b/src/include/prime/CWorldState.hpp @@ -3,6 +3,10 @@ #include #include +#include + +class CRelayTracker; +class CMapWorldInfo; class CWorldLayers { public: @@ -24,10 +28,12 @@ class CWorldState { public: uint32 x0_worldAssetId; TAreaId x4_areaId; - PADDING(0x0c); - CWorldLayerState **layerState; + rstl::rc_ptr relayTracker; + rstl::rc_ptr mapWorldInfo; + CAssetId desiredAreaAssetId; + rstl::rc_ptr layerState; - CWorldLayerState &GetLayerState(); + rstl::rc_ptr& GetLayerState(); void SetDesiredAreaAssetId(CAssetId id); }; diff --git a/src/prime-practice.cpp b/src/prime-practice.cpp index 7a43f83..79eaa05 100644 --- a/src/prime-practice.cpp +++ b/src/prime-practice.cpp @@ -115,10 +115,10 @@ void resetLayerStates(const CStateManager &manager) { } CWorldState &worldState = gameState->StateForWorld(currentMlvl); - CWorldLayerState *layerState = *worldState.layerState; + CWorldLayerState& layerState = *worldState.layerState; rstl::vector &srcLayers = intermediate->defaultLayerStates; - rstl::vector &destLayers = layerState->areaLayers; + rstl::vector &destLayers = layerState.areaLayers; if (srcLayers.len == destLayers.len) { for (int i = 0; i < srcLayers.len; i++) { @@ -188,12 +188,12 @@ void Hook_CMainFlow_AdvanceGameState(CMainFlow *pMainFlow, CArchitectureQueue &Q static bool sHasDoneInitialBoot = false; // Make sure the patch does not run twice if the player quits out to main menu - if (!sHasDoneInitialBoot && pMainFlow->GetGameState() == 7) { + if (!sHasDoneInitialBoot && pMainFlow->GetGameState() == EClientFlowStates::PreFrontEnd) { sHasDoneInitialBoot = true; CGameState *gameState = *((CGameState **) (0x80457798 + 0x134)); gameState->SetCurrentWorldId(0x39F2DE28); gameState->CurrentWorldState().SetDesiredAreaAssetId(0xC44E7A07); - pMainFlow->SetGameState(kCFS_Game, Queue); + pMainFlow->SetGameState(EClientFlowStates::Game, Queue); return; } else { pMainFlow->AdvanceGameState(Queue);