Initial commit

This commit is contained in:
Léo Lam
2020-06-05 17:09:06 +02:00
commit 2de366be0f
52 changed files with 113067 additions and 0 deletions
+24
View File
@@ -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
+22
View File
@@ -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
+20
View File
@@ -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
+17
View File
@@ -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
+44
View File
@@ -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
+110
View File
@@ -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
+113
View File
@@ -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
+409
View File
@@ -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
+286
View File
@@ -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
+219
View File
@@ -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
View File
+34
View File
@@ -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
+45
View File
@@ -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
+31
View File
@@ -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