Actor: PlayerInfo/PlayerBase are game, GameConfig ksys

Every decomp user of PlayerInfo is game code, and PlayerBase sits right
above Player. GameConfig.h models the engine base that
links at GameConfig's slot in KingSystem/System.

(AI assisted using Claude Fable 5.1 and Claude Opus 5.5)
This commit is contained in:
Léo Lam
2026-09-28 03:39:30 +02:00
parent 34e57daf61
commit d8da4fc5f2
21 changed files with 316 additions and 304 deletions
+9
View File
@@ -1,2 +1,11 @@
add_subdirectory(AI)
add_subdirectory(Action)
target_sources(uking PRIVATE
actPlayerBase.cpp
actPlayerBase.h
actPlayerInfo.cpp
actPlayerInfo.h
actPlayerInfoBase.cpp
actPlayerInfoStub.cpp
)
+1
View File
@@ -0,0 +1 @@
#include "Game/Actor/Player/actPlayerBase.h"
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <prim/seadSafeString.h>
#include "KingSystem/ActorSystem/actActor.h"
namespace uking::act {
// TODO
class PlayerBase : public ksys::act::Actor {
public:
// FIXME: name for x and name+type for y
void switchEquipment(const sead::SafeString& slot, int frames, int x = -1,
const uintptr_t& y = {});
// FIXME: name for x
void setExtraLife(s32 extra_life, f32 x);
};
} // namespace uking::act
+134
View File
@@ -0,0 +1,134 @@
#include "Game/Actor/Player/actPlayerInfo.h"
#include "Game/Actor/Player/actPlayerBase.h"
#include "KingSystem/ActorSystem/actActorConstDataAccess.h"
#include "KingSystem/ActorSystem/actActorLinkConstDataAccess.h"
#include "KingSystem/ActorSystem/actBaseProc.h"
#include "KingSystem/ActorSystem/actBaseProcMgr.h"
#include "KingSystem/GameData/gdtCommonFlagsUtils.h"
#include "KingSystem/ksys.h"
namespace uking::act {
SEAD_SINGLETON_DISPOSER_IMPL(PlayerInfo)
PlayerInfo::PlayerInfo() = default;
PlayerInfo::~PlayerInfo() = default;
bool PlayerInfo::init() {
return true;
}
void PlayerInfo::resetPlayer(PlayerBase* player) {
if (mPlayerActor == player) {
mPlayerActor = nullptr;
ksys::setPlayerLink(nullptr);
}
}
bool PlayerInfo::acquireHorse(ksys::act::BaseProc* horse) {
return mHorseLink.acquire(horse, false);
}
void PlayerInfo::setHorseLink(const ksys::act::BaseProcLink& horse_link) {
mHorseLink = horse_link;
}
PlayerBase* PlayerInfo::getPlayer() const {
if (!mPlayerActor) {
return nullptr;
}
ksys::act::BaseProcMgr::instance()->isAccessingProcSafe(mPlayerActor, nullptr);
return mPlayerActor;
}
PlayerBase* PlayerInfo::getPlayer_() const {
if (!mPlayerActor) {
return nullptr;
}
ksys::act::BaseProcMgr::instance()->isAccessingProcSafe(mPlayerActor, nullptr);
return mPlayerActor;
}
s32 PlayerInfo::getMaxLifeFromPlayerActor() const {
return mPlayerActor ? mPlayerActor->getMaxLife() : 0;
}
void PlayerInfo::setMaxHeartValue(s32 quarter_hearts) {
ksys::gdt::setFlag_MaxHartValue(quarter_hearts);
mMaxHeartValue = static_cast<f32>(quarter_hearts);
}
u32 PlayerInfo::getMaxHeartValue() const {
// Return type is unsigned, but the conversion is signed
return static_cast<s32>(mMaxHeartValue);
}
void PlayerInfo::updateMaxHeartValueFromGameData() {
mMaxHeartValue = static_cast<f32>(ksys::gdt::getFlag_MaxHartValue());
}
void PlayerInfo::setLifeForPlayerActor(s32 life) {
if (mPlayerActor) {
*mPlayerActor->getLife() = life;
}
}
s32 PlayerInfo::getLifeFromPlayerActor() const {
if (!mPlayerActor) {
return 0;
}
auto* life = mPlayerActor->getLife();
return life ? *life : 1;
}
void PlayerInfo::recoverLife() {
setLifeForPlayerActor(getMaxLifeFromPlayerActor());
}
void PlayerInfo::setStaminaCurrentMax(f32 max_stamina) {
ksys::gdt::setFlag_StaminaCurrentMax(max_stamina);
mStaminaCurrentMax = max_stamina;
}
f32 PlayerInfo::getStaminaCurrentMax() const {
return mStaminaCurrentMax;
}
void PlayerInfo::updateStaminaCurrentMaxFromGameData() {
mStaminaCurrentMax = ksys::gdt::getFlag_StaminaCurrentMax();
}
void PlayerInfo::setStaminaMax(f32 max_stamina) {
ksys::gdt::setFlag_StaminaMax(max_stamina);
mStaminaMax = max_stamina;
}
f32 PlayerInfo::getStaminaMax() const {
return mStaminaMax;
}
void PlayerInfo::updateStaminaMaxFromGameData() {
mStaminaMax = ksys::gdt::getFlag_StaminaMax();
}
PlayerBase* PlayerInfo::getPlayerUnchecked() {
return mPlayerActor;
}
sead::Vector3f& PlayerInfo::getPlayerPos() {
ksys::act::ActorConstDataAccess accessor;
ksys::act::acquireActor(&mPlayerLink, &accessor);
accessor.debugLog(1, "getPlayerPos");
return mPlayerPos;
}
sead::Vector3f& PlayerInfo::getPlayerPosForPostCalc() {
ksys::act::ActorConstDataAccess accessor;
ksys::act::acquireActor(&mPlayerLink, &accessor);
accessor.debugLog(0, "getPlayerPosForPostCalc");
return mPlayerPosForPostCalc;
}
} // namespace uking::act
+123
View File
@@ -0,0 +1,123 @@
#pragma once
#include <heap/seadDisposer.h>
#include <math/seadVector.h>
#include "KingSystem/ActorSystem/actBaseProcLink.h"
#include "container/seadRingBuffer.h"
namespace ksys::act {
class Actor;
}
namespace uking::act {
class PlayerBase;
class PlayerInfoBase {
public:
PlayerInfoBase();
virtual ~PlayerInfoBase();
};
class PlayerInfo : public PlayerInfoBase {
SEAD_SINGLETON_DISPOSER(PlayerInfo)
PlayerInfo();
~PlayerInfo() override;
public:
ksys::act::BaseProcLink& getPlayerLink() { return mPlayerLink; }
bool init();
void setAndAcquirePlayer(PlayerBase* player); // requires PlayerOrEnemy and PlayerBase
void resetPlayer(PlayerBase* player);
bool acquireHorse(ksys::act::BaseProc* horse);
void setHorseLink(const ksys::act::BaseProcLink& horse_link);
PlayerBase* getPlayer() const;
PlayerBase* getPlayer_() const; // possibly duped by compiler?
ksys::act::Actor* getRiddenHorse() const; // requires PlayerBase vtable
void setMaxLifeForPlayerActor(s32 max_heart); // requires PlayerBase
s32 getMaxLifeFromPlayerActor() const;
void setMaxHeartValue(s32 quarter_hearts);
u32 getMaxHeartValue() const;
void updateMaxHeartValueFromGameData();
void setLifeForPlayerActor(s32 life);
s32 getLifeFromPlayerActor() const;
void updateCurrentHartFlagFromPlayerActor(); // TODO
void updateLifeAfterGameOver(); // requires a global flag
void
resetLifeToBeforeSwordPull(); // requires HeartDisplayMgr (0x25D6578) and PlayerBase vtable
void saveLifeInfoForSwordPull(); // requires PlayerBase vtable
void recoverLife();
void setStaminaCurrentMax(f32 max_stamina);
f32 getStaminaCurrentMax() const;
void updateStaminaCurrentMaxFromGameData();
void setStaminaMax(f32 max_stamina);
f32 getStaminaMax() const;
void updateStaminaMaxFromGameData();
void setMaxStaminaForPlayerActor(f32 max_stamina); // requires PlayerBase
f32 getMaxStaminaFromPlayerActor() const; // requires PlayerBase
void recoverStamina(); // requires PlayerBase
void recoverCondition(); // requires PlayerBase
PlayerBase* getPlayerUnchecked();
sead::Vector3f& getPlayerPos();
sead::Vector3f& getPlayerPosForPostCalc();
// TODO: name and PlayerBase vtable
sead::Vector3f& getPlayerM265();
private:
// These are probably debug stuff that were removed
class Info1 : public PlayerInfoBase {
public:
Info1();
~Info1() override;
} mInfo1;
class Info2 : public PlayerInfoBase {
public:
Info2();
~Info2() override;
} mInfo2;
class Info3 : public PlayerInfoBase {
public:
Info3();
~Info3() override;
} mInfo3;
class Info4 : public PlayerInfoBase {
public:
Info4();
~Info4() override;
} mInfo4;
class Info5 : public PlayerInfoBase {
public:
Info5();
~Info5() override;
} mInfo5;
class Info6 : public PlayerInfoBase {
public:
Info6();
~Info6() override;
} mInfo6;
class Info7 : public PlayerInfoBase {
public:
Info7();
~Info7() override;
} mInfo7;
PlayerBase* mPlayerActor = nullptr;
ksys::act::BaseProcLink mPlayerLink;
ksys::act::BaseProcLink mHorseLink;
sead::Vector3f mPlayerPos{0, 0, 0};
sead::Vector3f mPlayerPosForPostCalc{0, 0, 0};
f32 mMaxHeartValue = 0;
f32 mStaminaCurrentMax = 1000; // 1000 = 1 wheel
f32 mStaminaMax = 1000;
f32 mLifeBeforeSwordPull = 0;
f32 mExtraLifeBeforeSwordPull = 0;
sead::FixedRingBuffer<sead::Vector3f, 60> mPreviousPositions;
f32 _3a0 = 65535;
f32 _3a4 = 65535;
f32 _3a8 = -1;
};
KSYS_CHECK_SIZE_NX150(PlayerInfo, 0x3B0);
} // namespace uking::act
@@ -0,0 +1,6 @@
#include "Game/Actor/Player/actPlayerInfo.h"
namespace uking::act {
// these are separate from actPlayerInfo.cpp so clang doesn't inline/dedupe them
[[gnu::noinline]] PlayerInfoBase::PlayerInfoBase() = default;
[[gnu::noinline]] PlayerInfoBase::~PlayerInfoBase() = default;
} // namespace uking::act
@@ -0,0 +1,19 @@
#include "Game/Actor/Player/actPlayerInfo.h"
namespace uking::act {
// these are separate from actPlayerInfo.cpp so clang doesn't inline/dedupe them
PlayerInfo::Info1::Info1() = default;
PlayerInfo::Info1::~Info1() = default;
PlayerInfo::Info2::Info2() = default;
PlayerInfo::Info2::~Info2() = default;
PlayerInfo::Info3::Info3() = default;
PlayerInfo::Info3::~Info3() = default;
PlayerInfo::Info4::Info4() = default;
PlayerInfo::Info4::~Info4() = default;
PlayerInfo::Info5::Info5() = default;
PlayerInfo::Info5::~Info5() = default;
PlayerInfo::Info6::Info6() = default;
PlayerInfo::Info6::~Info6() = default;
PlayerInfo::Info7::Info7() = default;
PlayerInfo::Info7::~Info7() = default;
} // namespace uking::act
@@ -1,6 +1,6 @@
#include "Game/Actor/Query/queryComparePlayerHeart.h"
#include <evfl/Query.h>
#include "KingSystem/ActorSystem/actPlayerInfo.h"
#include "Game/Actor/Player/actPlayerInfo.h"
namespace uking::query {
@@ -9,7 +9,7 @@ ComparePlayerHeart::ComparePlayerHeart(const InitArg& arg) : ksys::act::ai::Quer
ComparePlayerHeart::~ComparePlayerHeart() = default;
int ComparePlayerHeart::doQuery() {
auto* pi = ksys::act::PlayerInfo::instance();
auto* pi = uking::act::PlayerInfo::instance();
if (pi == nullptr)
return 0;
@@ -1,6 +1,6 @@
#include "Game/Actor/Query/queryComparePlayerMaxHeart.h"
#include <evfl/Query.h>
#include "KingSystem/ActorSystem/actPlayerInfo.h"
#include "Game/Actor/Player/actPlayerInfo.h"
namespace uking::query {
@@ -9,7 +9,7 @@ ComparePlayerMaxHeart::ComparePlayerMaxHeart(const InitArg& arg) : ksys::act::ai
ComparePlayerMaxHeart::~ComparePlayerMaxHeart() = default;
int ComparePlayerMaxHeart::doQuery() {
auto* pi = ksys::act::PlayerInfo::instance();
auto* pi = uking::act::PlayerInfo::instance();
if (pi == nullptr)
return 0;
@@ -1,6 +1,6 @@
#include "Game/Actor/Query/queryComparePlayerMaxStamina.h"
#include <evfl/Query.h>
#include "KingSystem/ActorSystem/actPlayerInfo.h"
#include "Game/Actor/Player/actPlayerInfo.h"
namespace uking::query {
@@ -9,7 +9,7 @@ ComparePlayerMaxStamina::ComparePlayerMaxStamina(const InitArg& arg) : ksys::act
ComparePlayerMaxStamina::~ComparePlayerMaxStamina() = default;
int ComparePlayerMaxStamina::doQuery() {
auto* pi = ksys::act::PlayerInfo::instance();
auto* pi = uking::act::PlayerInfo::instance();
if (pi == nullptr)
return 0;
@@ -1,6 +1,6 @@
#include "Game/Actor/Query/queryComparePlayerOriginalHeart.h"
#include <evfl/Query.h>
#include "KingSystem/ActorSystem/actPlayerInfo.h"
#include "Game/Actor/Player/actPlayerInfo.h"
namespace uking::query {
@@ -10,7 +10,7 @@ ComparePlayerOriginalHeart::ComparePlayerOriginalHeart(const InitArg& arg)
ComparePlayerOriginalHeart::~ComparePlayerOriginalHeart() = default;
int ComparePlayerOriginalHeart::doQuery() {
using PlayerInfo = ksys::act::PlayerInfo;
using PlayerInfo = uking::act::PlayerInfo;
if (PlayerInfo::instance() == nullptr)
return 0;
+4 -4
View File
@@ -1,10 +1,11 @@
#include "Game/Actor/actPlayerCreateMgr.h"
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadStringBuilder.h>
#include "Game/Actor/Player/actPlayerBase.h"
#include "Game/Actor/Player/actPlayerInfo.h"
#include "Game/Actor/actPlayerCreateUtils.h"
#include "Game/Actor/actWeapon.h"
#include "Game/UI/uiPauseMenuDataMgr.h"
#include "KingSystem/ActorSystem/Profiles/actPlayerBase.h"
#include "KingSystem/ActorSystem/Profiles/actWeaponBase.h"
#include "KingSystem/ActorSystem/actActorConstDataAccess.h"
#include "KingSystem/ActorSystem/actActorCreator.h"
@@ -13,7 +14,6 @@
#include "KingSystem/ActorSystem/actInfoCommon.h"
#include "KingSystem/ActorSystem/actInfoData.h"
#include "KingSystem/ActorSystem/actInstParamPack.h"
#include "KingSystem/ActorSystem/actPlayerInfo.h"
#include "KingSystem/GameData/gdtCommonFlagsUtils.h"
namespace uking::act {
@@ -154,7 +154,7 @@ void CreatePlayerEquipActorMgr::requestCreateWeapon(s32 slot_idx, const sead::Sa
auto scope = mTracer.trace()->makeScope("requestCreateWeapon", caller, 1);
deleteLoadingProc(slot_idx);
auto* player = ksys::act::PlayerInfo::instance()->getPlayer();
auto* player = PlayerInfo::instance()->getPlayer();
sead::Matrix34f pos;
pos.makeT(player->getMtx().getTranslation());
@@ -213,7 +213,7 @@ void CreatePlayerEquipActorMgr::requestCreateArmor(s32 slot_idx, const sead::Saf
{
ksys::act::ActorConstDataAccess access;
ksys::act::acquireActor(&ksys::act::PlayerInfo::instance()->getPlayerLink(), &access);
ksys::act::acquireActor(&PlayerInfo::instance()->getPlayerLink(), &access);
sead::Vector3f pos;
access.getActorMtx().getTranslation(pos);
params->addPosition(pos);
+5 -5
View File
@@ -4,6 +4,8 @@
#include <limits>
#include <math/seadMathCalcCommon.h>
#include <prim/seadScopedLock.h>
#include "Game/Actor/Player/actPlayerBase.h"
#include "Game/Actor/Player/actPlayerInfo.h"
#include "Game/Actor/actPlayerCreateMgr.h"
#include "Game/Actor/actPlayerCreateUtils.h"
#include "Game/Actor/actWeapon.h"
@@ -12,14 +14,12 @@
#include "Game/Scene/gameScene.h"
#include "Game/UI/uiUtils.h"
#include "Game/gameItemUtils.h"
#include "KingSystem/ActorSystem/Profiles/actPlayerBase.h"
#include "KingSystem/ActorSystem/actActorConstDataAccess.h"
#include "KingSystem/ActorSystem/actActorHeapUtil.h"
#include "KingSystem/ActorSystem/actActorUtil.h"
#include "KingSystem/ActorSystem/actBaseProcLink.h"
#include "KingSystem/ActorSystem/actInfoCommon.h"
#include "KingSystem/ActorSystem/actInfoData.h"
#include "KingSystem/ActorSystem/actPlayerInfo.h"
#include "KingSystem/GameData/gdtCommonFlagsUtils.h"
#include "KingSystem/GameData/gdtManager.h"
#include "KingSystem/GameData/gdtSpecialFlagNames.h"
@@ -315,7 +315,7 @@ void PauseMenuDataMgr::initForNewSave() {
mCanSeeHealthBar = false;
mEquippedWeapons.fill({});
auto* player = ksys::act::PlayerInfo::instance()->getPlayer();
auto* player = uking::act::PlayerInfo::instance()->getPlayer();
if (player) {
player->switchEquipment(getDefaultEquipment(EquipmentSlot::WeaponRight), 1);
player->switchEquipment(getDefaultEquipment(EquipmentSlot::WeaponLeft), 1);
@@ -1357,7 +1357,7 @@ void PauseMenuDataMgr::removeItem(const sead::SafeString& name) {
void PauseMenuDataMgr::removeWeaponIfEquipped(const sead::SafeString& name) {
const auto lock = sead::makeScopedLock(mCritSection);
if (!ksys::act::PlayerInfo::instance()->getPlayer())
if (!uking::act::PlayerInfo::instance()->getPlayer())
return;
const auto& items = getItems();
@@ -1502,7 +1502,7 @@ void PauseMenuDataMgr::createPlayerEquipment() {
}
}
auto* player = ksys::act::PlayerInfo::instance()->getPlayer();
auto* player = uking::act::PlayerInfo::instance()->getPlayer();
s32 slot = 0; // <- this is required to match
for (u64 i = 0; i != equipment_items.size(); slot = s32(++i)) {