mirror of
https://github.com/zeldaret/botw
synced 2026-06-25 17:24:37 -04:00
Initial commit
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
#include "Game/Action/actionSetLinkTagBasic.h"
|
||||
#include "KingSystem/ActorSystem/actActor.h"
|
||||
|
||||
namespace uking::action {
|
||||
|
||||
SetLinkTagBasicAction::SetLinkTagBasicAction(const ksys::act::ai::ClassArg& arg)
|
||||
: ksys::act::ai::Action(arg) {}
|
||||
|
||||
SetLinkTagBasicAction::~SetLinkTagBasicAction() = default;
|
||||
|
||||
void SetLinkTagBasicAction::enter() {
|
||||
if (IsOn.value())
|
||||
mActor->emitBasicSigOn();
|
||||
else
|
||||
mActor->emitBasicSigOff();
|
||||
|
||||
setFinished();
|
||||
}
|
||||
|
||||
void SetLinkTagBasicAction::loadParams() {
|
||||
getParamStatic(&IsOn, "IsOn");
|
||||
}
|
||||
|
||||
} // namespace uking::action
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "KingSystem/ActorSystem/actAiAction.h"
|
||||
#include "KingSystem/ActorSystem/actAiParam.h"
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace uking::action {
|
||||
|
||||
class SetLinkTagBasicAction : public ksys::act::ai::Action {
|
||||
public:
|
||||
SetLinkTagBasicAction(const ksys::act::ai::ClassArg& arg);
|
||||
~SetLinkTagBasicAction() override;
|
||||
|
||||
void enter() override;
|
||||
void loadParams() override;
|
||||
|
||||
private:
|
||||
ksys::act::ai::ParamRef<bool> IsOn;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(SetLinkTagBasicAction, 0x28);
|
||||
|
||||
} // namespace uking::action
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "KingSystem/ActorSystem/actBaseProc.h"
|
||||
|
||||
namespace ksys {
|
||||
|
||||
namespace act {
|
||||
|
||||
class Actor : public BaseProc {
|
||||
public:
|
||||
Actor(); // FIXME
|
||||
~Actor() override;
|
||||
|
||||
void emitBasicSigOn();
|
||||
void emitBasicSigOff();
|
||||
};
|
||||
|
||||
} // namespace act
|
||||
|
||||
} // namespace ksys
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "KingSystem/ActorSystem/actActorCreator.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
SEAD_SINGLETON_DISPOSER_IMPL(ActorCreator)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <container/seadOffsetList.h>
|
||||
#include <heap/seadDisposer.h>
|
||||
#include <prim/seadDelegate.h>
|
||||
#include <thread/seadCriticalSection.h>
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
class Actor;
|
||||
struct ActorCreateArg;
|
||||
class ActorFactory;
|
||||
|
||||
class ActorCreator {
|
||||
SEAD_SINGLETON_DISPOSER(ActorCreator)
|
||||
ActorCreator();
|
||||
virtual ~ActorCreator();
|
||||
|
||||
public:
|
||||
void setActorFactory(ActorFactory* factory) { mActorFactory = factory; }
|
||||
|
||||
private:
|
||||
sead::Heap* forBaseProcDualHeap;
|
||||
sead::Heap* placementMgrHeap;
|
||||
sead::OffsetList<Actor> mActorList;
|
||||
void* _50;
|
||||
bool mEnableDistanceChecks;
|
||||
bool _59;
|
||||
bool _5a;
|
||||
void* _60;
|
||||
sead::Delegate1<ActorCreator, ActorCreateArg&> mCreateActorDelegate;
|
||||
// FIXME: argument type
|
||||
sead::Delegate1<ActorCreator, void*> mCleanUpDelegate;
|
||||
sead::CriticalSection mActorListCS;
|
||||
ActorFactory* mActorFactory;
|
||||
};
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "KingSystem/ActorSystem/actActorFactory.h"
|
||||
#include "KingSystem/ActorSystem/actActorCreator.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
SEAD_SINGLETON_DISPOSER_IMPL(ActorFactoryHolder)
|
||||
|
||||
void ActorFactory::dummy() {}
|
||||
|
||||
void ActorFactory::dummy2() {}
|
||||
|
||||
ActorFactoryHolder::~ActorFactoryHolder() {
|
||||
ActorCreator::deleteInstance();
|
||||
}
|
||||
|
||||
void ActorFactoryHolder::init(sead::Heap* heap) {
|
||||
ActorCreator::createInstance(heap);
|
||||
ActorCreator::instance()->setActorFactory(&mFactory);
|
||||
}
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <heap/seadDisposer.h>
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
struct ActorCreateArg;
|
||||
class BaseProc;
|
||||
|
||||
class ActorFactory {
|
||||
public:
|
||||
virtual void dummy();
|
||||
virtual BaseProc* createActor(const ActorCreateArg& arg);
|
||||
virtual void dummy2();
|
||||
};
|
||||
|
||||
class ActorFactoryHolder {
|
||||
SEAD_SINGLETON_DISPOSER(ActorFactoryHolder)
|
||||
virtual ~ActorFactoryHolder();
|
||||
|
||||
public:
|
||||
void init(sead::Heap* heap);
|
||||
|
||||
private:
|
||||
ActorFactory mFactory;
|
||||
};
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace ksys {
|
||||
|
||||
namespace act {
|
||||
|
||||
class BaseProc;
|
||||
|
||||
/// Provides read-only access to actor data for safe, multi-threaded access.
|
||||
class ActorLinkConstDataAccess {
|
||||
public:
|
||||
~ActorLinkConstDataAccess();
|
||||
|
||||
private:
|
||||
bool mAcquired = false;
|
||||
BaseProc* mProc = nullptr;
|
||||
};
|
||||
|
||||
} // namespace act
|
||||
|
||||
} // namespace ksys
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "KingSystem/ActorSystem/actAiAction.h"
|
||||
|
||||
namespace ksys::act::ai {
|
||||
|
||||
Action::Action(const ClassArg& arg) : ActionBase(arg) {}
|
||||
|
||||
} // namespace ksys::act::ai
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "KingSystem/ActorSystem/actAiClass.h"
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys::act::ai {
|
||||
|
||||
class Action : public ActionBase {
|
||||
public:
|
||||
Action(const ClassArg& arg);
|
||||
|
||||
virtual void enter() {}
|
||||
virtual void loadParams() {}
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(Action, 0x20);
|
||||
|
||||
} // namespace ksys::act::ai
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "KingSystem/ActorSystem/actAiClass.h"
|
||||
|
||||
namespace ksys::act::ai {
|
||||
|
||||
ActionBase::ActionBase(const ClassArg& arg)
|
||||
: mActor{arg.actor}, mDefinitionIdx{u16(arg.definitionIdx)}, mRootIdx{u8(arg.rootIdx)} {}
|
||||
|
||||
} // namespace ksys::act::ai
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <basis/seadTypes.h>
|
||||
|
||||
#include "KingSystem/ActorSystem/actAiParam.h"
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
class Actor;
|
||||
|
||||
namespace ai {
|
||||
|
||||
struct ClassArg {
|
||||
Actor* actor;
|
||||
u32 definitionIdx;
|
||||
u32 rootIdx;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(ClassArg, 0x10);
|
||||
|
||||
class ActionBase {
|
||||
public:
|
||||
ActionBase(const ClassArg& arg);
|
||||
virtual ~ActionBase() = default;
|
||||
|
||||
protected:
|
||||
void setFinished();
|
||||
|
||||
template <typename T>
|
||||
void getParamStatic(ParamRef<T>* value, const sead::SafeString& key);
|
||||
|
||||
Actor* mActor;
|
||||
ParamPack mParams;
|
||||
u16 mDefinitionIdx;
|
||||
u8 mRootIdx;
|
||||
u8 mStatus = 0;
|
||||
u16 mClassIdx;
|
||||
u16 mPrevClassIdx;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(ActionBase, 0x20);
|
||||
|
||||
} // namespace ai
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "KingSystem/ActorSystem/actAiParam.h"
|
||||
|
||||
namespace ksys::act::ai {
|
||||
|
||||
ParamPack::ParamPack() = default;
|
||||
|
||||
ParamPack::~ParamPack() {
|
||||
auto* param = mParams;
|
||||
while (param) {
|
||||
if (param->data) {
|
||||
switch (Param::Type(param->type)) {
|
||||
case Param::Type::String:
|
||||
delete static_cast<sead::SafeString*>(param->data);
|
||||
break;
|
||||
case Param::Type::Int:
|
||||
delete static_cast<int*>(param->data);
|
||||
break;
|
||||
case Param::Type::Float:
|
||||
delete static_cast<float*>(param->data);
|
||||
break;
|
||||
case Param::Type::Vec3:
|
||||
delete static_cast<sead::Vector3f*>(param->data);
|
||||
break;
|
||||
case Param::Type::Bool:
|
||||
delete static_cast<bool*>(param->data);
|
||||
break;
|
||||
case Param::Type::AITreeVariablePointer:
|
||||
delete static_cast<void**>(param->data);
|
||||
break;
|
||||
case Param::Type::UInt:
|
||||
delete static_cast<u32*>(param->data);
|
||||
break;
|
||||
case Param::Type::MesTransceiverId:
|
||||
delete static_cast<mes::TransceiverId*>(param->data);
|
||||
break;
|
||||
case Param::Type::BaseProcHandle:
|
||||
delete static_cast<BaseProcHandle**>(param->data);
|
||||
break;
|
||||
case Param::Type::Rail:
|
||||
delete static_cast<Rail**>(param->data);
|
||||
break;
|
||||
case Param::Type::BaseProcLink:
|
||||
delete static_cast<BaseProcLink*>(param->data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
param = mParams->next;
|
||||
if (mParams)
|
||||
delete mParams;
|
||||
mParams = param;
|
||||
}
|
||||
}
|
||||
|
||||
void InlineParamPack::copyToParamPack(ParamPack& pack) const {
|
||||
const u32 n = count >= 0x1F ? 0x1F : count;
|
||||
const InlineParam* param = params;
|
||||
for (u32 i = 0; i < n; ++i, ++param) {
|
||||
switch (param->type) {
|
||||
case Param::Type::String: {
|
||||
const sead::SafeString src = param->cstr;
|
||||
const sead::SafeString key = param->key;
|
||||
auto* dst = pack.getVariable<sead::BufferedSafeString>(key, Param::Type::String);
|
||||
if (dst)
|
||||
dst->copy(src);
|
||||
break;
|
||||
}
|
||||
case Param::Type::Int:
|
||||
pack.setVariable(param->key, Param::Type::Int, param->i);
|
||||
break;
|
||||
case Param::Type::Float:
|
||||
pack.setVariable(param->key, Param::Type::Float, param->f);
|
||||
break;
|
||||
case Param::Type::Vec3:
|
||||
if (auto* dst = pack.getVariable<sead::Vector3f>(param->key, Param::Type::Vec3)) {
|
||||
dst->x = param->vec3.x;
|
||||
dst->y = param->vec3.y;
|
||||
dst->z = param->vec3.z;
|
||||
}
|
||||
break;
|
||||
case Param::Type::Bool:
|
||||
pack.setVariable(param->key, Param::Type::Bool, param->b);
|
||||
break;
|
||||
case Param::Type::UInt:
|
||||
pack.setVariable(param->key, Param::Type::UInt, param->u);
|
||||
break;
|
||||
case Param::Type::BaseProcLink:
|
||||
pack.setVariable(param->key, Param::Type::BaseProcLink, param->baseProcLink);
|
||||
break;
|
||||
case Param::Type::MesTransceiverId:
|
||||
pack.setVariable(param->key, Param::Type::MesTransceiverId, param->mesTransceiverId);
|
||||
break;
|
||||
case Param::Type::BaseProcHandle: {
|
||||
auto* baseProcHandle = static_cast<BaseProcHandle*>(param->ptr);
|
||||
pack.setVariable(param->key, Param::Type::BaseProcHandle, baseProcHandle);
|
||||
break;
|
||||
}
|
||||
case Param::Type::Rail: {
|
||||
auto* rail = static_cast<Rail*>(param->ptr);
|
||||
pack.setVariable(param->key, Param::Type::Rail, rail);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ksys::act::ai
|
||||
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#include <agl/Utils/aglParameter.h>
|
||||
#include <basis/seadTypes.h>
|
||||
#include <math/seadVector.h>
|
||||
#include <prim/seadSafeString.h>
|
||||
|
||||
#include "KingSystem/ActorSystem/actBaseProc.h"
|
||||
#include "KingSystem/MessageSystem/mesTransceiver.h"
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys {
|
||||
|
||||
class Rail;
|
||||
|
||||
namespace act::ai {
|
||||
|
||||
struct Param {
|
||||
enum class Type {
|
||||
String = 0,
|
||||
Int = 1,
|
||||
Float = 2,
|
||||
Vec3 = 3,
|
||||
Bool = 4,
|
||||
Tree = 5,
|
||||
AITreeVariablePointer = 6,
|
||||
UInt = 7,
|
||||
BaseProcLink = 8,
|
||||
MesTransceiverId = 9,
|
||||
BaseProcHandle = 10,
|
||||
Rail = 11,
|
||||
Other = 12,
|
||||
};
|
||||
|
||||
Param* next;
|
||||
u32 hash;
|
||||
const char* name;
|
||||
void* data;
|
||||
u16 type;
|
||||
bool used;
|
||||
u8 _23;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(Param, 0x28);
|
||||
|
||||
class ParamPack {
|
||||
public:
|
||||
ParamPack();
|
||||
~ParamPack();
|
||||
|
||||
template <typename T>
|
||||
T* getVariable(const sead::SafeString& key, Param::Type type, bool a4 = true) const {
|
||||
const u32 hash = agl::utl::ParameterBase::calcHash(key);
|
||||
auto* param = mParams;
|
||||
if (!param)
|
||||
return nullptr;
|
||||
while (param->hash != hash || Param::Type(param->type) != type) {
|
||||
param = param->next;
|
||||
if (!param)
|
||||
return nullptr;
|
||||
}
|
||||
if (a4)
|
||||
param->used = true;
|
||||
return static_cast<T*>(param->data);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setVariable(const sead::SafeString& key, Param::Type type, const T& val) const {
|
||||
T* variable = getVariable<T>(key, type, true);
|
||||
if (variable)
|
||||
*variable = val;
|
||||
}
|
||||
|
||||
private:
|
||||
Param* mParams = nullptr;
|
||||
};
|
||||
|
||||
struct InlineParam {
|
||||
union {
|
||||
bool b;
|
||||
int i;
|
||||
u32 u;
|
||||
float f;
|
||||
const char* cstr;
|
||||
void* ptr;
|
||||
};
|
||||
BaseProcLink baseProcLink;
|
||||
sead::Vector3f vec3;
|
||||
mes::TransceiverId mesTransceiverId;
|
||||
Param::Type type;
|
||||
const char* key;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(InlineParam, 0x50);
|
||||
|
||||
struct InlineParamPack {
|
||||
void copyToParamPack(ParamPack& pack) const;
|
||||
|
||||
InlineParam params[32];
|
||||
int count;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(InlineParamPack, 0xA08);
|
||||
|
||||
template <typename T>
|
||||
class ParamRef {
|
||||
public:
|
||||
const T& value() const { return *mValue; }
|
||||
void setValuePtr(const T* ptr) { mValue = ptr; }
|
||||
|
||||
private:
|
||||
const T* mValue = nullptr;
|
||||
};
|
||||
} // namespace act::ai
|
||||
|
||||
} // namespace ksys
|
||||
@@ -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
|
||||
@@ -0,0 +1,286 @@
|
||||
#pragma once
|
||||
|
||||
#include <basis/seadTypes.h>
|
||||
#include <container/seadListImpl.h>
|
||||
#include <container/seadSafeArray.h>
|
||||
#include <container/seadTreeMap.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 {
|
||||
|
||||
namespace act {
|
||||
|
||||
class ActorLinkConstDataAccess;
|
||||
class BaseProc;
|
||||
class BaseProcLinkData;
|
||||
class BaseProcJobHandler;
|
||||
|
||||
class BaseProcLink {
|
||||
public:
|
||||
BaseProcLink();
|
||||
~BaseProcLink() { reset(); }
|
||||
BaseProcLink& operator=(const BaseProcLink&);
|
||||
bool operator==(const BaseProcLink&) const;
|
||||
bool operator!=(const BaseProcLink& rhs) const { return !operator==(rhs); }
|
||||
BaseProc* fromAccessorAndActor(ActorLinkConstDataAccess&, BaseProc*);
|
||||
BaseProc* fromAccessor(ActorLinkConstDataAccess&);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
BaseProcLinkData* mData = nullptr;
|
||||
u32 mId = -1;
|
||||
bool mAcquired = false;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(BaseProcLink, 0x10);
|
||||
|
||||
class BaseProcUnit;
|
||||
|
||||
class BaseProcHandle {
|
||||
public:
|
||||
BaseProcHandle();
|
||||
~BaseProcHandle();
|
||||
|
||||
private:
|
||||
BaseProcUnit* mUnit;
|
||||
u8 mFlag;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(BaseProcHandle, 0x10);
|
||||
|
||||
/// 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,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
u8 getPriority() const { return mPriority; }
|
||||
void setPriority(u8 priority) { mPriority = priority; }
|
||||
|
||||
bool isDeletedOrDeleting() const {
|
||||
return mState == State::Delete || 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,
|
||||
};
|
||||
|
||||
enum class StateFlags : u32 {
|
||||
RequestDelete = 1,
|
||||
_2 = 2,
|
||||
RequestSleep = 4,
|
||||
RequestWakeUp = 8,
|
||||
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,
|
||||
};
|
||||
|
||||
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_(bool* do_not_destruct_immediately);
|
||||
|
||||
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_(bool* do_not_destruct_immediately);
|
||||
/// Called to actually pre-delete (first callback).
|
||||
virtual void preDelete1_();
|
||||
|
||||
virtual bool isSpecialJobType_(JobType type);
|
||||
virtual bool canWakeUp_();
|
||||
virtual void queueExtraJobPush_(JobType type);
|
||||
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();
|
||||
/// Actually pre-delete the actor. Called from BaseProcDeleter.
|
||||
void doPreDelete(bool* do_not_destruct_immediately);
|
||||
void startDelete_();
|
||||
|
||||
bool isSpecialJobTypeForThisActor_(JobType type) const {
|
||||
return mSpecialJobTypesMask.isOnBit(int(type));
|
||||
}
|
||||
|
||||
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::Delegate<BaseProc> mInvoker; // TODO: is this correct?
|
||||
sead::ListNode mPostDeleteListNode;
|
||||
sead::ListNode mDeleteListNode;
|
||||
BaseProcMapNode mMapNode{this};
|
||||
BaseProcUnit* mProcUnit = nullptr;
|
||||
sead::Atomic<u32> mRefCount = 0;
|
||||
|
||||
private:
|
||||
void unlinkProcUnit_();
|
||||
void unlinkCalcChild_();
|
||||
void unlinkCalcParent_();
|
||||
void loadNewCalcChild_(u8 counter);
|
||||
void loadNewCalcParent_(u8 counter);
|
||||
|
||||
void handleSleepRequest_();
|
||||
void handleWakeUpRequest_();
|
||||
void handleJobPriorityChangeRequest_();
|
||||
|
||||
bool canWakeUpOrFlagsSet_() {
|
||||
return mFlags.isOn(Flags::_80) ? mFlags.isOn(Flags::_100) : canWakeUp_();
|
||||
}
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(BaseProc, 0x180);
|
||||
|
||||
} // namespace act
|
||||
|
||||
} // namespace ksys
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "KingSystem/ActorSystem/actBaseProcJob.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
BaseProcJobLink::BaseProcJobLink(BaseProc* proc, u8 priority)
|
||||
: TListNode(proc), mPriority(priority), mNewPriority(priority), mPriority2(3),
|
||||
mNewPriority2(3) {}
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include <container/seadTList.h>
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
class BaseProc;
|
||||
|
||||
enum class Priority : u8 {
|
||||
PlayerBefore = 0,
|
||||
Player = 2,
|
||||
PlayerAfter = 2,
|
||||
AllAfter = 3,
|
||||
};
|
||||
|
||||
enum class JobType {
|
||||
PreCalc = 0,
|
||||
Calc1 = 1,
|
||||
Calc2 = 2,
|
||||
Calc3 = 3,
|
||||
Calc4 = 4,
|
||||
AfterMessageDispatch = 5,
|
||||
Calc3Alt = 6,
|
||||
Invalid = 7,
|
||||
};
|
||||
|
||||
class BaseProcJobLink : public sead::TListNode<BaseProc*> {
|
||||
public:
|
||||
BaseProcJobLink(BaseProc* proc, u8 priority);
|
||||
|
||||
u8 getPriority() const { return mPriority; }
|
||||
u8 getPriority2() const { return mPriority2; }
|
||||
|
||||
void setNewPriority(u8 priority) { mNewPriority = priority; }
|
||||
void setNewPriority2(u8 priority) { mNewPriority2 = priority; }
|
||||
|
||||
void loadNewPriority() { mPriority = mNewPriority; }
|
||||
void loadNewPriority2() { mPriority2 = mNewPriority2; }
|
||||
|
||||
bool hasPriorityChange() const {
|
||||
return mPriority != mNewPriority || mPriority2 != mNewPriority2;
|
||||
}
|
||||
|
||||
private:
|
||||
u8 mPriority;
|
||||
u8 mNewPriority;
|
||||
u8 mPriority2;
|
||||
u8 mNewPriority2;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(BaseProcJobLink, 0x28);
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "KingSystem/ActorSystem/actBaseProcJobHandler.h"
|
||||
#include "KingSystem/ActorSystem/actBaseProc.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
BaseProcJobHandler::BaseProcJobHandler(BaseProc* proc) : mLink(proc, proc->getPriority()) {}
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "KingSystem/ActorSystem/actBaseProcJob.h"
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
class BaseProcJobHandler {
|
||||
public:
|
||||
BaseProcJobHandler(BaseProc* proc);
|
||||
virtual ~BaseProcJobHandler() = default;
|
||||
virtual void invoke() = 0;
|
||||
virtual void invokeSpecial() {}
|
||||
|
||||
BaseProcJobLink& getLink() { return mLink; }
|
||||
const BaseProcJobLink& getLink() const { return mLink; }
|
||||
|
||||
protected:
|
||||
BaseProcJobLink mLink;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(BaseProcJobHandler, 0x30);
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "KingSystem/ActorSystem/actBaseProcLinkDataMgr.h"
|
||||
#include <prim/seadScopedLock.h>
|
||||
#include <thread/seadThread.h>
|
||||
#include "KingSystem/ActorSystem/actBaseProc.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
SEAD_SINGLETON_DISPOSER_IMPL(BaseProcLinkDataMgr)
|
||||
|
||||
bool BaseProcLinkDataMgr::acquireLink(BaseProc* proc) {
|
||||
auto lock = sead::makeScopedLock(mCS);
|
||||
s32 index = mIndex;
|
||||
for (s32 i = 0; i < mData.size(); ++i) {
|
||||
const s32 j = index == 0x800 ? 0 : index;
|
||||
auto& data = mData[j];
|
||||
if (data.mId == u32(-1)) {
|
||||
{
|
||||
auto data_lock = sead::makeScopedLock(data.mCS);
|
||||
data.mProc = proc;
|
||||
data.mId = proc->mId;
|
||||
proc->mBaseProcLinkData = &data;
|
||||
}
|
||||
mIndex = j + 1;
|
||||
return true;
|
||||
}
|
||||
index = j + 1;
|
||||
}
|
||||
|
||||
for (s32 i = 0; i < mData.size(); ++i) {
|
||||
auto data_lock = sead::makeScopedLock(mData[i].mCS);
|
||||
// Debug code was probably here?
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BaseProcLinkDataMgr::releaseLink(BaseProc* proc) {
|
||||
auto* data = proc->mBaseProcLinkData;
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
const auto thread = sead::ThreadMgr::instance()->getCurrentThread();
|
||||
thread->getPriority();
|
||||
|
||||
auto lock = sead::makeScopedLock(data->mCS);
|
||||
data->mProc = nullptr;
|
||||
data->mId = -1;
|
||||
proc->mBaseProcLinkData = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <container/seadSafeArray.h>
|
||||
#include <heap/seadDisposer.h>
|
||||
#include <prim/seadScopedLock.h>
|
||||
#include <thread/seadCriticalSection.h>
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
class BaseProc;
|
||||
|
||||
class BaseProcLinkData {
|
||||
public:
|
||||
u32 id() const { return mId; }
|
||||
BaseProc* proc() const { return mProc; }
|
||||
s32 refCount() const { return mRefCount; }
|
||||
|
||||
private:
|
||||
friend class BaseProcLinkDataMgr;
|
||||
|
||||
sead::CriticalSection mCS;
|
||||
u32 mId = -1;
|
||||
BaseProc* mProc = nullptr;
|
||||
s32 mRefCount = 0;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(BaseProcLinkData, 0x58);
|
||||
|
||||
class BaseProcLinkDataMgr {
|
||||
SEAD_SINGLETON_DISPOSER(BaseProcLinkDataMgr)
|
||||
|
||||
public:
|
||||
bool acquireLink(BaseProc* proc);
|
||||
bool releaseLink(BaseProc* proc);
|
||||
|
||||
private:
|
||||
sead::CriticalSection mCS;
|
||||
s32 mIndex = 0;
|
||||
sead::SafeArray<BaseProcLinkData, 2048> mData{};
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(BaseProcLinkDataMgr, 0x2C068);
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "KingSystem/ActorSystem/actBaseProcMap.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
void BaseProcMapNode::add(BaseProcMapNode* node) {
|
||||
auto next = mNext;
|
||||
node->mPrev = this;
|
||||
node->mNext = next;
|
||||
mNext = node;
|
||||
if (next)
|
||||
next->mPrev = node;
|
||||
}
|
||||
|
||||
void BaseProcMap::insert(BaseProcMapNode* node) {
|
||||
if (auto existing_node = find(node->key()))
|
||||
existing_node->add(node);
|
||||
else
|
||||
StrTreeMap::insert(node);
|
||||
node->setInserted();
|
||||
}
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "KingSystem/Utils/StrTreeMap.h"
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
class BaseProc;
|
||||
|
||||
class BaseProcMapNode final : public util::StrTreeMapNode {
|
||||
public:
|
||||
explicit BaseProcMapNode(BaseProc* proc) : mProc(proc) {}
|
||||
~BaseProcMapNode() override;
|
||||
|
||||
// NON_MATCHING: addressing mode for mPrev
|
||||
void erase_() override {
|
||||
if (mPrev)
|
||||
mPrev->mNext = mNext;
|
||||
|
||||
if (mNext)
|
||||
mNext->mPrev = mPrev;
|
||||
|
||||
StrTreeMapNode::erase_();
|
||||
mInserted = false;
|
||||
mPrev = mNext = nullptr;
|
||||
}
|
||||
|
||||
util::StrTreeMapKey& key() { return mKey; }
|
||||
const util::StrTreeMapKey& key() const { return mKey; }
|
||||
BaseProc* proc() const { return mProc; }
|
||||
BaseProcMapNode* prev() const { return mPrev; }
|
||||
BaseProcMapNode* next() const { return mNext; }
|
||||
|
||||
void add(BaseProcMapNode* node);
|
||||
|
||||
bool isInserted() const { return mInserted; }
|
||||
void setInserted() { mInserted = true; }
|
||||
|
||||
private:
|
||||
BaseProc* mProc = nullptr;
|
||||
BaseProcMapNode* mPrev = nullptr;
|
||||
BaseProcMapNode* mNext = nullptr;
|
||||
bool mInserted = false;
|
||||
};
|
||||
|
||||
class BaseProcMap : public util::StrTreeMap<BaseProcMapNode> {
|
||||
public:
|
||||
void insert(BaseProcMapNode* node);
|
||||
|
||||
void erase(BaseProcMapNode* node) {
|
||||
auto prev = node->prev();
|
||||
auto next = node->next();
|
||||
if (prev)
|
||||
node->erase_();
|
||||
else if (next)
|
||||
StrTreeMap::insert(next);
|
||||
else
|
||||
StrTreeMap::erase(node->key());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,133 @@
|
||||
#include "KingSystem/ActorSystem/actBaseProcMgr.h"
|
||||
#include <prim/seadScopedLock.h>
|
||||
#include <thread/seadThread.h>
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
SEAD_SINGLETON_DISPOSER_IMPL(BaseProcMgr)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void BaseProcMgr::addToPreDeleteList(BaseProc& proc) {
|
||||
auto lock = sead::makeScopedLock(mProcPreDeleteListCS);
|
||||
mProcPreDeleteList.pushBack(&proc);
|
||||
}
|
||||
|
||||
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::eraseFromPreDeleteList(BaseProc& proc) {
|
||||
auto lock = sead::makeScopedLock(mProcPreDeleteListCS);
|
||||
if (mProcPreDeleteList.isNodeLinked(&proc))
|
||||
mProcPreDeleteList.erase(&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;
|
||||
}
|
||||
|
||||
bool BaseProcMgr::hasExtraJobLink(BaseProcJobLink* job_link, s32 idx) {
|
||||
for (auto& ptr : mExtraJobLinkArrays[idx]) {
|
||||
if (&ptr == job_link)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BaseProcMgr::clearExtraJobArrays() {
|
||||
mExtraJobLinkArrays[0].clear();
|
||||
mExtraJobLinkArrays[1].clear();
|
||||
}
|
||||
|
||||
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::clearMode() {
|
||||
mMode = Mode::_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;
|
||||
}
|
||||
|
||||
sead::CriticalSection* BaseProcMgr::lockProcMap() {
|
||||
mProcMapCS.lock();
|
||||
return &mProcMapCS;
|
||||
}
|
||||
|
||||
void BaseProcMgr::unlockProcMap() {
|
||||
mLastProcMapNode = nullptr;
|
||||
mProcMapCS.unlock();
|
||||
}
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,219 @@
|
||||
#pragma once
|
||||
|
||||
#include <agl/Utils/aglAtomicPtrArray.h>
|
||||
#include <container/seadOffsetList.h>
|
||||
#include <container/seadPtrArray.h>
|
||||
#include <container/seadSafeArray.h>
|
||||
#include <heap/seadDisposer.h>
|
||||
#include <prim/seadBitFlag.h>
|
||||
#include <prim/seadScopedLock.h>
|
||||
#include <thread/seadAtomic.h>
|
||||
#include <thread/seadCriticalSection.h>
|
||||
#include "KingSystem/ActorSystem/actBaseProc.h"
|
||||
#include "KingSystem/ActorSystem/actBaseProcJob.h"
|
||||
#include "KingSystem/ActorSystem/actBaseProcMap.h"
|
||||
#include "KingSystem/Utils/StrTreeMap.h"
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace sead {
|
||||
class FixedSizeJQ;
|
||||
template <typename F>
|
||||
class IFunction;
|
||||
class WorkerMgr;
|
||||
} // namespace sead
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
class BaseProcDeleter;
|
||||
class BaseProcInitializer;
|
||||
class BaseProcInitializerArgs;
|
||||
class BaseProcJobLists;
|
||||
class BaseProcJobQue;
|
||||
|
||||
class BaseProcMgr {
|
||||
SEAD_SINGLETON_DISPOSER(BaseProcMgr)
|
||||
BaseProcMgr();
|
||||
|
||||
public:
|
||||
class ProcCreateRequest;
|
||||
|
||||
enum class Status : u8 {
|
||||
Idle = 0,
|
||||
_1 = 1,
|
||||
ProcessingActorJobs = 2,
|
||||
ProcessingPreDeleteList = 3,
|
||||
ProcessingUpdateStateList = 4,
|
||||
};
|
||||
|
||||
enum class Mode : u8 {
|
||||
_0 = 0,
|
||||
};
|
||||
|
||||
using ExtraJobLinkArray = agl::utl::FixedPtrArray<BaseProcJobLink, 512>;
|
||||
|
||||
static void createInstanceAndInit(sead::Heap* heap);
|
||||
static u32 getConstant0() { return sConstant0; }
|
||||
static u32 getConstant1() { return sConstant1; }
|
||||
static u32 getConstant2() { return sConstant2; }
|
||||
static u32 getConstant4() { return sConstant4; }
|
||||
|
||||
virtual ~BaseProcMgr();
|
||||
|
||||
void init(sead::Heap* heap, s32 num_job_types, u32 main_thread_id, u32 havok_thread_id1,
|
||||
u32 havok_thread_id2, BaseProcInitializerArgs* initializer_args);
|
||||
|
||||
// region BaseProc management
|
||||
|
||||
void generateProcId(u32* id);
|
||||
void registerProc(BaseProc& proc);
|
||||
void unregisterProc(BaseProc& proc);
|
||||
|
||||
void addToPreDeleteList(BaseProc& proc);
|
||||
bool addToUpdateStateList(BaseProc& proc);
|
||||
void eraseFromPreDeleteList(BaseProc& proc);
|
||||
void eraseFromUpdateStateList(BaseProc& proc);
|
||||
void processPreDeleteList();
|
||||
|
||||
void forEachProc(const sead::IDelegate1<BaseProc*>& callback, u32 flags);
|
||||
void deleteAllProcs();
|
||||
bool hasFinishedDeletingAllProcs();
|
||||
|
||||
// endregion
|
||||
|
||||
bool requestPreDelete(BaseProc& proc);
|
||||
void requestUnloadActorParam(void*);
|
||||
|
||||
// region Job processing
|
||||
|
||||
void pushJob(BaseProc& proc, JobType type);
|
||||
void pushJobs(BaseProc& proc);
|
||||
void eraseJob(BaseProc& proc, JobType type);
|
||||
void eraseJobs(BaseProc& proc);
|
||||
|
||||
void processExtraJobsDirectly(JobType type, s32 prio, bool);
|
||||
ExtraJobLinkArray& getExtraJobs();
|
||||
void swapExtraJobArray();
|
||||
|
||||
void queueExtraJobPush(BaseProcJobLink* job_link);
|
||||
void moveExtraJobsToOtherBuffer();
|
||||
bool hasExtraJobLink(BaseProcJobLink* job_link, s32 idx);
|
||||
void clearExtraJobArrays();
|
||||
|
||||
void pushJobQueues(sead::WorkerMgr* mgr, JobType type, bool);
|
||||
bool pushExtraJobsEx(sead::FixedSizeJQ* jq, JobType type, bool, bool);
|
||||
bool pushExtraJobsForCurrentTypeAndPrio(sead::FixedSizeJQ* jq, ExtraJobLinkArray& array);
|
||||
bool pushPreCalcJobs(sead::FixedSizeJQ* jq, JobType type, s32 prio, bool, bool);
|
||||
|
||||
void setActorJobType(JobType type);
|
||||
void setActorJobTypeAndPrio(JobType type, s32 prio, bool);
|
||||
void goIdle();
|
||||
void clearMode();
|
||||
void calc();
|
||||
void jobInvoked(BaseProcJobLink* link, s32 required_calc_rounds);
|
||||
|
||||
// endregion
|
||||
|
||||
// region Special job types
|
||||
|
||||
bool isSpecialJobType(JobType type) const;
|
||||
void addSpecialJobTypes(u16 mask);
|
||||
void removeSpecialJobTypes(u16 mask);
|
||||
|
||||
// endregion
|
||||
|
||||
/// Returns true if and only if the calling thread is the game thread or a Havok thread.
|
||||
bool isHighPriorityThread() const;
|
||||
/// Returns true if and only if it is safe to access the specified BaseProc.
|
||||
bool isAccessingProcSafe(BaseProc* proc, BaseProc* other);
|
||||
|
||||
// region BaseProc creation
|
||||
|
||||
bool requestCreateProc(ProcCreateRequest& req);
|
||||
BaseProc* createProc(ProcCreateRequest& req);
|
||||
|
||||
// endregion
|
||||
|
||||
// region Actor initializer control
|
||||
|
||||
void resumeThreadMaybe();
|
||||
void stopThreads();
|
||||
void clearMessageQueueMaybe();
|
||||
void startActorCreateThread();
|
||||
|
||||
void clearInitializerMessageQueuesMaybe();
|
||||
s32 getActorCreateInitializerQueueSize();
|
||||
s32 getActorCreateInitializerQueueSizeEx(s32 x);
|
||||
void invokeOnActorCreateInitializerThreadMaybe(void* delegate);
|
||||
void setActorGenerationEnabled(bool enabled);
|
||||
|
||||
// endregion
|
||||
|
||||
auto getUnk3() const { return mUnk3; }
|
||||
void incrementUnk3();
|
||||
void decrementUnk3();
|
||||
|
||||
void writeResidentActorsCsv(const sead::SafeString& file_path);
|
||||
|
||||
auto& getProcUpdateStateListCS() { return mProcUpdateStateListCS; }
|
||||
|
||||
void incrementPendingDeletions() { mNumPendingDeletions.increment(); }
|
||||
void decrementPendingDeletions() { mNumPendingDeletions.decrement(); }
|
||||
|
||||
u32 getNumJobTypes() const { return mNumJobTypes; }
|
||||
|
||||
private:
|
||||
void doAddToUpdateStateList_(BaseProc& proc);
|
||||
|
||||
sead::CriticalSection* lockProcMap();
|
||||
void unlockProcMap();
|
||||
void getNextActor(sead::CriticalSection* cs, BaseProc* proc, u32 flags);
|
||||
|
||||
static sead::BufferedSafeString* sResidentActorListStr;
|
||||
static u32 sConstant0;
|
||||
static u32 sConstant1;
|
||||
static u32 sConstant2;
|
||||
static u32 sConstant4;
|
||||
|
||||
Status mStatus = Status::Idle;
|
||||
util::SizedEnum<JobType, u8> mJobType = JobType::Invalid;
|
||||
u8 mCurrentlyProcessingPrio = 8;
|
||||
u8 mCounter = 0;
|
||||
sead::CriticalSection mProcMapCS;
|
||||
sead::OffsetList<BaseProc> mProcPreDeleteList;
|
||||
u32 mNumJobTypes = 0;
|
||||
BaseProcJobLists* mJobLists = nullptr;
|
||||
BaseProcMap mProcMap;
|
||||
sead::OffsetList<BaseProc> mProcUpdateStateList;
|
||||
sead::CriticalSection mProcUpdateStateListCS;
|
||||
sead::CriticalSection mProcPreDeleteListCS;
|
||||
BaseProcMapNode* mLastProcMapNode = nullptr;
|
||||
BaseProcJobQue* mProcJobQue = nullptr;
|
||||
sead::Atomic<u32> mCreatedProcCounter = 0;
|
||||
sead::Atomic<u32> mNumPendingDeletions = 0;
|
||||
BaseProcInitializer* mProcInitializer = nullptr;
|
||||
BaseProcDeleter* mProcDeleter = nullptr;
|
||||
bool mIsPushingJobs = false;
|
||||
bool mPushActorJobType3InsteadOf6 = false;
|
||||
bool mEnableExtraJobPush = false;
|
||||
Mode mMode = Mode::_0;
|
||||
bool mUnk2 = false;
|
||||
bool mIsInitialisingQuestMgrMaybe = false;
|
||||
u8 mCurrentExtraJobArrayIdx = 0;
|
||||
u8 mUnk3 = 0;
|
||||
sead::BitFlag16 mSpecialJobTypesMask = 0;
|
||||
u32 mMainThreadId = 0;
|
||||
u32 mHavokThreadId1 = 0;
|
||||
u32 mHavokThreadId2 = 0;
|
||||
u32 mUnk4 = 0;
|
||||
sead::SafeArray<ExtraJobLinkArray, 2> mExtraJobLinkArrays{};
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(BaseProcMgr, 0x21a0);
|
||||
|
||||
inline bool BaseProcMgr::addToUpdateStateList(BaseProc& proc) {
|
||||
auto lock = sead::makeScopedLock(mProcUpdateStateListCS);
|
||||
doAddToUpdateStateList_(proc);
|
||||
return (proc.mStateFlags.set(BaseProc::StateFlags::RequestDelete) &
|
||||
u32(BaseProc::StateFlags::RequestDelete)) != 0;
|
||||
}
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <basis/seadTypes.h>
|
||||
#include <thread/seadCriticalSection.h>
|
||||
|
||||
namespace ksys::act {
|
||||
|
||||
class BaseProc;
|
||||
class BaseProcHandle;
|
||||
|
||||
class BaseProcUnit {
|
||||
public:
|
||||
bool deleteProc(void*, BaseProcHandle* handle);
|
||||
bool setProc(BaseProc* proc);
|
||||
void unlinkProc(BaseProc* proc);
|
||||
void cleanUp(BaseProc* proc, bool set_flag_5);
|
||||
bool isParentHandleDefault() const;
|
||||
|
||||
private:
|
||||
u32 mFlags;
|
||||
BaseProcHandle* mHandle;
|
||||
BaseProc* mProc;
|
||||
// FIXME:
|
||||
// BaseProcRequest mRequest;
|
||||
sead::CriticalSection mCS;
|
||||
};
|
||||
|
||||
} // namespace ksys::act
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <basis/seadTypes.h>
|
||||
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys {
|
||||
|
||||
namespace mes {
|
||||
|
||||
struct TransceiverId {
|
||||
TransceiverId();
|
||||
|
||||
TransceiverId& operator=(const TransceiverId& other) {
|
||||
_0 = other._0;
|
||||
_4 = other._4;
|
||||
_8 = other._8;
|
||||
_10 = other._10;
|
||||
return *this;
|
||||
}
|
||||
|
||||
u32 _0;
|
||||
u32 _4;
|
||||
void* _8;
|
||||
void* _10;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(TransceiverId, 0x18);
|
||||
|
||||
} // namespace mes
|
||||
|
||||
} // namespace ksys
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
namespace ksys::tera {
|
||||
|
||||
// TODO:
|
||||
class ApertureMaps {
|
||||
void updateMap();
|
||||
};
|
||||
class ApertureMapsCollector {
|
||||
void allocateImage();
|
||||
void releaseImage();
|
||||
};
|
||||
class Core {
|
||||
class Grass;
|
||||
class Model;
|
||||
class Tree;
|
||||
};
|
||||
class ImageResourceMgr {
|
||||
void procUnloadResidualRequest();
|
||||
};
|
||||
class ResourceHolder;
|
||||
class Scene {
|
||||
void exportFileBinary();
|
||||
};
|
||||
class System {
|
||||
void loadScene();
|
||||
};
|
||||
class Water {
|
||||
void setUpAttributeTable();
|
||||
};
|
||||
|
||||
bool checkTeraSystemStatus();
|
||||
|
||||
} // namespace ksys::tera
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <basis/seadTypes.h>
|
||||
#include <codec/seadHashCRC32.h>
|
||||
#include <container/seadTreeMap.h>
|
||||
|
||||
namespace ksys::util {
|
||||
|
||||
class StrTreeMapKey {
|
||||
public:
|
||||
const sead::SafeString& key() const { return mKey; }
|
||||
|
||||
// NON_MATCHING: stack
|
||||
void setKey(u32 hash, sead::SafeString key) {
|
||||
mKeyHash = hash;
|
||||
mKey = key;
|
||||
}
|
||||
|
||||
void setKey(const sead::SafeString& key) {
|
||||
setKey(sead::HashCRC32::calcStringHash(key.cstr()), key);
|
||||
}
|
||||
|
||||
s32 compare(const StrTreeMapKey& rhs) const {
|
||||
if (mKeyHash < rhs.mKeyHash)
|
||||
return -1;
|
||||
if (mKeyHash > rhs.mKeyHash)
|
||||
return 1;
|
||||
return mKey.compare(rhs.mKey);
|
||||
}
|
||||
|
||||
private:
|
||||
u32 mKeyHash = 0;
|
||||
sead::SafeString mKey;
|
||||
};
|
||||
|
||||
class StrTreeMapNode : public sead::TreeMapNode<StrTreeMapKey> {
|
||||
public:
|
||||
~StrTreeMapNode() override { ; }
|
||||
void erase_() override { mLeft = mRight = nullptr; }
|
||||
};
|
||||
|
||||
template <typename Node>
|
||||
class StrTreeMap : public sead::IntrusiveTreeMap<StrTreeMapKey, Node> {};
|
||||
|
||||
} // namespace ksys::util
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef SEAD_DEBUG
|
||||
#define KSYS_CHECK_SIZE_NX150(CLASS, SIZE)
|
||||
#else
|
||||
#define KSYS_CHECK_SIZE_NX150(CLASS, SIZE) static_assert(sizeof(CLASS) == SIZE)
|
||||
#endif
|
||||
|
||||
namespace ksys::util {
|
||||
|
||||
/// For storing an enum with a particular storage size when specifying the underlying type of the
|
||||
/// enum is not an option.
|
||||
template <typename Enum, typename Storage>
|
||||
struct SizedEnum {
|
||||
static_assert(std::is_enum<Enum>());
|
||||
static_assert(!std::is_enum<Storage>());
|
||||
|
||||
constexpr SizedEnum() = default;
|
||||
constexpr SizedEnum(Enum value) { *this = value; }
|
||||
constexpr operator Enum() const { return static_cast<Enum>(mValue); }
|
||||
constexpr SizedEnum& operator=(Enum value) {
|
||||
mValue = static_cast<Storage>(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Storage mValue;
|
||||
};
|
||||
|
||||
} // namespace ksys::util
|
||||
Reference in New Issue
Block a user