diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a1aa8ff..df6e9957 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,8 @@ add_executable(uking src/KingSystem/ActorSystem/actBaseProcJob.h src/KingSystem/ActorSystem/actBaseProcJobHandler.cpp src/KingSystem/ActorSystem/actBaseProcJobHandler.h - src/KingSystem/ActorSystem/actBaseProcLinkDataMgr.cpp - src/KingSystem/ActorSystem/actBaseProcLinkDataMgr.h + src/KingSystem/ActorSystem/actBaseProcLink.cpp + src/KingSystem/ActorSystem/actBaseProcLink.h src/KingSystem/ActorSystem/actBaseProcMap.cpp src/KingSystem/ActorSystem/actBaseProcMap.h src/KingSystem/ActorSystem/actBaseProcMgr.cpp diff --git a/data/uking_functions.csv b/data/uking_functions.csv index a65a8bbb..81697797 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -74114,7 +74114,7 @@ 0x0000007100dca6d4,_ZN15ActorInstParams3BufaSERS0_,56, 0x0000007100dca70c,_ZN13ActorAccessorD2Ev,56,_ZN4ksys3act24ActorLinkConstDataAccessD1Ev 0x0000007100dca744,ActorAccessor::acquire,88,_ZN4ksys3act24ActorLinkConstDataAccess7acquireEPNS0_8BaseProcE -0x0000007100dca79c,act::acquireActorFromGameOrHavokThread,256,_ZN4ksys3act11acquireProcEPNS0_24ActorLinkConstDataAccessEPNS0_8BaseProcERKN4sead14SafeStringBaseIcEE +0x0000007100dca79c,act::acquireActorFromGameOrHavokThread,256,_ZN4ksys3act11acquireProcEPNS0_24ActorLinkConstDataAccessEPNS0_8BaseProcERKN4sead14SafeStringBaseIcEEi 0x0000007100dca89c,GameFramework::ctor,96, 0x0000007100dca8fc,GameFramework::dtor,64, 0x0000007100dca93c,GameFramework::dtorDelete,72, @@ -89523,18 +89523,18 @@ 0x00000071011bc42c,sub_71011BC42C,56, 0x00000071011bc464,sinitBaseProcHandle,172, 0x00000071011bc510,_ZN12BaseProcLinkC2Ev,20,_ZN4ksys3act12BaseProcLinkC1Ev -0x00000071011bc524,_ZN12BaseProcLink12acquireActorER13ActorAccessorP9ActorBase,308, +0x00000071011bc524,_ZN12BaseProcLink12acquireActorER13ActorAccessorP9ActorBase,308,_ZN4ksys3act12BaseProcLink7getProcEPNS0_24ActorLinkConstDataAccessEPNS0_8BaseProcE 0x00000071011bc658,BaseProcLinkData::lockCritSectionOnGameThreadOrHavokThread,68,_ZN4ksys3act16BaseProcLinkData12lockIfNeededEv 0x00000071011bc69c,BaseProcLinkData::checkIdAndEngaged,52,_ZNK4ksys3act16BaseProcLinkData7getProcEjb -0x00000071011bc6d0,_ZN12BaseProcLink12fromAccessorER13ActorAccessor,276, -0x00000071011bc7e4,BaseProcLink::checkHasActorById,40, -0x00000071011bc80c,_ZN12BaseProcLinkeqERS_,152, -0x00000071011bc8a4,BaseProcLink::hasAcquiredActor,100, -0x00000071011bc908,BaseProcLink::fromActor,328, -0x00000071011bca50,BaseProcLink::reset,52, -0x00000071011bca84,BaseProcLink::isStateCalc,204, -0x00000071011bcb50,BaseProcLink::isActor,228, -0x00000071011bcc34,_ZN12BaseProcLinkaSERS_,80, +0x00000071011bc6d0,_ZN12BaseProcLink12fromAccessorER13ActorAccessor,276,_ZN4ksys3act12BaseProcLink7getProcEPNS0_24ActorLinkConstDataAccessE +0x00000071011bc7e4,BaseProcLink::checkHasActorById,40,_ZNK4ksys3act12BaseProcLink11hasProcByIdEPNS0_8BaseProcE +0x00000071011bc80c,_ZN12BaseProcLinkeqERS_,152,_ZNK4ksys3act12BaseProcLinkeqERKS1_ +0x00000071011bc8a4,BaseProcLink::hasAcquiredActor,100,_ZNK4ksys3act12BaseProcLink7hasProcEv +0x00000071011bc908,BaseProcLink::fromActor,328,_ZN4ksys3act12BaseProcLink7acquireEPNS0_8BaseProcEb +0x00000071011bca50,BaseProcLink::reset,52,_ZN4ksys3act12BaseProcLink5resetEv +0x00000071011bca84,BaseProcLink::isStateCalc,204,_ZNK4ksys3act12BaseProcLink18hasProcInCalcStateEv +0x00000071011bcb50,BaseProcLink::isActor,228,_ZNK4ksys3act12BaseProcLink30isAccessingSpecifiedProcUnsafeEPNS0_8BaseProcE +0x00000071011bcc34,_ZN12BaseProcLinkaSERS_,80,_ZN4ksys3act12BaseProcLinkaSERKS1_ 0x00000071011bcc84,BaseProcLinkDataMgr::deleteInstance,132,_ZN4ksys3act19BaseProcLinkDataMgr18SingletonDisposer_D2Ev 0x00000071011bcd08,BaseProcLinkDataMgr::deleteInstance2,140,_ZN4ksys3act19BaseProcLinkDataMgr18SingletonDisposer_D0Ev 0x00000071011bcd94,BaseProcLinkDataMgr::createInstance,212,_ZN4ksys3act19BaseProcLinkDataMgr14createInstanceEPN4sead4HeapE diff --git a/lib/sead b/lib/sead index c53aff46..9f70679d 160000 --- a/lib/sead +++ b/lib/sead @@ -1 +1 @@ -Subproject commit c53aff46fc42344958c42d0b69b27f992fc8d979 +Subproject commit 9f70679d4cfbce260d967b27adf4c17f17ac8e34 diff --git a/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.cpp b/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.cpp index 91a3c860..8222b176 100644 --- a/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.cpp +++ b/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.cpp @@ -33,7 +33,8 @@ void ActorLinkConstDataAccess::debugLog(s32, const sead::SafeString&) { // Intentionally left empty. } -bool acquireProc(ActorLinkConstDataAccess* accessor, BaseProc* proc, const sead::SafeString& from) { +bool acquireProc(ActorLinkConstDataAccess* accessor, BaseProc* proc, const sead::SafeString& from, + s32) { bool acquired = false; if (accessor) { diff --git a/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.h b/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.h index 6727adfb..405a3d01 100644 --- a/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.h +++ b/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.h @@ -35,7 +35,8 @@ private: /// Acquire the specified BaseProc using `accessor`. Using ActorLinkConstDataAccess is mandatory /// when acquiring from a low priority thread (see BaseProcMgr for a definition). -bool acquireProc(ActorLinkConstDataAccess* accessor, BaseProc* proc, const sead::SafeString& from); +bool acquireProc(ActorLinkConstDataAccess* accessor, BaseProc* proc, const sead::SafeString& from, + s32 = 2); } // namespace act diff --git a/src/KingSystem/ActorSystem/actAiParam.h b/src/KingSystem/ActorSystem/actAiParam.h index b5df35c2..b15e9807 100644 --- a/src/KingSystem/ActorSystem/actAiParam.h +++ b/src/KingSystem/ActorSystem/actAiParam.h @@ -6,6 +6,7 @@ #include #include "KingSystem/ActorSystem/actBaseProc.h" +#include "KingSystem/ActorSystem/actBaseProcLink.h" #include "KingSystem/MessageSystem/mesTransceiver.h" #include "KingSystem/Utils/Types.h" diff --git a/src/KingSystem/ActorSystem/actBaseProc.cpp b/src/KingSystem/ActorSystem/actBaseProc.cpp index aef2365f..149386e2 100644 --- a/src/KingSystem/ActorSystem/actBaseProc.cpp +++ b/src/KingSystem/ActorSystem/actBaseProc.cpp @@ -1,14 +1,12 @@ #include "KingSystem/ActorSystem/actBaseProc.h" #include "KingSystem/ActorSystem/actBaseProcJobHandler.h" -#include "KingSystem/ActorSystem/actBaseProcLinkDataMgr.h" +#include "KingSystem/ActorSystem/actBaseProcLink.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(); diff --git a/src/KingSystem/ActorSystem/actBaseProc.h b/src/KingSystem/ActorSystem/actBaseProc.h index 5b378e5e..e0fde4c1 100644 --- a/src/KingSystem/ActorSystem/actBaseProc.h +++ b/src/KingSystem/ActorSystem/actBaseProc.h @@ -22,25 +22,6 @@ 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 { @@ -108,6 +89,9 @@ public: bool deleteLater(DeleteReason reason); void freeLinkData(); + u32 getId() const { return mId; } + const sead::SafeString& getName() const { return mName; } + u8 getPriority() const { return mPriority; } void setPriority(u8 priority) { mPriority = priority; } @@ -118,6 +102,7 @@ public: /// For BaseProcLink or ActorLinkConstDataAccess. bool acquire(ActorLinkConstDataAccess& accessor); + BaseProcLinkData* getBaseProcLinkData() const { return mBaseProcLinkData; } /// For BaseProcLink or ActorLinkConstDataAccess. void release(); diff --git a/src/KingSystem/ActorSystem/actBaseProcLink.cpp b/src/KingSystem/ActorSystem/actBaseProcLink.cpp new file mode 100644 index 00000000..a99960d9 --- /dev/null +++ b/src/KingSystem/ActorSystem/actBaseProcLink.cpp @@ -0,0 +1,160 @@ +#include "KingSystem/ActorSystem/actBaseProcLink.h" +#include +#include +#include "KingSystem/ActorSystem/actActorLinkConstDataAccess.h" +#include "KingSystem/ActorSystem/actBaseProc.h" +#include "KingSystem/ActorSystem/actBaseProcMgr.h" + +namespace ksys::act { + +BaseProcLink::BaseProcLink() = default; + +BaseProcLink& BaseProcLink::operator=(const BaseProcLink& rhs) { + if (this == &rhs) + return *this; + + reset(); + + if (rhs.mData) + mData = rhs.mData; + mId = rhs.mId; + + return *this; +} + +bool BaseProcLink::operator==(const BaseProcLink& rhs) const { + return (!hasProc() && !rhs.hasProc()) || mId == rhs.mId; +} + +bool BaseProcLink::hasProc() const { + return getProc(); +} + +bool BaseProcLink::hasProcInCalcState() const { + return getProcInContext( + [](BaseProc* proc) { return proc && proc->getState() == BaseProc::State::Calc; }); +} + +bool BaseProcLink::hasProcById(BaseProc* proc) const { + return proc != nullptr & mId != cInvalidId && mId == proc->getId(); +} + +BaseProc* BaseProcLink::getProc(ActorLinkConstDataAccess* accessor, BaseProc* other_proc) { + return getProcInContext([&](BaseProc* proc) -> BaseProc* { + if (proc && acquireProc(accessor, proc, "frm::BaseProcLink") && + BaseProcMgr::instance()->isAccessingProcSafe(proc, other_proc)) { + return proc; + } + return nullptr; + }); +} + +BaseProc* BaseProcLink::getProc(ActorLinkConstDataAccess* accessor) { + return getProcInContext([&](BaseProc* proc) -> BaseProc* { + if (proc && acquireProc(accessor, proc, "frm::BaseProcLink")) + return proc; + return nullptr; + }); +} + +bool BaseProcLink::acquire(BaseProc* proc, bool acquire_immediately) { + reset(); + + if (!proc || proc->isDeletedOrDeleting()) + return false; + + mData = proc->getBaseProcLinkData(); + + if (!mData) { + static constexpr const char* sStateNames[] = {"Init", "Calc", "Sleep", "Delete"}; + sead::FixedSafeString<256> message; + message.format("%s:%s", proc->getName().cstr(), sStateNames[u8(proc->getState())]); + return false; + } + + mId = proc->getId(); + if (acquire_immediately) { + mData->mRefCount.increment(); + mAcquired = true; + } + return true; +} + +void BaseProcLink::reset() { + if (mAcquired) { + mAcquired = false; + if (mData) + mData->mRefCount.decrement(); + } + mId = cInvalidId; +} + +bool BaseProcLink::isAccessingSpecifiedProcUnsafe(BaseProc* other) const { + return getProcInContext([&](BaseProc* proc) { + return proc && !BaseProcMgr::instance()->isAccessingProcSafe(proc, other); + }); +} + +SEAD_SINGLETON_DISPOSER_IMPL(BaseProcLinkDataMgr) + +BaseProc* BaseProcLinkData::getProc(u32 id, bool allow_deleted) const { + if (id == u32(-1) || mId != id) + return nullptr; + + if (!allow_deleted && (!mProc || mProc->getState() == BaseProc::State::Delete)) + return nullptr; + + return mProc; +} + +sead::CriticalSection* BaseProcLinkData::lockIfNeeded() { + if (BaseProcMgr::instance()->isHighPriorityThread()) + return nullptr; + + mCS.lock(); + return &mCS; +} + +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 diff --git a/src/KingSystem/ActorSystem/actBaseProcLink.h b/src/KingSystem/ActorSystem/actBaseProcLink.h new file mode 100644 index 00000000..df1e1aa6 --- /dev/null +++ b/src/KingSystem/ActorSystem/actBaseProcLink.h @@ -0,0 +1,119 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "KingSystem/Utils/Types.h" + +namespace ksys::act { + +class ActorLinkConstDataAccess; +class BaseProc; +class BaseProcLinkData; + +class BaseProcLink { +public: + BaseProcLink(); + ~BaseProcLink() { reset(); } + BaseProcLink& operator=(const BaseProcLink& rhs); + + bool operator==(const BaseProcLink& rhs) const; + bool operator!=(const BaseProcLink& rhs) const { return !operator==(rhs); } + explicit operator bool() const { return hasProc(); } + + bool hasProc() const; + bool hasProcInCalcState() const; + bool hasProcById(BaseProc* proc) const; + + BaseProc* getProc(ActorLinkConstDataAccess* accessor, BaseProc* other_proc); + BaseProc* getProc(ActorLinkConstDataAccess* accessor); + + /// Acquire the specified BaseProc. + /// If a BaseProc has already been specified, it is released. + /// + /// @param acquire_immediately If true, the BaseProc's reference count is immediately + /// incremented. Otherwise, full acquisition is delayed until + /// the next call to getProc(accessor[, proc]). + bool acquire(BaseProc* proc, bool acquire_immediately); + void reset(); + + bool isAccessingSpecifiedProcUnsafe(BaseProc* other) const; + +private: + static constexpr u32 cInvalidId = -1; + + BaseProc* getProc() const; + + template + auto getProcInContext(const Function& function) const; + + BaseProcLinkData* mData = nullptr; + u32 mId = cInvalidId; + bool mAcquired = false; +}; +KSYS_CHECK_SIZE_NX150(BaseProcLink, 0x10); + +class BaseProcLinkData { +public: + u32 id() const { return mId; } + s32 refCount() const { return mRefCount; } + + /// Get the stored BaseProc. + BaseProc* getProc() const { return mProc; } + /// Get the stored BaseProc or nullptr if its ID or state are unexpected. + /// @param id The expected ID. + /// @param allow_deleted Whether to allow the BaseProc to be in the Delete state. + BaseProc* getProc(u32 id, bool allow_deleted) const; + + /// Locks the critical section if on a low priority thread and returns it; + /// unlocking it is the responsibility of the caller. + /// Returns nullptr if on a high priority thread. In that case, nothing needs to be done. + sead::CriticalSection* lockIfNeeded(); + +private: + friend class BaseProcLink; + friend class BaseProcLinkDataMgr; + + sead::CriticalSection mCS; + u32 mId = -1; + BaseProc* mProc = nullptr; + sead::Atomic 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 mData{}; +}; +KSYS_CHECK_SIZE_NX150(BaseProcLinkDataMgr, 0x2C068); + +inline BaseProc* BaseProcLink::getProc() const { + return mData->getProc(mId, mAcquired); +} + +template +inline auto BaseProcLink::getProcInContext(const Function& function) const { + if (mId == cInvalidId) + return function(nullptr); + + const auto guard = sead::makeScopeGuard([crit_section = mData->lockIfNeeded()] { + if (crit_section) + crit_section->unlock(); + }); + + return function(getProc()); +} + +} // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actBaseProcLinkDataMgr.cpp b/src/KingSystem/ActorSystem/actBaseProcLinkDataMgr.cpp deleted file mode 100644 index 8479ae09..00000000 --- a/src/KingSystem/ActorSystem/actBaseProcLinkDataMgr.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "KingSystem/ActorSystem/actBaseProcLinkDataMgr.h" -#include -#include -#include "KingSystem/ActorSystem/actBaseProc.h" -#include "KingSystem/ActorSystem/actBaseProcMgr.h" - -namespace ksys::act { - -SEAD_SINGLETON_DISPOSER_IMPL(BaseProcLinkDataMgr) - -BaseProc* BaseProcLinkData::getProc(u32 id, bool allow_deleted) const { - if (id == u32(-1) || mId != id) - return nullptr; - - if (!allow_deleted && mProc && mProc->getState() == BaseProc::State::Delete) - return nullptr; - - return mProc; -} - -sead::CriticalSection* BaseProcLinkData::lockIfNeeded() { - if (BaseProcMgr::instance()->isHighPriorityThread()) - return nullptr; - - mCS.lock(); - return &mCS; -} - -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 diff --git a/src/KingSystem/ActorSystem/actBaseProcLinkDataMgr.h b/src/KingSystem/ActorSystem/actBaseProcLinkDataMgr.h deleted file mode 100644 index 7ce56373..00000000 --- a/src/KingSystem/ActorSystem/actBaseProcLinkDataMgr.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include "KingSystem/Utils/Types.h" - -namespace ksys::act { - -class BaseProc; - -class BaseProcLinkData { -public: - u32 id() const { return mId; } - s32 refCount() const { return mRefCount; } - - /// Get the stored BaseProc. - BaseProc* getProc() const { return mProc; } - /// Get the stored BaseProc or nullptr if its ID or state are unexpected. - /// @param id The expected ID. - /// @param allow_deleted Whether to allow the BaseProc to be in the Delete state. - BaseProc* getProc(u32 id, bool allow_deleted) const; - - /// Locks the critical section if on a low priority thread and returns it; - /// unlocking it is the responsibility of the caller. - /// Returns nullptr if on a high priority thread. In that case, nothing needs to be done. - sead::CriticalSection* lockIfNeeded(); - -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 mData{}; -}; -KSYS_CHECK_SIZE_NX150(BaseProcLinkDataMgr, 0x2C068); - -} // namespace ksys::act