diff options
| author | Léo Lam <leo@leolam.fr> | 2020-06-05 17:09:06 +0200 |
|---|---|---|
| committer | Léo Lam <leo@leolam.fr> | 2020-08-18 22:50:25 +0200 |
| commit | 2de366be0fa75e571c605e017b5604bccbdb75bf (patch) | |
| tree | b8044fc96bba792b1875067032da2fd4498a44a3 /src/KingSystem/ActorSystem/actBaseProc.cpp | |
Initial commit
Diffstat (limited to 'src/KingSystem/ActorSystem/actBaseProc.cpp')
| -rw-r--r-- | src/KingSystem/ActorSystem/actBaseProc.cpp | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/src/KingSystem/ActorSystem/actBaseProc.cpp b/src/KingSystem/ActorSystem/actBaseProc.cpp new file mode 100644 index 00000000..01ccc5d4 --- /dev/null +++ b/src/KingSystem/ActorSystem/actBaseProc.cpp @@ -0,0 +1,409 @@ +#include "KingSystem/ActorSystem/actBaseProc.h" +#include "KingSystem/ActorSystem/actBaseProcJobHandler.h" +#include "KingSystem/ActorSystem/actBaseProcLinkDataMgr.h" +#include "KingSystem/ActorSystem/actBaseProcMgr.h" +#include "KingSystem/ActorSystem/actBaseProcUnit.h" +#include "KingSystem/Terrain/teraSystem.h" + +namespace ksys::act { + +BaseProcLink::BaseProcLink() = default; + +BaseProc::BaseProc(const CreateArg& arg) + : mName(arg.actor_name), mPriority(arg.class_info->priority) { + BaseProcMgr* mgr = BaseProcMgr::instance(); + mgr->generateProcId(&mId); + mgr->registerProc(*this); + + mJobHandlers.fill(nullptr); + + BaseProcLinkDataMgr::instance()->acquireLink(this); +} + +BaseProcMapNode::~BaseProcMapNode() = default; + +BaseProc::~BaseProc() { + unlinkCalcChild_(); + unlinkCalcParent_(); + + if (mDeleteListNode.isLinked()) + BaseProcMgr::instance()->eraseFromUpdateStateList(*this); +} + +bool BaseProc::init(sead::Heap* heap, bool sleep_after_init) { + InitContext context; + context.sleep_after_init = sleep_after_init; + context.result = InitResult::Skipped; + + if (shouldInit_()) { + PrepareArg arg; + if (prepareInit_(heap, arg)) { + if (context.result != InitResult::Failed) + context.result = init_(); + } else { + context.result = InitResult::Failed; + } + } + + finalizeInit_(&context); + return context.result == InitResult::Ok && mStateFlags.isOff(StateFlags::RequestDelete); +} + +bool BaseProc::deleteLater(DeleteReason reason) { + if (isDeletedOrDeleting()) + return false; + + // Debug leftovers? + mName.cstr(); + mName.cstr(); + + BaseProcMgr* mgr = BaseProcMgr::instance(); + const bool is_high_prio = mgr->isHighPriorityThread(); + + if (!is_high_prio) { + mgr->getProcUpdateStateListCS().lock(); + if (isDeletedOrDeleting()) { + mgr->getProcUpdateStateListCS().unlock(); + return false; + } + } + + if (!BaseProcMgr::instance()->addToUpdateStateList(*this)) + onDeleteRequested_(reason); + + if (!is_high_prio) + mgr->getProcUpdateStateListCS().unlock(); + + return true; +} + +BaseProc::InitResult BaseProc::init_() { + return InitResult::Ok; +} + +bool BaseProc::shouldInit_() { + return true; +} + +void BaseProc::finalizeInit_(InitContext* context) { + if (mState == State::Delete) + return; + + if (context->result != InitResult::Ok) { + deleteLater(DeleteReason::_1); + return; + } + + if (!mProcUnit) { + if (context->sleep_after_init) + sleep(SleepWakeReason::_0); + else + wakeUp(SleepWakeReason::_0); + } else { + sleep(SleepWakeReason::_0); + if (!mProcUnit->setProc(this)) + deleteLater(DeleteReason::_2); + } +} + +BaseProc::PreDeletePrepareResult BaseProc::prepareForPreDelete_() { + return PreDeletePrepareResult::Done; +} + +// NON_MATCHING: branching +bool BaseProc::startPreparingForPreDelete_() { + if (mDeleteListNode.isLinked()) + return false; + + return !mBaseProcLinkData || mBaseProcLinkData->refCount() <= 0 || + BaseProcMgr::instance()->getUnk3() || tera::checkTeraSystemStatus(); +} + +void BaseProc::destruct_(int should_destruct) { + if (should_destruct == 1) { + BaseProcMgr::instance()->eraseFromPreDeleteList(*this); + BaseProcMgr::instance()->unregisterProc(*this); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundefined-bool-conversion" + // Yes, this check looks strange. + if (this) + delete this; +#pragma clang diagnostic pop + } +} + +void BaseProc::onEnterCalc_() {} + +void BaseProc::onDeleteRequested_(BaseProc::DeleteReason) {} + +void BaseProc::onSleepRequested_(BaseProc::SleepWakeReason) {} + +void BaseProc::onWakeUpRequested_(BaseProc::SleepWakeReason) {} + +void BaseProc::onEnterDelete_() {} + +void BaseProc::onEnterSleep_() {} + +void BaseProc::preDelete3_(bool*) {} + +bool BaseProc::prepareInit_(sead::Heap*, BaseProc::PrepareArg&) { + return true; +} + +void BaseProc::onPreDeleteStart_(PrepareArg&) {} + +void BaseProc::preDelete2_(bool*) {} + +void BaseProc::preDelete1_() {} + +// NON_MATCHING: branching +bool BaseProc::isSpecialJobType_(JobType type) { + return BaseProcMgr::instance()->isSpecialJobType(type) || isSpecialJobTypeForThisActor_(type); +} + +bool BaseProc::canWakeUp_() { + return true; +} + +void BaseProc::queueExtraJobPush_(JobType type) { + if (!isDeletedOrDeleting()) + BaseProcMgr::instance()->queueExtraJobPush(&mJobHandlers[int(type)]->getLink()); +} + +bool BaseProc::hasJobType_(JobType type) { + return mJobHandlers[int(type)] != nullptr; +} + +void BaseProc::afterUpdateState_() { + mFlags.reset(Flags::_80); + mFlags.reset(Flags::_100); +} + +bool BaseProc::shouldSkipJobPush_(JobType) { + return false; +} + +void BaseProc::onJobPush1_(JobType) {} + +void BaseProc::onJobPush2_(JobType) {} + +// NON_MATCHING: branching +bool BaseProc::processStateUpdate(u8 counter) { + const bool delete_requested = mStateFlags.isOn(StateFlags::RequestDelete); + const bool initialized = mFlags.isOn(Flags::Initialized); + + if (delete_requested) { + // Deletion cannot start until the reference count is 0. + if (initialized && mRefCount.compareExchange(0, -1)) { + if (mState != State::Delete) { + BaseProcMgr::instance()->eraseJobs(*this); + BaseProcMgr::instance()->addToPreDeleteList(*this); + startDelete_(); + } + mStateFlags.makeAllZero(); + return true; + } + // Try the deletion again later. + mStateFlags.setDirect(StateFlags::RequestDelete); + return false; + } + + sead::TypedBitFlag<StateFlags> new_flags{mStateFlags}; + + if (initialized) { + if (new_flags.isOn(StateFlags::RequestDeleteProcUnit)) + unlinkProcUnit_(); + + if (mStateFlags.isOn(StateFlags::_4000)) { + if (shouldClearStateFlag4000_()) + new_flags.makeAllZero(); + else + new_flags.setDirect(StateFlags::_4000); + } else { + new_flags.makeAllZero(); + } + + const auto check_calc_sleep = [&] { + const bool sleep_requested = mStateFlags.isOn(StateFlags::RequestSleep); + const State state = mState; + if (sleep_requested) { + handleSleepRequest_(); + if (mStateFlags.isAnyOn({StateFlags::RequestWakeUp, StateFlags::_2})) { + new_flags.setDirect(mStateFlags.getDirect() & + (u32(StateFlags::RequestWakeUp) | u32(StateFlags::_2))); + } + return true; + } + + const sead::TypedBitFlag<StateFlags> flags{mStateFlags}; + + if (state == State::Calc) { + if (flags.isOn(StateFlags::RequestChangeCalcJobPriority)) + handleJobPriorityChangeRequest_(); + return true; + } + + if (!flags.isAnyOn({StateFlags::RequestWakeUp, StateFlags::_2})) + return true; + + if (canWakeUpOrFlagsSet_()) { + handleWakeUpRequest_(); + return true; + } + + return mStateFlags.isOn(StateFlags::RequestSleep); + }; + + if (!check_calc_sleep()) { + new_flags.setDirect(mStateFlags.getDirect() & + (u32(StateFlags::RequestWakeUp) | u32(StateFlags::_2))); + } + + if (mStateFlags.isOn(StateFlags::RequestDelete)) { + new_flags.set(StateFlags::RequestDelete); + mStateFlags.setDirect(new_flags.getDirect()); + return false; + } + + if (mStateFlags.isOn(StateFlags::RequestSleep)) + handleSleepRequest_(); + + if (mStateFlags.isOn(StateFlags::RequestResetChild)) + unlinkCalcChild_(); + + if (mStateFlags.isOn(StateFlags::RequestResetParent)) + unlinkCalcParent_(); + + if (mStateFlags.isOn(StateFlags::RequestSetChild)) + loadNewCalcChild_(counter); + + if (mStateFlags.isOn(StateFlags::RequestSetParent)) + loadNewCalcParent_(counter); + } + + const bool ret = new_flags.isZero(); + mStateFlags = new_flags; + return ret; +} + +void BaseProc::processPreDelete() { + if (!mFlags.isOn(Flags::Initialized)) + return; + + if (mFlags.isOn(Flags::PreDeleteFailed)) { + // Try again. + if (BaseProcMgr::instance()->requestPreDelete(*this)) { + mFlags.set(Flags::PreDeleteStarted); + mFlags.reset(Flags::PreDeleteFailed); + } + + } else if (!mFlags.isOn(Flags::PreDeleteStarted) && startPreparingForPreDelete_()) { + mFlags.set(Flags::PreDeleting); + if (prepareForPreDelete_() == PreDeletePrepareResult::Done) { + BaseProcLinkDataMgr::instance()->releaseLink(this); + PrepareArg arg; + onPreDeleteStart_(arg); + + if (BaseProcMgr::instance()->requestPreDelete(*this)) + mFlags.set(Flags::PreDeleteStarted); + else + mFlags.set(Flags::PreDeleteFailed); + } + } +} + +void BaseProc::doPreDelete(bool* do_not_destruct_immediately) { + preDelete1_(); + preDelete2_(do_not_destruct_immediately); + preDelete3_(do_not_destruct_immediately); + + if (*do_not_destruct_immediately) + return; + + mFlags.set(Flags::Destructed); + destruct_(1); + BaseProcMgr::instance()->decrementPendingDeletions(); +} + +void BaseProc::unlinkProcUnit_() { + if (mProcUnit) { + mProcUnit->unlinkProc(this); + mProcUnit = nullptr; + } +} + +void BaseProc::unlinkCalcChild_() { + if (mConnectedCalcChild) { + mConnectedCalcChild->mConnectedCalcParent = nullptr; + mConnectedCalcChild = nullptr; + } +} + +void BaseProc::unlinkCalcParent_() { + auto parent = mConnectedCalcParent; + if (parent && parent->mConnectedCalcChild) { + parent->mConnectedCalcChild->mConnectedCalcParent = nullptr; + parent->mConnectedCalcChild = nullptr; + } +} + +void BaseProc::loadNewCalcChild_(u8 counter) { + auto child = mConnectedCalcChildNew; + if (child && !child->isDeletedOrDeleting() && !mConnectedCalcChild && + !child->mConnectedCalcParent && !isDeletedOrDeleting() && + child->mStateFlags.isOff(StateFlags::RequestDelete)) { + mConnectedCalcChild = child; + child->mConnectedCalcParent = this; + mCounter = counter; + } + mConnectedCalcChildNew = nullptr; +} + +void BaseProc::loadNewCalcParent_(u8 counter) { + auto parent = mConnectedCalcParentNew; + if (parent && !parent->isDeletedOrDeleting() && !parent->mConnectedCalcChild && + !mConnectedCalcParent && parent->mStateFlags.isOff(StateFlags::RequestDelete) && + !isDeletedOrDeleting()) { + parent->mConnectedCalcChild = this; + mConnectedCalcParent = parent; + parent->mCounter = counter; + } + mConnectedCalcParentNew = nullptr; +} + +void BaseProc::handleSleepRequest_() { + if (isDeletedOrDeleting() || mState == State::Sleep) + return; + + mState = State::Sleep; + onEnterSleep_(); + BaseProcMgr::instance()->eraseJobs(*this); +} + +void BaseProc::handleWakeUpRequest_() { + if (isDeletedOrDeleting()) + return; + + onEnterCalc_(); + + if (!mStateFlags.isOff(StateFlags::RequestDelete)) + return; + + mState = State::Calc; + BaseProcMgr::instance()->pushJobs(*this); + unlinkProcUnit_(); +} + +void BaseProc::handleJobPriorityChangeRequest_() { + for (u32 i = 0; i < BaseProcMgr::instance()->getNumJobTypes(); ++i) { + if (!mJobHandlers[i] || !mJobHandlers[i]->getLink().hasPriorityChange()) + continue; + + BaseProcMgr::instance()->eraseJob(*this, JobType(i)); + mJobHandlers[i]->getLink().loadNewPriority(); + mJobHandlers[i]->getLink().loadNewPriority2(); + BaseProcMgr::instance()->pushJob(*this, JobType(i)); + } +} + +} // namespace ksys::act |
