diff --git a/data/uking_functions.csv b/data/uking_functions.csv index f3b3e6d93..83813bffd 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -73599,31 +73599,31 @@ Address,Quality,Size,Name 0x0000007100d375e4,O,000076,_ZN4ksys3map16LazyTraverseListD1Ev 0x0000007100d37630,O,000132,_ZN4ksys3map16LazyTraverseList11updateFlagsEv 0x0000007100d376b4,O,000216,_ZN4ksys3map16LazyTraverseList16wereFlagsUpdatedEv -0x0000007100d3778c,U,000204,LinkTag::construct -0x0000007100d37858,U,000280,LinkTag::calc -0x0000007100d37970,U,000064,LinkTag::dtor -0x0000007100d379b0,U,000072,LinkTag::dtorDelete -0x0000007100d379f8,U,001656,LinkTag::init2 +0x0000007100d3778c,W,000204,_ZN4ksys3act7LinkTag9constructERKNS0_8BaseProc9CreateArgEPN4sead4HeapE +0x0000007100d37858,W,000280,_ZN4ksys3act7LinkTag4calcEv +0x0000007100d37970,O,000064,_ZN4ksys3act7LinkTagD1Ev +0x0000007100d379b0,O,000072,_ZN4ksys3act7LinkTagD0Ev +0x0000007100d379f8,W,001656,_ZN4ksys3act7LinkTag4initEv 0x0000007100d38070,U,000256,isLinkTagNAndOrNOr 0x0000007100d38170,U,000308,map::isFlagSet -0x0000007100d382a4,U,000056,LinkTag::finalizeInit -0x0000007100d382dc,U,000188,LinkTag::prepareForPreDelete -0x0000007100d38398,U,000092,LinkTag::isDonePreparingForPreDelete -0x0000007100d383f4,U,000320,LinkTag::calcCount -0x0000007100d38534,U,000748,LinkTag::calcPulse +0x0000007100d382a4,O,000056,_ZN4ksys3act7LinkTag12finalizeInitEPNS0_8BaseProc11InitContextE +0x0000007100d382dc,O,000188,_ZN4ksys3act7LinkTag20prepareForPreDelete_Ev +0x0000007100d38398,O,000092,_ZN4ksys3act7LinkTag27isDonePreparingForPreDeleteEv +0x0000007100d383f4,W,000320,_ZN4ksys3act7LinkTag9calcCountEb +0x0000007100d38534,W,000748,_ZN4ksys3act7LinkTag9calcPulseEb 0x0000007100d38820,U,001372,LinkTag::calcOther -0x0000007100d38d7c,U,000372,LinkTag::onEnterCalc -0x0000007100d38ef0,U,000076,LinkTag::hasJobType -0x0000007100d38f3c,U,000132,LinkTag::queueExtraJobPush -0x0000007100d38fc0,U,000008,LinkTag::isSpecialJobType -0x0000007100d38fc8,U,000148,LinkTag::canWakeUp -0x0000007100d3905c,U,000064,LinkTag::shouldSkipJobPush_ -0x0000007100d3909c,U,000132,LinkTag::prePushJob2 +0x0000007100d38d7c,O,000372,_ZN4ksys3act7LinkTag11onEnterCalcEv +0x0000007100d38ef0,O,000076,_ZN4ksys3act7LinkTag10hasJobTypeENS0_7JobTypeE +0x0000007100d38f3c,O,000132,_ZN4ksys3act7LinkTag17queueExtraJobPushENS0_7JobTypeEj +0x0000007100d38fc0,O,000008,_ZN4ksys3act7LinkTag16isSpecialJobTypeEv +0x0000007100d38fc8,O,000148,_ZN4ksys3act7LinkTag9canWakeUpEv +0x0000007100d3905c,O,000064,_ZN4ksys3act7LinkTag17shouldSkipJobPushEv +0x0000007100d3909c,O,000132,_ZN4ksys3act7LinkTag11prePushJob2Ev 0x0000007100d39120,U,000172, -0x0000007100d391cc,U,000596,LinkTag::updateIsFlagSetFlag +0x0000007100d391cc,O,000596,_ZN4ksys3act7LinkTag19updateIsFlagSetFlagEbbb 0x0000007100d39420,U,000052, 0x0000007100d39454,U,000588,isAreaOrLinkTagOrOtherTag -0x0000007100d396a0,U,000584,LinkTag::isTriggered +0x0000007100d396a0,W,000584,_ZN4ksys3act7LinkTag11isTriggeredEPNS_3map10ObjectLinkEh 0x0000007100d398e8,U,000124,PlacementObj::checkRevivalMaybe 0x0000007100d39964,U,000492,map::getLinkTagRevivalGameDataFlagHash 0x0000007100d39b50,U,000332,map::getLinkTagSaveFlagName @@ -73631,8 +73631,8 @@ Address,Quality,Size,Name 0x0000007100d39d60,U,000132, 0x0000007100d39de4,U,000072, 0x0000007100d39e2c,U,000028, -0x0000007100d39e48,U,000204,LinkTag::rtti1 -0x0000007100d39f14,U,000092,LinkTag::rtti2 +0x0000007100d39e48,O,000204,_ZNK4ksys3act7LinkTag27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x0000007100d39f14,O,000092,_ZNK4ksys3act7LinkTag18getRuntimeTypeInfoEv 0x0000007100d39f70,O,000004,_ZN4ksys3act8BaseProc18onDeleteRequested_ENS1_12DeleteReasonE 0x0000007100d39f74,O,000004,_ZN4ksys3act8BaseProc17onSleepRequested_ENS1_15SleepWakeReasonE 0x0000007100d39f78,O,000004,_ZN4ksys3act8BaseProc18onWakeUpRequested_ENS1_15SleepWakeReasonE diff --git a/src/KingSystem/ActorSystem/CMakeLists.txt b/src/KingSystem/ActorSystem/CMakeLists.txt index c071fdf2e..00bf6f300 100644 --- a/src/KingSystem/ActorSystem/CMakeLists.txt +++ b/src/KingSystem/ActorSystem/CMakeLists.txt @@ -107,6 +107,8 @@ target_sources(uking PRIVATE actInstParamPack.cpp actInstParamPack.h actLifeRecoveryInfo.h + actLinkTag.cpp + actLinkTag.h actPlayerInfo.cpp actPlayerInfo.h actTag.h diff --git a/src/KingSystem/ActorSystem/actActor.h b/src/KingSystem/ActorSystem/actActor.h index 71d5d0f8b..607aa649e 100644 --- a/src/KingSystem/ActorSystem/actActor.h +++ b/src/KingSystem/ActorSystem/actActor.h @@ -5,6 +5,7 @@ #include #include "KingSystem/ActorSystem/actBaseProc.h" #include "KingSystem/Map/mapMubinIter.h" +#include "KingSystem/Map/mapObjectLink.h" namespace ksys { @@ -64,6 +65,7 @@ class Actor : public BaseProc { const ActorParam* getParam() const { return mActorParam; } map::Object* getMapObject() const { return mMapObject; } const map::MubinIter& getMapObjIter() const { return mMapObjIter; } + map::MapLinkDefType getEmittedSignalType() const { return mEmittedSignalType; } bool checkFlag(ActorFlag flag) const; bool deleteEx(DeleteType type, DeleteReason reason, bool* ok = nullptr); @@ -105,7 +107,8 @@ class Actor : public BaseProc { /* 0x658 */ u8 TEMP_0x650[0x710 - 0x658]; /* ..... */ // The name could be incorrect. /* 0x710 */ sead::TypedBitFlag mStasisFlags; - /* 0x714 */ u8 TEMP_0x714[0x7b0 - 0x714]; // FIXME + /* 0x714 */ map::MapLinkDefType mEmittedSignalType; + /* 0x718 */ u8 TEMP_0x714[0x7b0 - 0x718]; // FIXME /* 0x7b0 */ ActorCreator* mCreator{}; /* 0x7b8 */ sead::ListNode mCreatorListNode; /* 0x7c8 */ map::Object* mMapObject; diff --git a/src/KingSystem/ActorSystem/actBaseProcMgr.h b/src/KingSystem/ActorSystem/actBaseProcMgr.h index 3f0df876a..14f965e03 100644 --- a/src/KingSystem/ActorSystem/actBaseProcMgr.h +++ b/src/KingSystem/ActorSystem/actBaseProcMgr.h @@ -214,12 +214,15 @@ class BaseProcMgr { void incrementPendingDeletions() { mNumPendingDeletions.increment(); } void decrementPendingDeletions() { mNumPendingDeletions.decrement(); } + s8 getCurrentExtraJobArrayIdx() const { return mCurrentExtraJobArrayIdx; } Status getStatus() const { return mStatus; } JobType getJobType() const { return mJobType; } u32 getNumJobTypes() const { return mJobLists.size(); } BaseProcJobLists& getJobLists(JobType type) { return mJobLists[u32(type)]; } bool isPushingJobs() const { return mIsPushingJobs; } + void setPushActorJobType3InsteadOf6(bool value) { mPushActorJobType3InsteadOf6 = value; } + static u32 sConstant0; static u32 sConstant1; static u32 sConstant2; diff --git a/src/KingSystem/ActorSystem/actLinkTag.cpp b/src/KingSystem/ActorSystem/actLinkTag.cpp new file mode 100644 index 000000000..2f72f4ff1 --- /dev/null +++ b/src/KingSystem/ActorSystem/actLinkTag.cpp @@ -0,0 +1,650 @@ +#include "KingSystem/ActorSystem/actLinkTag.h" + +#include +#include "KingSystem/ActorSystem/actBaseProcMgr.h" +#include "KingSystem/GameData/gdtManager.h" +#include "KingSystem/Map/mapObject.h" +#include "KingSystem/System/MCMgr.h" +#include "KingSystem/System/SystemTimers.h" + +namespace ksys::act { + +LinkTag* LinkTag::construct(const BaseProc::CreateArg& arg, sead::Heap* heap) { + return new (heap, std::nothrow) LinkTag(arg); +} + +LinkTag::LinkTag(const BaseProc::CreateArg& arg) : BaseProc(arg), mJob(this, &LinkTag::calc) { + mJobHandlers[3] = &mJob; +} + +LinkTag::~LinkTag() { + if (getSceneStatus() != 4) { + mJobFlags.load(); + } +} + +bool LinkTag::init() { + if (mName == "LinkTagOr") + mLinkTagType = Type::Or; + else if (mName == "LinkTagNOr") + mLinkTagType = Type::NOr; + else if (mName == "LinkTagNAnd") + mLinkTagType = Type::NAnd; + else if (mName == "LinkTagXOr") + mLinkTagType = Type::XOr; + else if (mName == "LinkTagAnd") + mLinkTagType = Type::And; + else if (mName == "LinkTagCount") + mLinkTagType = Type::Count; + else if (mName == "LinkTagPulse") + mLinkTagType = Type::Pulse; + else if (mName == "LinkTagNone") + mLinkTagType = Type::None; + + if (mName == "LinkTagNAnd" || mName == "LinkTagNOr") + mFlags.set(LinkTagFlag::_4); + + int noChangeSignalValue = 0; + mMubinIter.tryGetParamIntByKey(&noChangeSignalValue, "NoChangeSignal"); + if (noChangeSignalValue != 0) + mFlags.set(LinkTagFlag::_40); + + int saveFlagOnOffTypeValue = 0; + if (mMubinIter.tryGetParamIntByKey(&saveFlagOnOffTypeValue, "SaveFlagOnOffType")) { + if (saveFlagOnOffTypeValue == 2) + mFlags.set(LinkTagFlag::_200); + else if (saveFlagOnOffTypeValue == 1) + mFlags.set(LinkTagFlag::_100); + } + + bool flagSet = false; + isFlagSet(&flagSet, 0, mMapObj); + updateIsFlagSetFlag(flagSet, 1, 1); + if (flagSet) { + mFlags.set(LinkTagFlag::_10); + mTriggeredLinkFlags.makeAllOne(); + mFlags.set(LinkTagFlag::_20); + } else { + mFlags.reset(LinkTagFlag::_10); + mTriggeredLinkFlags.makeAllZero(); + mFlags.reset(LinkTagFlag::_20); + } + return true; +} + +void LinkTag::finalizeInit(BaseProc::InitContext* context) { + if (mMapObj) + mMapObj->registerBaseProc(this); + BaseProc::finalizeInit_(context); +} + +void LinkTag::calc() { + if (this->mState != BaseProc::State::Delete && !_1de) { + int currentExtraJobArrayIdx = BaseProcMgr::instance()->getCurrentExtraJobArrayIdx(); + s32 currentCounter = SystemTimers::instance() ? SystemTimers::instance()->mFrameCounter : 0; + s32 oldCounter = mCounter; + mCounter = currentCounter; + + switch (mLinkTagType) { + case Type::Count: + calcCount(mCounter != oldCounter); + break; + case Type::Pulse: + calcPulse(mCounter != oldCounter); + break; + case Type::None: + break; + default: + calcOther(mCounter != oldCounter); + break; + } + if (mFlags.isOff(LinkTagFlag::_1)) { + mFlags.set(LinkTagFlag::_1); + if (mMapObj && mMapObj->getLinkData()) + mMapObj->getLinkData()->setNumExecLinkTagTo1(); + } + mFlags.reset(LinkTagFlag::_1000); + mJobFlags.setBitOff(currentExtraJobArrayIdx ^ 1); + } +} + +inline s8 LinkTag::getSelfLinkCount() { + if (!mMapObj || !mMapObj->getLinkData()) + return 0; + auto& links = mMapObj->getLinkData()->mLinksToSelf.links; + s8 linkCount = 0; + + s32 end = std::min(links.size(), 0x60); + for (s32 i = 0; i < end; i++) { + auto& link = links[i]; + if (link.type <= map::MapLinkDefType::ChangeAtnSig && isTriggered(&link, i)) + linkCount += 1; + } + return linkCount; +} + +void LinkTag::calcCount(bool update) { + if (mFlags.isOff(LinkTagFlag::_1) || !mMapObj) + return; + + s8 linkCount = 0; + if (mMapObj->getLinkData()) { + auto& links = mMapObj->getLinkData()->mLinksToSelf.links; + + s32 end = std::min(links.size(), 0x60); + for (s32 i = 0; i < end; i++) { + auto& link = links[i]; + if (link.type <= map::MapLinkDefType::ChangeAtnSig && isTriggered(&link, i)) + linkCount += 1; + } + } + + mFlags.reset(LinkTagFlag::_10); + if (linkCount != mTagCount) { + mTagCount = linkCount; + gdt::Manager::instance()->setS32ByIdxForLinkTag(linkCount, + mMapObj->getRevivalGameDataFlagHash()); + updateIsFlagSetFlag(mTagCount > 0, false, update); + } +} + +void LinkTag::calcPulse(bool update) { + if (mFlags.isOff(LinkTagFlag::_1)) { + if (mMapObj && mMapObj->getLinkData()) { // maybe inlined getSelfLinkCount? + auto& links = mMapObj->getLinkData()->mLinksToSelf.links; + s32 end = std::min(links.size(), 0x60); + for (s32 i = 0; i < end; i++) { + auto& link = links[i]; + if (link.type <= map::MapLinkDefType::ChangeAtnSig && isTriggered(&link, i)) + mTagCount += 1; + } + } + mFlags.reset(LinkTagFlag::_10); + return; + } + + bool something = mFlags.isOn(LinkTagFlag::_80); + s8 selfLinkCount = getSelfLinkCount(); + s8 oldTagCount = mTagCount; + mTagCount = selfLinkCount; + + if (update) { + if ((mTagCount != oldTagCount) == mFlags.isOn(LinkTagFlag::_8)) { + something = mFlags.isOn(LinkTagFlag::_80); + mFlags.reset(LinkTagFlag::_10); + } else { + something = true; + updateIsFlagSetFlag(mTagCount != oldTagCount, false, true); + } + + if (selfLinkCount != oldTagCount) { + mFlags.set(LinkTagFlag::_2000); + if (mMapObj && mMapObj->getLinkData()) { + for (auto& link : mMapObj->getLinkData()->mLinksOther.links) { + if (link.type == map::MapLinkDefType::OffWaitRevival && link.other_obj) { + gdt::Manager::instance()->setBoolByHash( + false, link.other_obj->getRevivalGameDataFlagHash()); + } + } + } + } else { + mFlags.reset(LinkTagFlag::_2000); + } + } + if (!something) + return; + + if (mMapObj) { + if (mMapObj->getLinkData()) { + for (auto& link : mMapObj->getLinkData()->mLinksOther.links) { + ActorLinkConstDataAccess acc{}; + link.getObjectProcWithAccessor(acc); + triggerLink(acc); + } + } + if (mMapObj->getRevivalGameDataFlagHash() != gdt::InvalidHandle) { + BaseProcMgr::instance()->setPushActorJobType3InsteadOf6(true); + } + } + mFlags.reset(LinkTagFlag::_80); +} + +void LinkTag::onEnterCalc() { + if (mLinkTagType == Type::Pulse) { + mFlags.set(LinkTagFlag::_4000); + if (mMapObj) { + auto mapLinkData = mMapObj->getLinkData(); + if (mapLinkData) { + // inlined getSelfLinkCount? + auto& links = mMapObj->getLinkData()->mLinksToSelf.links; + + s32 end = std::min(links.size(), 0x60); + for (s32 i = 0; i < end; i++) { + auto& link = links[i]; + if (link.type <= map::MapLinkDefType::ChangeAtnSig && isTriggered(&link, i)) + mTagCount += 1; + } + } + } + mFlags.reset(LinkTagFlag::_10); + } + _1dd = 0; + mFlags.reset(LinkTagFlag::_1081); + mFlags.set(LinkTagFlag::_80); + + if (mMapObj) { + if (mMapObj->getRevivalGameDataFlagHash() != gdt::InvalidHandle) + mFlags.set(LinkTagFlag::_4000); + s8 extraJobArrayId = BaseProcMgr::instance()->getCurrentExtraJobArrayIdx(); + if (!isDeletedOrDeleting() && mJobFlags.setBitOn(extraJobArrayId)) { + BaseProcMgr::instance()->queueExtraJobPush(&mJob.getLink()); + } + } +} + +void LinkTag::updateIsFlagSetFlag(bool isFlagSet, bool a3, bool a4) { + if (!mMapObj) + return; + + mFlags.change(LinkTagFlag::_8, isFlagSet); + + if (mFlags.isOff(LinkTagFlag::_40) || a3) { + mMapObj->getFlags0().change(map::Object::Flag0::_100, isFlagSet); + + if (mFlags.isOff(LinkTagFlag::_40)) { + auto weirdFlag = + isFlagSet == mMapObj->getFlags().isOn(map::Object::Flag::IsLinkTagNAndOrNOr); + int frameCounter = + SystemTimers::instance() ? SystemTimers::instance()->mFrameCounter : 0; + + if (mMapObj->getLinkData()) { + for (auto& mapLink : mMapObj->getLinkData()->mLinksOther.links) { + if (!mapLink.other_obj) + continue; + + switch (mapLink.type) { + case map::MapLinkDefType::Create: + case map::MapLinkDefType::MtxCopyCreate: + if (weirdFlag) { + if (mapLink.other_obj->getFlags0().isOff( + map::Object::Flag0::_10000000)) { + mapLink.other_obj->getFlags0().set(map::Object::Flag0::_10000000); + _1E8 = frameCounter; + } + } else if (_1E8 == frameCounter) { + mapLink.other_obj->getFlags0().reset(map::Object::Flag0::_10000000); + } + break; + case map::MapLinkDefType::Delete: + if (!weirdFlag) { + if (mapLink.other_obj->getFlags0().isOff( + map::Object::Flag0::_20000000)) { + mapLink.other_obj->getFlags0().set(map::Object::Flag0::_20000000); + _1E8 = frameCounter; + } + } else if (_1E8 == frameCounter) { + mapLink.other_obj->getFlags0().reset(map::Object::Flag0::_20000000); + } + break; + } + } + } + } + } + + bool v0 = isFlagSet != mFlags.isOn(LinkTagFlag::_4); + + if (a4) { + mFlags.reset(LinkTagFlag::_800); + } + if (v0) { + if (mFlags.isOff(LinkTagFlag::_400)) { + mFlags.set(LinkTagFlag::_800); + } + mFlags.set(LinkTagFlag::_400); + } else if (mFlags.isOn(LinkTagFlag::_800)) { + mFlags.reset(LinkTagFlag::_800); + mFlags.reset(LinkTagFlag::_400); + } + + if (!a3) { + auto* mapLinkData = mMapObj->getLinkData(); + if (mapLinkData) { + if (mapLinkData->isGenGroupInitState3() && + (mapLinkData->findLinkWithType(map::MapLinkDefType::Create) || + mapLinkData->findLinkWithType(map::MapLinkDefType::Delete) || + mapLinkData->findLinkWithType(map::MapLinkDefType::MtxCopyCreate))) { + mapLinkData->sub_7100D4FA90(); + } + } + } +} + +BaseProc::PreDeletePrepareResult LinkTag::prepareForPreDelete_() { + if (!BaseProc::startPreparingForPreDelete_()) + return PreDeletePrepareResult::NotDone; + if (!mJobFlags) + return PreDeletePrepareResult::Done; + + auto jobLink = &mJob.getLink(); + if (mJobFlags.isBitOn(0)) { + if (BaseProcMgr::instance()->hasExtraJobLink(jobLink, 0)) + return PreDeletePrepareResult::NotDone; + mJobFlags.setBitOff(0); + } + + if (mJobFlags.isBitOn(1)) { + if (BaseProcMgr::instance()->hasExtraJobLink(jobLink, 1)) + return PreDeletePrepareResult::NotDone; + mJobFlags.setBitOff(1); + } + return PreDeletePrepareResult::Done; +} + +bool LinkTag::isDonePreparingForPreDelete() { + if (!mMapObj) + return true; + auto linkData = mMapObj->getLinkData(); + if (linkData && mFlags.isOn(LinkTagFlag::_8000)) { + linkData->x_3(true); + linkData->printDebugInfo(); + } + mMapObj->unlinkProc(true); + mMapObj = nullptr; + return true; +} + +bool LinkTag::hasJobType(JobType jobType) { + if (jobType != JobType::Calc3) + return false; + if (mFlags.isOn(LinkTagFlag::_4000)) + return true; + if (!mMapObj || mMapObj->getRevivalGameDataFlagHash() == gdt::InvalidHandle) + return mLinkTagType == Type::Pulse; + else + return true; +} + +bool LinkTag::shouldSkipJobPush() { + if (mJobFlags.isBitOn(BaseProcMgr::instance()->getCurrentExtraJobArrayIdx())) + return true; + + if (mFlags.isOn(LinkTagFlag::_1000)) + return false; + else + return mFlags.isOff(LinkTagFlag::_2000); +} + +bool LinkTag::isSpecialJobType() { + return false; +} + +void LinkTag::queueExtraJobPush(JobType jobType, u32 jobFlagBit) { + if (jobType == JobType::Calc3) { + mJobFlags.setBitOff(1 ^ jobFlagBit); + s8 extraJobArrayId = BaseProcMgr::instance()->getCurrentExtraJobArrayIdx(); + if (!isDeletedOrDeleting() && mJobFlags.setBitOn(extraJobArrayId)) { + BaseProcMgr::instance()->queueExtraJobPush(&mJob.getLink()); + } + } +} + +bool LinkTag::canWakeUp() { + if (mMapObj && mMapObj->getLinkData()) { + auto linkData = mMapObj->getLinkData(); + if (mFlags.isOff(LinkTagFlag::_8000)) { + mFlags.set(LinkTagFlag::_8000); + linkData->x_8(true); + linkData->x_9(); + } + if (!linkData->x_7(true)) + return false; + } + if (mMapObj && mMapObj->getLinkData()) { + if (mMapObj->getLinkData()->findLinkWithType(map::MapLinkDefType::MtxCopyCreate)) + mFlags.set(LinkTagFlag::_2); + } + + return true; +} + +void LinkTag::prePushJob2() { + if (MCMgr::instance()) { + if (_1dd == MCMgr::instance()->mCalcJobCounterMaybe) { + mFlags.set(LinkTagFlag::_1000); // Here + } else if (mMapObj) { + bool a1 = false; + if (isFlagSet(&a1, 1, mMapObj)) { + if (mFlags.isOn(LinkTagFlag::_8) != a1) { + mFlags.set(LinkTagFlag::_1000); // duplicate usage with above that gets + // removed in ASM + } + } + } + } + _1dd.storeNonAtomic(0xff); +} + +/*void LinkTag::calcOther(bool update) { + if (update) + _1E3 = 0; + + bool flagIsSet = false; + if (isFlagSet(&flagIsSet, 1, mMapObj) && flagIsSet != mFlags.isOn(LinkTagFlag::_8)) { + updateIsFlagSetFlag(flagIsSet, 0, update); + if (mMapObj) { + auto* linkData = mMapObj->getLinkData(); + if (linkData) { + for (auto& link : linkData->mLinksOther.links) { + ksys::act::ActorLinkConstDataAccess accessor{}; + link.getObjectProcWithAccessor(accessor); + triggerLink(accessor); + } + } + goto LABEL_111; + } + goto end; + } else { + if (mMapObj) { + auto* linkData = mMapObj->getLinkData(); + if (linkData) { + auto& links = linkData->mLinksToSelf.links; + if (links.size()) { + bool status; + s32 end; + + bool v35, v36; + gdt::FlagHandle flagHash; + switch (mLinkTagType) { + case Type::And: + case Type::NAnd: + status = true; + end = std::min(links.size(), 0x60); + for (s32 i = 0; i < end; i++) { + auto& link = links[i]; + if (link.type <= map::MapLinkDefType::ChangeAtnSig) + status &= isTriggered(&link, i); + } + goto common; + case Type::Or: + case Type::NOr: + status = false; + end = std::min(links.size(), 0x60); + for (s32 i = 0; i < end; i++) { + auto& link = links[i]; + if (link.type <= map::MapLinkDefType::ChangeAtnSig) + status |= isTriggered(&link, i); + } + goto common; + case Type::XOr: + status = false; + end = std::min(links.size(), 0x60); + for (s32 i = 0; i < end; i++) { + auto& link = links[i]; + if (link.type <= map::MapLinkDefType::ChangeAtnSig) + status ^= isTriggered(&link, i); + } + common: + mFlags.change(LinkTagFlag::_10, status); + if (mMapObj) + goto LABEL_61; + else { + v36 = 1; + flagHash = gdt::InvalidHandle; + v35 = 0; + } + break; + default: + status = false; + LABEL_61: + flagHash = mMapObj->getRevivalGameDataFlagHash(); + v35 = 0; + v36 = mMapObj->getFlags0().isOn(map::Object::Flag0::_2); + break; + } + + if (status != mFlags.isOn(LinkTagFlag::_8)) { + if (_1E3) + _1E3 = 0; + else if (v36 || (mFlags.isOn(LinkTagFlag::_100))) { + status = true; + if (!v36 && mFlags.isOff(LinkTagFlag::_8)) { + status = true; + _1E3 = 1; + } + } else { + status &= mFlags.isOff(LinkTagFlag::_200); + if (mFlags.isOn(LinkTagFlag::_200) && mFlags.isOn(LinkTagFlag::_8)) { + status = false; + _1E3 = 1; + } + } + } + + if (!v35 && mFlags.isOn(LinkTagFlag::_8)) + goto LABEL_105; + else if (status != mFlags.isOn(LinkTagFlag::_8)) { + updateIsFlagSetFlag(status, false, update); + if (flagHash != gdt::InvalidHandle) { + if (!v36) { + gdt::Manager::instance()->setBoolByHash(status, flagHash); + if (BaseProcMgr::instance()->getJobType() == JobType::Calc3 && + MCMgr::instance()) { + if (MCMgr::instance()->mCalcJobCounterMaybe >= 1) + BaseProcMgr::instance()->setPushActorJobType3InsteadOf6( + true); + } + if (mState == State::Calc) { + if (mStateFlags.isOff(StateFlags::RequestDelete)) { + if (mJobFlags.setBitOn( + BaseProcMgr::instance() + ->getCurrentExtraJobArrayIdx())) { + BaseProcMgr::instance()->queueExtraJobPush( + &mJob.getLink()); + } + } + } + _1dd.storeNonAtomic(MCMgr::instance() ? + MCMgr::instance()->mCalcJobCounterMaybe : + 0); + if (!mMapObj) + goto end; + goto LABEL_107; + } else if (status) { + gdt::Manager::instance()->setS32ByIdxForLinkTag(true, flagHash); + if (!mMapObj) + goto end; + goto LABEL_107; + } + } + goto LABEL_106; + } else if (!v36 || mFlags.isOn(LinkTagFlag::_10) || + mFlags.isOff(LinkTagFlag::_10)) { + LABEL_105: + if (mFlags.isOff(LinkTagFlag::_80)) + return; + LABEL_106: + if (mMapObj) { + LABEL_107: + if (mMapObj->getLinkData()) { + for (auto& link : mMapObj->getLinkData()->mLinksOther.links) { + ActorLinkConstDataAccess acc{}; + link.getObjectProcWithAccessor(acc); + triggerLink(acc); + } + } + LABEL_111: + if (mMapObj->getRevivalGameDataFlagHash() != gdt::InvalidHandle) { + BaseProcMgr::instance()->setPushActorJobType3InsteadOf6(true); + } + } + end: + mFlags.reset(LinkTagFlag::_80); + return; + } else { + int value = 0; + gdt::Manager::instance()->getParamBypassPerm().get().getS32( + &value, ""); // wrong string + gdt::Manager::instance()->setS32ByIdxForLinkTag(value, flagHash); + } + } + } + } + } +}*/ + +inline void setBitAfterCheck(sead::LongBitFlag<96>* mTriggeredLinkFlags, s8 linkIdx) { + if (linkIdx < 0x60) + mTriggeredLinkFlags->setBit(linkIdx); +} +inline void resetBitAfterCheck(sead::LongBitFlag<96>* mTriggeredLinkFlags, s8 linkIdx) { + if (linkIdx < 0x60) + mTriggeredLinkFlags->resetBit(linkIdx); +} + +bool LinkTag::isTriggered(map::ObjectLink* link, u8 linkIdx) { + auto* otherObj = link->other_obj; + if (!otherObj) + return mTriggeredLinkFlags.isOnBit(linkIdx); + + BaseProc* baseProc = otherObj->getProc(); + if (baseProc && + (baseProc->getState() == State::Calc || baseProc->getState() == State::Delete)) { + LinkTag* linkTag = sead::DynamicCast(baseProc); + if (!linkTag) { + Actor* actor = sead::DynamicCast(baseProc); + if (!actor) { + resetBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + } else if (actor->getEmittedSignalType() == link->type) + resetBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + else + setBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + } else if (linkTag->mFlags.isOn(LinkTagFlag::_40)) { + if (linkTag->mFlags.isOn(LinkTagFlag::_20) == linkTag->mFlags.isOn(LinkTagFlag::_4)) + resetBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + setBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + } else if (link->type != map::MapLinkDefType::BasicSigOnOnly) { + if (linkTag->mFlags.isOn(LinkTagFlag::_8) == linkTag->mFlags.isOn(LinkTagFlag::_4)) + resetBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + setBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + } else if (linkTag->mFlags.isOff(LinkTagFlag::_400)) { + resetBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + } else { + setBitAfterCheck(&mTriggeredLinkFlags, linkIdx); + } + } else { + if (link->type <= map::MapLinkDefType::DeadUp) { + if (otherObj->getFlags0().isOn(map::Object::Flag0::_100000) || + otherObj->checkRevivalFlag(map::ActorData::Flag::RevivalEnable)) { + if (linkIdx >= 0x60) + mTriggeredLinkFlags.resetBit(linkIdx); + } + } + } + if (mFlags.isOn(LinkTagFlag::_2) && otherObj->getFlags().isOff(map::Object::Flag::IsLinkTag)) + _1df = linkIdx; + + return mTriggeredLinkFlags.isOnBit(linkIdx); +} + +} // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actLinkTag.h b/src/KingSystem/ActorSystem/actLinkTag.h new file mode 100644 index 000000000..540e88dea --- /dev/null +++ b/src/KingSystem/ActorSystem/actLinkTag.h @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include +#include "KingSystem/ActorSystem/actBaseProc.h" +#include "KingSystem/ActorSystem/actBaseProcJobHandler.h" +#include "KingSystem/Map/mapMubinIter.h" +#include "KingSystem/Map/mapObjectLink.h" +#include "KingSystem/Utils/Types.h" + +namespace ksys::map { +class Object; +} // namespace ksys::map + +namespace ksys::act { + +class LinkTag : public BaseProc { + SEAD_RTTI_OVERRIDE(LinkTag, BaseProc) + +public: + enum class Type { And, Or, NAnd, NOr, XOr, Count, Pulse, None }; + enum class JobFlag {}; + enum class LinkTagFlag : u16 { + _1 = 0x1, + _2 = 0x2, + _4 = 0x4, + _8 = 0x8, + _10 = 0x10, + _20 = 0x20, + _40 = 0x40, + _80 = 0x80, + _100 = 0x100, + _200 = 0x200, + _400 = 0x400, + _800 = 0x800, + _1000 = 0x1000, + _2000 = 0x2000, + _4000 = 0x4000, + _8000 = 0x8000, + + _30 = _10 | _20, + _1081 = _1000 | _80 | _1 + }; + + static LinkTag* construct(const BaseProc::CreateArg& arg, sead::Heap* heap); + + explicit LinkTag(const BaseProc::CreateArg& arg); + ~LinkTag(); + + void calc(); + void calcPulse(bool update); + void calcCount(bool update); + void calcOther(bool update); + void onEnterCalc(); + bool init(); + void finalizeInit(BaseProc::InitContext* context); + void updateIsFlagSetFlag(bool isFlagSet, bool a3, bool a4); + bool isTriggered(map::ObjectLink* link, u8 linkIdx); + PreDeletePrepareResult prepareForPreDelete_() override; + bool isDonePreparingForPreDelete(); + bool hasJobType(JobType jobType); + bool shouldSkipJobPush(); + bool isSpecialJobType(); + void queueExtraJobPush(JobType jobType, u32 jobFlagBit); + bool canWakeUp(); + void prePushJob2(); + + s8 getSelfLinkCount(); + + // this doesn't even belong in this namespace, but is used as a placeholder for init() and + // prePushJob2() + static bool isFlagSet(bool* isSet, int unk, map::Object* object); + // this also doesn't belong here, used in calcPulse(), calcOther() (7100d15b04); + static void triggerLink(ActorLinkConstDataAccess& acc); + // this also doesn't belong here, used in dtor + static u32 getSceneStatus(); + + BaseProcJobHandlerT mJob; + sead::LongBitFlag<96> mTriggeredLinkFlags; + sead::SizedEnum mLinkTagType = Type::And; + sead::Atomic _1dd = 0xFF; + sead::Atomic _1de = 0; + u8 _1df = 0xFF; + sead::TypedBitFlag mFlags; + s8 mTagCount = 0; + u8 _1E3 = 0; + s32 mCounter = 0; + int _1E8 = 0; + sead::Atomic mJobFlags; + u32 mHashId = 0; + map::MubinIter mMubinIter; + map::Object* mMapObj = nullptr; +}; +KSYS_CHECK_SIZE_NX150(LinkTag, 0x210); + +} // namespace ksys::act diff --git a/src/KingSystem/GameData/gdtManager.h b/src/KingSystem/GameData/gdtManager.h index cf3251623..e75290031 100644 --- a/src/KingSystem/GameData/gdtManager.h +++ b/src/KingSystem/GameData/gdtManager.h @@ -518,6 +518,11 @@ class Manager : public IManager, public KingEditorComponent { mResetFlags.set(ResetFlag::AnimalMaster); } + // TODO needs implementation: 0x7100D39C9C + void setS32ByIdxForLinkTag(s32, FlagHandle); + // TODO needs implementation: 0x7100247B3C + bool setBoolByHash(bool, FlagHandle); + private: enum class BitFlag { _1 = 0x1, diff --git a/src/KingSystem/Map/mapObject.h b/src/KingSystem/Map/mapObject.h index 10e9d3c54..3b7d198d5 100644 --- a/src/KingSystem/Map/mapObject.h +++ b/src/KingSystem/Map/mapObject.h @@ -49,6 +49,8 @@ class Object { _400000 = 0x400000, _2000000 = 0x2000000, _4000000 = 0x4000000, + _10000000 = 0x10000000, + _20000000 = 0x20000000, _40000000 = 0x40000000, _80000000 = 0x80000000, ResetOnUnlinkFailed = _100 | _2000, @@ -176,6 +178,7 @@ class Object { Object* findSrcLODLinkObject() const; const auto& getFlags0() const { return mFlags0; } + auto& getFlags0() { return mFlags0; } const auto& getFlags() const { return mFlags; } const auto& getActorFlags8() const { return mActorFlags8; } const auto& getHardModeFlags() const { return mHardModeFlags; } diff --git a/src/KingSystem/Map/mapObjectLink.h b/src/KingSystem/Map/mapObjectLink.h index 382aa804d..4328f9e6f 100644 --- a/src/KingSystem/Map/mapObjectLink.h +++ b/src/KingSystem/Map/mapObjectLink.h @@ -112,6 +112,23 @@ class ObjectLinkData { return checkDeleteLinkObjRevival() || checkCreateLinkObjRevival(); } + // TODO requires implementation: 0x7100D4FA70 + bool isGenGroupInitState3() const; + // TODO requires implementation: 0x7100D4FA90 + void sub_7100D4FA90(); + // TODO requires implementation: 0x7100D4F9C8 + void setNumExecLinkTagTo1(); + // TODO requires implementation: 0x7100D4F97C + void x_3(bool a1); + // TODO requires implementation: 0x7100D4F884 + void printDebugInfo(); + // TODO requires implementation: 0x7100D4F968 + void x_8(bool a1); + // TODO requires implementation: 0x7100D4F824 + void x_9(); + // TODO requires implementation: 0x7100D4F9B0 + bool x_7(bool a1); + Object* mCreateLinksSrcObj = nullptr; Object* mDeleteLinksSrcObj = nullptr; diff --git a/src/KingSystem/System/CMakeLists.txt b/src/KingSystem/System/CMakeLists.txt index a0d1eb082..ef1d97870 100644 --- a/src/KingSystem/System/CMakeLists.txt +++ b/src/KingSystem/System/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(uking PRIVATE HavokWorkerMgr.h KingEditor.cpp KingEditor.h + MCMgr.h MemoryProfiler.cpp MemoryProfiler.h MessageCapture.cpp diff --git a/src/KingSystem/System/MCMgr.h b/src/KingSystem/System/MCMgr.h new file mode 100644 index 000000000..6d096050a --- /dev/null +++ b/src/KingSystem/System/MCMgr.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include "KingSystem/Utils/Types.h" + +namespace ksys { + +struct ActorPhysics; + +class MCMgrJob : sead::Job { + +public: + void invoke() override; + +private: + void* mActorChemicalStuff; + ActorPhysics* mActorPhysics; + short mFlags; + const char* mName; + void* _38; +}; + +class MCMgr { + SEAD_SINGLETON_DISPOSER(MCMgr) + +public: + MCMgr(); + + void* _0; // TODO: Add gsys::ISystemTaskCallback, as it is a base class of this one + sead::FixedSizeJQ mQueue0; + sead::FixedSizeJQ mQueue1; + sead::FixedSizeJQ mQueue2; + sead::FixedSizeJQ mQueue3; + sead::FixedSizeJQ mPostBgPlayerAfter; + sead::FixedSizeJQ mQueue4; + sead::FixedSizeJQ mPlacementMgrJobQueue; + sead::FixedSizeJQ mQueue5; + sead::FixedSizeJQ mQueue6; + sead::FixedSizeJQ mQueue7; + sead::FixedSizeJQ mQueues8[8]; + sead::Job0 mCalcControllerAndUiJob; + sead::Job0 mMessageDispatcherJob; + u32 mFlags; + int _bdc; + MCMgrJob mInitProcessJobs[64]; + int mNumJobs; + int mCalcJobCounterMaybe; + void* _1be8; + sead::Delegate1R mInvoker2; + sead::Delegate1R mInvoker3; + sead::Delegate1R mInvoker4; +}; +KSYS_CHECK_SIZE_NX150(MCMgr, 0x1C50); + +} // namespace ksys