mirror of
https://github.com/zeldaret/botw
synced 2026-05-24 07:10:50 -04:00
396 lines
11 KiB
C++
396 lines
11 KiB
C++
#include "KingSystem/ActorSystem/actBaseProcMgr.h"
|
|
#include <mc/seadWorkerMgr.h>
|
|
#include <prim/seadScopedLock.h>
|
|
#include <thread/seadThread.h>
|
|
#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<BaseProcJobLink*>(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
|