botw/src/KingSystem/ActorSystem/actBaseProc.h

337 lines
11 KiB
C++

#pragma once
#include <basis/seadTypes.h>
#include <container/seadListImpl.h>
#include <container/seadSafeArray.h>
#include <container/seadTreeMap.h>
#include <math/seadMathCalcCommon.h>
#include <prim/seadBitFlag.h>
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadSafeString.h>
#include <prim/seadTypedBitFlag.h>
#include <thread/seadAtomic.h>
#include "KingSystem/ActorSystem/actBaseProcJob.h"
#include "KingSystem/ActorSystem/actBaseProcMap.h"
#include "KingSystem/Utils/StrTreeMap.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::act {
class ActorLinkConstDataAccess;
class BaseProc;
class BaseProcLinkData;
class BaseProcJobHandler;
class BaseProcUnit;
/// Actor base class that encapsulates all the low-level actor lifetime logic.
class BaseProc {
public:
enum class State : u8 {
/// The actor is constructed, but not fully initialized yet.
Init = 0,
/// The actor is active.
Calc = 1,
/// The actor is sleeping: its update jobs won't be run.
Sleep = 2,
/// The actor is scheduled for deletion.
Delete = 3,
};
enum class DeleteReason : u32 {
_0 = 0,
_1 = 1,
_2 = 2,
BaseProcMgrDeleteAll = 4,
_f = 0xf,
_15 = 0x15,
_16 = 0x16,
_17 = 0x17,
_18 = 0x18,
_19 = 0x19,
};
enum class SleepWakeReason : u32 {
_0 = 0,
};
struct ClassInfo {
sead::SafeString name;
u8 priority;
};
KSYS_CHECK_SIZE_NX150(ClassInfo, 0x18);
struct CreateArg {
const ClassInfo* class_info;
void* _10;
u32 _14;
u32 _18;
sead::SafeString actor_name;
};
KSYS_CHECK_SIZE_NX150(CreateArg, 0x28);
struct PreDeleteArg {
bool do_not_destruct_immediately = false;
};
explicit BaseProc(const CreateArg& arg);
virtual ~BaseProc();
SEAD_RTTI_BASE(BaseProc)
/// @return true iff state is Calc and the actor is not being deleted.
bool init(sead::Heap* heap, bool sleep_after_init);
/// Put this actor to sleep. The request is queued.
void sleep(SleepWakeReason reason);
/// Wake up this actor. The request is queued.
void wakeUp(SleepWakeReason reason);
/// Delete this actor. The request is queued.
bool deleteLater(DeleteReason reason);
void freeLinkData();
u32 getId() const { return mId; }
const sead::SafeString& getName() const { return mName; }
u8 getPriority() const { return mPriority; }
void setPriority(u8 priority) { mPriority = priority; }
State getState() const { return mState; }
bool isInit() const { return mState == State::Init; }
bool isCalc() const { return mState == State::Calc; }
bool isSleep() const { return mState == State::Sleep; }
bool isDelete() const { return mState == State::Delete; }
bool isDeletedOrDeleting() const {
return mState == State::Delete || mStateFlags.isOn(StateFlags::RequestDelete);
}
bool isDeleteOrInvalid() const { return mState >= act::BaseProc::State::Delete; }
/// For BaseProcLink or ActorLinkConstDataAccess.
bool acquire(ActorLinkConstDataAccess& accessor);
BaseProcLinkData* getBaseProcLinkData() const { return mBaseProcLinkData; }
/// For BaseProcLink or ActorLinkConstDataAccess.
void release();
BaseProc* getConnectedCalcParent() const;
bool setConnectedCalcParent(BaseProc* parent, bool delete_parent_on_delete);
void resetConnectedCalcParent(bool clear_existing_set_request);
BaseProc* getConnectedCalcChild() const;
bool setConnectedCalcChild(BaseProc* child, bool delete_child_on_delete);
void resetConnectedCalcChild(bool clear_existing_set_request);
bool isSpecialJobType(JobType type);
bool shouldSkipJobPush(JobType type);
void setJobPriority(u8 actorparam_priority, JobType type);
void setJobPriority2(u8 actorparam_priority, JobType type);
void setCreatePriorityState1();
void setCreatePriorityState2();
void onJobPush(JobType type) {
onJobPush1_(type);
onJobPush2_(type);
}
/// Actually pre-delete the actor. Called from BaseProcDeleter.
void doPreDelete(const PreDeleteArg& arg);
/// Set the BaseProcUnit. Only for use by BaseProcCreateTask.
void setUnitForBaseProcCreateTask(BaseProcUnit* unit) { mProcUnit = unit; }
void setInitializedFlag() { mFlags.set(Flags::Initialized); }
bool requestDeleteProcUnit() { return setStateFlag(StateFlags::RequestDeleteProcUnit); }
bool isInitialized() const { return mFlags.isOn(Flags::Initialized); }
bool isDeleting() const { return mFlags.isOn(Flags::PreDeleteStarted); }
bool isDeleteRequested() const { return mStateFlags.isOn(StateFlags::RequestDelete); }
protected:
friend class BaseProcLinkDataMgr;
friend class BaseProcMgr;
enum class Flags : u32 {
Initialized = 1,
PreDeleteStarted = 2,
PreDeleteFailed = 4,
Destructed = 8,
DoNotDelete = 0x10,
DeleteChildOnDelete = 0x20,
DeleteParentOnDelete = 0x40,
_80 = 0x80,
_100 = 0x100,
PreDeleting = 0x200,
SleepWakeReason0 = 0x400,
SleepWakeReason1 = 0x800,
SleepWakeReason2 = 0x1000,
SleepWakeReason3 = 0x2000,
SleepWakeReasonAny =
SleepWakeReason0 | SleepWakeReason1 | SleepWakeReason2 | SleepWakeReason3,
};
enum class StateFlags : u32 {
RequestDelete = 1,
_2 = 2,
RequestSleep = 4,
RequestWakeUp = 8,
_a = _2 | RequestWakeUp,
RequestChangeCalcJobPriority = 0x10,
_20 = 0x20,
_40 = 0x40,
_80 = 0x80,
RequestSetParent = 0x100,
RequestSetChild = 0x200,
RequestResetParent = 0x400,
RequestResetChild = 0x800,
_1000 = 0x1000,
_2000 = 0x2000,
_4000 = 0x4000,
RequestDeleteProcUnit = 0x8000,
};
enum class InitResult : u32 {
Ok = 1,
Failed = 2,
Skipped = 3,
};
enum class PreDeletePrepareResult : u32 {
NotDone = 0,
Done = 1,
};
enum class IsSpecialJobTypeResult {
No = 0,
Yes = 1,
_2 = 2,
};
struct InitContext {
InitResult result;
bool sleep_after_init;
};
struct PrepareArg {
bool _0 = false;
int _4;
};
/// Initialize the actor.
/// @return Ok to keep the actor alive, anything else to kill it?
virtual InitResult init_();
/// @return whether prepareInit_ and init_ should be called.
virtual bool shouldInit_();
/// Finalize the initialization; the actor is deleted if the result is not Ok.
virtual void finalizeInit_(InitContext* context);
/// Called every tick to prepare for pre-delete (after startPreparingForPreDelete_).
virtual PreDeletePrepareResult prepareForPreDelete_();
/// Called to start preparing for pre-delete. Return true to allow pre-delete to go ahead.
virtual bool startPreparingForPreDelete_();
/// Destructs this actor if should_destruct is 1.
/// @warning The actor must NOT be used after calling this function.
virtual void destruct_(int should_destruct);
/// Called when entering the Calc state.
virtual void onEnterCalc_();
/// Called when a new delete operation is queued.
virtual void onDeleteRequested_(DeleteReason reason);
/// Called when a new sleep operation is queued.
virtual void onSleepRequested_(SleepWakeReason reason);
/// Called when a new wakeup operation is queued.
virtual void onWakeUpRequested_(SleepWakeReason reason);
virtual bool shouldClearStateFlag4000_() { return true; }
/// Called when entering the Delete state.
virtual void onEnterDelete_();
/// Called when entering the Sleep state.
virtual void onEnterSleep_();
/// Called to actually pre-delete (third and final callback).
virtual void preDelete3_(const PreDeleteArg& arg);
virtual bool prepareInit_(sead::Heap* heap, PrepareArg& arg);
/// Called when pre-delete actually starts (after preparation, before requesting it).
virtual void onPreDeleteStart_(PrepareArg&);
/// Called to actually pre-delete (second callback).
virtual void preDelete2_(const PreDeleteArg& arg);
/// Called to actually pre-delete (first callback).
virtual void preDelete1_();
virtual IsSpecialJobTypeResult isSpecialJobType_(JobType type);
virtual bool canWakeUp_();
virtual void queueExtraJobPush_(JobType type, int idx);
virtual bool hasJobType_(JobType type);
/// Called after processStateUpdate() is called for all actors in the update state list.
virtual void afterUpdateState_();
virtual bool shouldSkipJobPush_(JobType type);
/// Called before pushing a job with the specified job type (first callback).
virtual void onJobPush1_(JobType type);
/// Called before pushing a job with the specified job type (second and final callback).
virtual void onJobPush2_(JobType type);
bool processStateUpdate(u8 counter);
void processPreDelete();
void startDelete_();
/// Called from BaseProcMgr when a job for this process is invoked.
void jobInvoked(JobType type);
bool isSpecialJobTypeForThisActor_(JobType type) const {
return mSpecialJobTypesMask.isOnBit(int(type));
}
BaseProcJobHandler*& getJobHandler(JobType type) { return mJobHandlers[int(type)]; }
BaseProcJobHandler* getJobHandler(JobType type) const { return mJobHandlers[int(type)]; }
bool setStateFlag(u32 flag_bit);
bool setStateFlag(StateFlags flag) { return setStateFlag(sead::log2(u32(flag))); }
bool x00000071011ba9fc();
sead::FixedSafeString<64> mName;
u32 mId = -1;
State mState = State::Init;
u8 mPriority = 0;
u8 mCreatePriorityState = 0;
u8 mCounter = 0;
BaseProcLinkData* mBaseProcLinkData = nullptr;
sead::BitFlag16 mSkippedJobTypesMask;
sead::BitFlag16 mSpecialJobTypesMask;
sead::TypedBitFlag<Flags, sead::Atomic<u32>> mFlags;
sead::TypedBitFlag<StateFlags, sead::Atomic<u32>> mStateFlags;
BaseProc* mConnectedCalcParent = nullptr;
BaseProc* mConnectedCalcChild = nullptr;
BaseProc* mConnectedCalcParentNew = nullptr;
BaseProc* mConnectedCalcChildNew = nullptr;
sead::SafeArray<BaseProcJobHandler*, 7> mJobHandlers{};
sead::Delegate1R<BaseProc, void*, bool> mInvoker;
sead::ListNode mPreDeleteListNode;
sead::ListNode mUpdateStateListNode;
BaseProcMapNode mMapNode{this};
BaseProcUnit* mProcUnit = nullptr;
sead::Atomic<s32> mRefCount = 0;
private:
void unlinkProcUnit_();
void unlinkCalcChild_();
void unlinkCalcParent_();
void loadNewCalcChild_(u8 counter);
void loadNewCalcParent_(u8 counter);
void handleSleepRequest_();
void handleWakeUpRequest_();
void handleJobPriorityChangeRequest_();
void setJobPriorityDuringCalc_(BaseProcJobHandler*& handler, JobType type);
bool canWakeUpOrFlagsSet_() {
return mFlags.isOn(Flags::_80) ? mFlags.isOn(Flags::_100) : canWakeUp_();
}
};
KSYS_CHECK_SIZE_NX150(BaseProc, 0x180);
} // namespace ksys::act