#include "KingSystem/ActorSystem/actBaseProcMgr.h" #include #include #include #include "KingSystem/ActorSystem/actActorSystem.h" #include "KingSystem/ActorSystem/actBaseProcDeleter.h" #include "KingSystem/ActorSystem/actBaseProcHeapMgr.h" #include "KingSystem/ActorSystem/actBaseProcInitializer.h" #include "KingSystem/ActorSystem/actBaseProcJobHandler.h" #include "KingSystem/ActorSystem/actBaseProcJobQue.h" #include "KingSystem/ActorSystem/actBaseProcLink.h" namespace ksys::act { SEAD_SINGLETON_DISPOSER_IMPL(BaseProcMgr) BaseProcMgr::BaseProcMgr() { mProcPreDeleteList.initOffset(offsetof(BaseProc, mPreDeleteListNode)); mProcUpdateStateList.initOffset(offsetof(BaseProc, mUpdateStateListNode)); } BaseProcMgr::~BaseProcMgr() { if (mProcJobQue) { delete mProcJobQue; mProcJobQue = nullptr; } mJobLists.freeBuffer(); if (mProcInitializer) { delete mProcInitializer; mProcInitializer = nullptr; } if (mProcDeleter) { delete mProcDeleter; mProcDeleter = nullptr; } BaseProcHeapMgr::deleteInstance(); } // NON_MATCHING: mJobLists.allocBufferAssert - BaseProcJobLists ctor void BaseProcMgr::init(sead::Heap* heap, s32 num_job_types, u32 main_thread_id, u32 havok_thread_id1, u32 havok_thread_id2, const BaseProcInitializerArgs& initializer_args) { mProcJobQue = new (heap) BaseProcJobQue; mProcJobQue->init(heap); mJobLists.allocBufferAssert(num_job_types, heap); mProcInitializer = new (heap) BaseProcInitializer; mProcInitializer->init(heap, initializer_args); mProcDeleter = new (heap) BaseProcDeleter; BaseProcDeleter::InitArg deleter_arg; deleter_arg.heap = heap; deleter_arg.task_queue = mProcInitializer->getTaskQueue(); deleter_arg.task_queue_size = 2048; mProcDeleter->init(deleter_arg); mMainThreadId = main_thread_id; mHavokThreadId1 = havok_thread_id1; mHavokThreadId2 = havok_thread_id2; BaseProcHeapMgr::createInstance(heap); BaseProcLinkDataMgr::createInstance(heap); } void BaseProcMgr::generateProcId(u32* id) { *id = mCreatedProcCounter.increment(); } void BaseProcMgr::registerProc(BaseProc& proc) { auto lock = sead::makeScopedLock(mProcMapCS); proc.mMapNode.key().setKey(proc.mName); mProcMap.insert(&proc.mMapNode); } void BaseProcMgr::unregisterProc(BaseProc& proc) { if (!proc.mMapNode.isInserted()) return; auto lock = sead::makeScopedLock(mProcMapCS); mProcMap.erase(&proc.mMapNode); } bool BaseProcMgr::requestPreDelete(BaseProc& proc) { return mProcDeleter->requestPreDelete(&proc); } void BaseProcMgr::requestUnloadActorParam(ActorParam* param) { return mProcDeleter->requestUnloadActorParam(param); } void BaseProcMgr::addToPreDeleteList(BaseProc& proc) { auto lock = sead::makeScopedLock(mProcPreDeleteListCS); mProcPreDeleteList.pushFront(&proc); } void BaseProcMgr::eraseFromPreDeleteList(BaseProc& proc) { auto lock = sead::makeScopedLock(mProcPreDeleteListCS); if (mProcPreDeleteList.isNodeLinked(&proc)) mProcPreDeleteList.erase(&proc); } void BaseProcMgr::pushJob(BaseProc& proc, JobType type) { if (proc.isSleep() || !proc.hasJobType_(type)) return; getJobLists(type).pushJob(proc.getJobHandler(type)->getLink()); } void BaseProcMgr::pushJobs(BaseProc& proc) { for (u32 i = 0; i < u32(mJobLists.size()); ++i) { pushJob(proc, JobType(i)); } } void BaseProcMgr::eraseJob(BaseProc& proc, JobType type) { auto* handler = proc.getJobHandler(type); if (handler) getJobLists(type).eraseJob(handler->getLink()); } void BaseProcMgr::eraseJobs(BaseProc& proc) { for (u32 i = 0; i < u32(mJobLists.size()); ++i) { auto* handler = proc.getJobHandler(JobType(i)); if (handler) mJobLists[i].eraseJob(handler->getLink()); } } void BaseProcMgr::doAddToUpdateStateList_(BaseProc& proc) { if (mProcUpdateStateList.isNodeLinked(&proc)) return; if (proc.mCreatePriorityState == 1) { proc.mCreatePriorityState = 0; mProcUpdateStateList.pushFront(&proc); } else { mProcUpdateStateList.pushBack(&proc); } } void BaseProcMgr::eraseFromUpdateStateList(BaseProc& proc) { auto lock = sead::makeScopedLock(mProcUpdateStateListCS); if (mProcUpdateStateList.isNodeLinked(&proc)) mProcUpdateStateList.erase(&proc); } void BaseProcMgr::processPreDeleteList() { mStatus = Status::ProcessingPreDeleteList; auto lock = sead::makeScopedLock(mProcPreDeleteListCS); for (auto& proc : mProcPreDeleteList.robustRange()) proc.processPreDelete(); mStatus = Status::Idle; } BaseProcMgr::ExtraJobLinkArray& BaseProcMgr::getExtraJobs() { return mExtraJobLinkArrays.ref()[mCurrentExtraJobArrayIdx]; } void BaseProcMgr::swapExtraJobArray() { mCurrentExtraJobArrayIdx ^= 1; getExtraJobs().clear(); } bool BaseProcMgr::checkJobPushState() const { return mEnableExtraJobPush && mUnk4 != 1; } void BaseProcMgr::pushJobQueues(sead::WorkerMgr* mgr, JobType type, bool x) { if (!checkJobPushState()) return; mJobType = type; const auto type_ = mJobType; mStatus = Status::ProcessingActorJobs; mIsPushingJobs = true; mUnk2 = x; int i = 0; do { mPushActorJobType3InsteadOf6 = false; auto& lists = getJobLists(type_); for (int priority = 0; priority < 8; ++priority) { mCurrentlyProcessingPrio = priority; if (mProcJobQue->pushJobQueue(mgr, &lists, priority, type_)) { mgr->run(); mgr->sync(); } } mCurrentlyProcessingPrio = 8; ++i; } while (mPushActorJobType3InsteadOf6 && i < 8); mIsPushingJobs = false; mUnk2 = false; mStatus = Status::Idle; mJobType = JobType::Invalid; } bool BaseProcMgr::pushExtraJobsEx(sead::FixedSizeJQ* jq, JobType type, u8 priority, bool x, bool y) { if (!checkJobPushState()) return false; if (x) { mUnk2 = y; auto* queue = mProcJobQue; mStatus = Status::ProcessingActorJobs; mJobType = type; mCurrentlyProcessingPrio = priority; queue->clear(); } const auto type_ = JobType(u8(type)); mIsPushingJobs = true; mProcJobQue->pushExtraJobs(jq, &getJobLists(type_), priority, type_); return true; } bool BaseProcMgr::pushExtraJobsForCurrentTypeAndPrio(sead::FixedSizeJQ* jq, ExtraJobLinkArray* array) { if (!checkJobPushState()) return false; if (array) mProcJobQue->pushExtraJobs(jq, *array); return true; } void BaseProcMgr::setJobType(JobType type) { mProcJobQue->clear(); mJobType = type; } bool BaseProcMgr::pushPreCalcJobs(sead::FixedSizeJQ* jq, JobType type, u8 prio, bool x, bool y) { if (!checkJobPushState()) return false; if (x) { mStatus = Status::ProcessingActorJobs; mJobType = type; mCurrentlyProcessingPrio = prio; mUnk2 = y; } const auto type_ = JobType(u8(type)); mProcJobQue->pushExtraJobs(jq, &getJobLists(type_), prio, type_); return true; } void BaseProcMgr::setActorJobTypeAndPrio(JobType type, s32 prio, bool x) { mStatus = Status::ProcessingActorJobs; mJobType = type; mCurrentlyProcessingPrio = prio; mUnk2 = x; } void BaseProcMgr::goIdle() { mStatus = Status::Idle; mJobType = JobType::Invalid; mIsPushingJobs = false; mUnk2 = false; mEnableExtraJobPush = false; mCurrentlyProcessingPrio = 8; } void BaseProcMgr::jobInvoked(BaseProcJobLink* link, s32 required_calc_rounds) { if (required_calc_rounds == 1) { link->getProc()->jobInvoked(mJobType); return; } const auto& lists = getJobLists(mJobType); for (int i = 0; link && [&] { return i < required_calc_rounds; }(); ++i) { link->getProc()->jobInvoked(mJobType); link = static_cast(lists.getNextJob(link)); } } bool BaseProcMgr::isSpecialJobType(JobType type) const { return mSpecialJobTypesMask.isOnBit(int(type)); } void BaseProcMgr::addSpecialJobTypes(u16 mask) { mSpecialJobTypesMask.set(mask); } void BaseProcMgr::removeSpecialJobTypes(u16 mask) { mSpecialJobTypesMask.reset(mask); } void BaseProcMgr::calc() { ActorSystem::instance()->onBaseProcMgrCalc(); mProcInitializer->deleteThreadIfPaused(); if (mIsInitialisingQuestMgrMaybe) return; if (!mProcUpdateStateList.isEmpty()) { const auto lock = sead::makeScopedLock(mProcUpdateStateListCS); mStatus = Status::ProcessingUpdateStateList; for (auto& proc : mProcUpdateStateList) proc.processStateUpdate(mCounter); for (auto it = mProcUpdateStateList.robustBegin(), end = mProcUpdateStateList.robustEnd(); it != end; ++it) { it->afterUpdateState_(); if (it->mStateFlags.isZero()) { mProcUpdateStateList.erase(std::addressof(*it)); } } mStatus = Status::Idle; } ++mCounter; } void BaseProcMgr::clearMode() { mMode = Mode::_0; } sead::CriticalSection* BaseProcMgr::lockProcMap() { mProcMapCS.lock(); return &mProcMapCS; } void BaseProcMgr::unlockProcMap() { mLastProcMapNode = nullptr; mProcMapCS.unlock(); } void BaseProcMgr::deleteAllProcs() { auto procs = getProcs(ProcFilter::_1 | ProcFilter::_4 | ProcFilter::_8); while (auto* proc = procs.next()) { if (!proc->mFlags.isOn(BaseProc::Flags::DoNotDelete)) proc->deleteLater(BaseProc::DeleteReason::BaseProcMgrDeleteAll); } } bool BaseProcMgr::hasFinishedDeletingAllProcs() { auto procs = getProcs(ProcFilter::_1 | ProcFilter::_2 | ProcFilter::_4 | ProcFilter::_8); while (auto* proc = procs.next()) { if (!proc->mFlags.isOn(BaseProc::Flags::DoNotDelete)) return false; } return mNumPendingDeletions == 0; } bool BaseProcMgr::isHighPriorityThread() const { const auto current_thread = sead::ThreadMgr::instance()->getCurrentThread(); if (!current_thread) return false; const auto id = current_thread->getId(); if (!current_thread->isDefaultPriority()) return false; return id == mMainThreadId || id == mHavokThreadId1 || id == mHavokThreadId2; } void BaseProcMgr::incrementUnk3() { if (mUnk3 != 0xFF) ++mUnk3; } void BaseProcMgr::decrementUnk3() { if (mUnk3 != 0) --mUnk3; } bool BaseProcMgr::hasExtraJobLink(BaseProcJobLink* job_link, s32 idx) { for (auto& ptr : mExtraJobLinkArrays.ref()[idx]) { if (&ptr == job_link) return true; } return false; } void BaseProcMgr::clearExtraJobArrays() { mExtraJobLinkArrays.ref()[0].clear(); mExtraJobLinkArrays.ref()[1].clear(); } } // namespace ksys::act