#include thread_local const char* g_animErrorCode = ""; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma optimize("", off) using TApplyAnimationVariables = void*(void*, TESActionData*); POINTER_SKYRIMSE(TApplyAnimationVariables, ApplyAnimationVariables, 39004); POINTER_SKYRIMSE(void*, qword_142F271B8, 403566); extern thread_local bool g_forceAnimation; struct Class142F3A1E8 { uint8_t SendGraphAction(TESActionData* apAction); }; void hkbBehaviorGraph::ReSendEvent(hkEventContext& aContext, hkEventType& aType) { TP_THIS_FUNCTION(THandleEvents, void*, hkbBehaviorGraph, hkEventContext&, hkEventType&); POINTER_SKYRIMSE(THandleEvents, HandleEvents, 58377); if (!aContext.behaviorGraph) { // The game makes a copy, might as well do the same hkEventType type(aType); ReHandleEvent(aContext, type); } } void hkbBehaviorGraph::ReHandleEvent(hkEventContext& aContext, hkEventType& aType) { auto pContext = aContext.characterContext; if (!pContext) pContext = aContext.character->characterContext; const auto cpSymbolId = pContext->symbolIdMap; const auto cbyte20 = pContext->byte20; const auto cbyte30 = aContext.byte30; const auto counter = struct98->count; for (auto i = 0; i < counter; ++i) { const auto pSomeData = &struct98->data[i]; if (!pSomeData->byte84) { const auto pGraph = pSomeData->behaviorGraph; auto pGenerator = pSomeData->generator; pContext->symbolIdMap = pGraph->symbolIdMap; pContext->byte20 = 1; auto eventType = aType.type; if (pGraph->symbolIdMap && eventType >= 0) { TP_THIS_FUNCTION(Tsub_1409CA9D0, int32_t, void, int32_t, int64_t); POINTER_SKYRIMSE(Tsub_1409CA9D0, sub_1409CA9D0, 57185); eventType = TiltedPhoques::ThisCall(sub_1409CA9D0, &pGraph->symbolIdMap->pointer20, eventType + 1, -1ll); } if (eventType != -1) { aContext.behaviorGraph = pGraph; hkEventType type(eventType); type.behaviorGraph = aType.behaviorGraph; if (pSomeData->byte85 == 0) { TP_THIS_FUNCTION(Tsub_140A13150, int32_t, hkEventContext, hkbGenerator*, hkEventType&, SomeData*); POINTER_SKYRIMSE(Tsub_140A13150, sub_140A13150, 59310); TiltedPhoques::ThisCall(sub_140A13150, &aContext, pGenerator, type, pSomeData); } else { pGenerator->SendEvent(aContext, type); } } } } // dis magic fixes animations if (g_forceAnimation) aContext.byte30 = 1; pContext->symbolIdMap = cpSymbolId; pContext->byte20 = cbyte20; // auto result = 1; if (!(aContext.byte30 & 1)) { TP_THIS_FUNCTION(Tsub_1409F3EF0, void, hkbBehaviorGraph, hkEventContext&, hkEventType&); POINTER_SKYRIMSE(Tsub_1409F3EF0, sub_1409F3EF0, 58378); hkEventType type(aType); TiltedPhoques::ThisCall(sub_1409F3EF0, this, aContext, type); } if (byte12E || g_forceAnimation) { TP_THIS_FUNCTION(Tsub_140A4DFA0, void, hkbBehaviorGraph, hkEventContext&); POINTER_SKYRIMSE(Tsub_140A4DFA0, sub_140A4DFA0, 60079); TiltedPhoques::ThisCall(sub_140A4DFA0, this, aContext); } aContext.behaviorGraph = nullptr; aContext.byte30 = aContext.byte30 || cbyte30; } hkEventContext::hkEventContext(hkbCharacter* apCharacter, ahkpWorld* apWorld) { character = apCharacter; behaviorGraph = nullptr; unk10 = nullptr; characterContext = nullptr; unk20 = nullptr; unk28 = nullptr; byte30 = 0; hkpWorld = apWorld; unk40 = nullptr; unk48 = nullptr; } hkEventType::hkEventType(int32_t aType) { type = aType; behaviorGraph = nullptr; pointer10 = nullptr; } bool BShkbAnimationGraph::ReSendEvent(BSFixedString* apEventName) { if (behaviorGraph && behaviorGraph->byte12C) { if (hkxDB->ptr160) { using Thash_stub = uint32_t(uint32_t&, const char*); POINTER_SKYRIMSE(Thash_stub, hash_stub, 68221); uint32_t hash = 0; hash_stub(hash, apEventName->data); const auto pBuckets = hkxDB->hashTable.buckets; if (pBuckets) { const auto mask = hkxDB->hashTable.bucketCount - 1; auto pEntry = &pBuckets[hash & mask]; if (pEntry->next) { while (pEntry->key != apEventName->data) { pEntry = pEntry->next; if (pEntry == hkxDB->hashTable.end) return false; } ahkpWorld* pWorld = nullptr; if (hkWorldM) pWorld = hkWorldM->GetWorld(); auto* pCharacter = &character; hkEventContext context(pCharacter, pWorld); hkEventType type(pEntry->value); // 1409f0360 behaviorGraph->ReSendEvent(context, type); return context.byte30 != 0; } } } } return false; /* TP_THIS_FUNCTION(TBSSendEvent, bool, BShkbAnimationGraph, BSFixedString*); POINTER_SKYRIMSE(TBSSendEvent, InternalSendEvent, 63591); return TiltedPhoques::ThisCall(InternalSendEvent, this, apEventName);*/ } uint32_t BSAnimationGraphManager::ReSendEvent(BSFixedString* apEventName) { BSScopedLock _(lock); uint32_t counter = 0; for (decltype(animationGraphs.size) i = 0; i < animationGraphs.size; ++i) { auto pCurrentAnimationGraph = animationGraphs.Get(i); if (pCurrentAnimationGraph->ReSendEvent(apEventName)) ++counter; } // Not sure what this is, looks like it call this function on another graph manager, maybe to sync ridder/ridden ? TP_THIS_FUNCTION(Tsub_140AE2DB0, uint8_t, BSAnimationGraphManager, BSFixedString*); POINTER_SKYRIMSE(Tsub_140AE2DB0, sub_140AE2DB0, 63372); TiltedPhoques::ThisCall(sub_140AE2DB0, this, apEventName); return counter; } bool IAnimationGraphManagerHolder::ReSendAnimationEvent(BSFixedString* apAnimEvent) { BSAnimationGraphManager* pAnimationGraph = nullptr; auto result = GetBSAnimationGraph(&pAnimationGraph); TP_THIS_FUNCTION(TBSSendEvent, uint32_t, BSAnimationGraphManager, BSFixedString*); POINTER_SKYRIMSE(TBSSendEvent, BSSendEvent, 63362); if (pAnimationGraph) { result = pAnimationGraph->ReSendEvent(apAnimEvent) != 0; pAnimationGraph->Release(); } return result; } uint8_t Class142F3A1E8::SendGraphAction(TESActionData* apAction) { TP_THIS_FUNCTION(TGetSomeIdleProperty, uint8_t, TESIdleForm); POINTER_SKYRIMSE(TGetSomeIdleProperty, GetSomeIdleProperty, 24568); if (!apAction->actor) return 0; if (apAction->idleForm) { auto& objectManager = DefaultObjectManager::Get(); BGSAction* pAction = nullptr; if (objectManager.isSomeActionReady) { pAction = objectManager.someAction; } if (pAction == apAction->action) { const auto result = static_cast(TiltedPhoques::ThisCall(GetSomeIdleProperty, apAction->idleForm)); auto& stringManager = DefaultStringManager::Get(); apAction->actor->animationGraphHolder.SetVariableFloat(&stringManager.fIdleTimer, result); } } return apAction->actor->animationGraphHolder.ReSendAnimationEvent(&apAction->eventName); } bool ActorMediator::RePerformAction(TESActionData* apAction) noexcept { TP_THIS_FUNCTION(TAnimationStep, uint8_t, ActorMediator, TESActionData*); POINTER_SKYRIMSE(TAnimationStep, PerformIdleAction, 38952); POINTER_SKYRIMSE(TAnimationStep, PerformComplexAction, 38953); uint8_t result = 0; auto pActor = static_cast(apAction->actor); if (!pActor || pActor->animationGraphHolder.IsReady()) { // result = TiltedPhoques::ThisCall(PerformIdleAction, this, apAction); // if (apAction->someFlag & BGSActionData::kTransitionNoAnimation) // apAction->someFlag = BGSActionData::kSkip; // else { result = TiltedPhoques::ThisCall(PerformComplexAction, this, apAction); // result = RePerformComplexAction(apAction); } ApplyAnimationVariables(*qword_142F271B8.Get(), apAction); /*if (result == 0) g_animErrorCode = "PerformIdleAction failed"; if(result) { if (apAction->someFlag & BGSActionData::kTransitionNoAnimation) apAction->someFlag = BGSActionData::kSkip; else { result = TiltedPhoques::ThisCall(PerformComplexAction, this, apAction); //result = RePerformComplexAction(apAction); } } else if ((apAction->someFlag & BGSActionData::kTransitionNoAnimation) == 0) { ApplyAnimationVariables(*qword_142F271B8.Get(), apAction); }*/ } return result; } bool ActorMediator::RePerformIdleAction(TESActionData* apData) noexcept { using Tsub_14063CAA0 = bool(void*, TESActionData*); using Tsub_14063CFB0 = bool(void*, TESActionData*); using Tsub_1405CCB20 = bool(void*, TESActionData*); using Tsub_1404ECF50 = bool(void*, TESActionData*); POINTER_SKYRIMSE(Tsub_14063CAA0, sub_14063CAA0, 39002); POINTER_SKYRIMSE(Tsub_14063CFB0, sub_14063CFB0, 38952); POINTER_SKYRIMSE(Tsub_1405CCB20, sub_1405CCB20, 37147); POINTER_SKYRIMSE(Tsub_1404ECF50, sub_1404ECF50, 32802); POINTER_SKYRIMSE(void*, qword_142F271C8, 403568); POINTER_SKYRIMSE(void*, qword_142EFF990, 401100); bool result = true; if (((apData->someFlag >> 1) & 1) == 0) { if (!sub_14063CAA0(*qword_142F271B8.Get(), apData)) { result = false; } if (sub_1405CCB20(*qword_142F271C8.Get(), apData)) { if (result && !sub_14063CFB0(*qword_142F271B8.Get(), apData)) result = false; } else { result = false; } // Has something to do with the target refr sub_1404ECF50(*qword_142EFF990.Get(), apData); } return result; } bool ActorMediator::RePerformComplexAction(TESActionData* apData) noexcept { TP_THIS_FUNCTION(Tsub_1404ED090, uint8_t, void, TESActionData*); using Tsub_1401A2220 = void(BSFixedString*); POINTER_SKYRIMSE(Tsub_1404ED090, sub_1404ED090, 32803); POINTER_SKYRIMSE(Tsub_1401A2220, sub_1401A2220, 15002); POINTER_SKYRIMSE(void, qword_142EFF990, 401100); POINTER_SKYRIMSE(Class142F3A1E8, qword_142F3A1E8, 403988); auto v4 = false; if (apData->ComputeResult()) v4 = apData->result == 2; auto result = TiltedPhoques::ThisCall(sub_1404ED090, qword_142EFF990, apData); if (result) { qword_142F3A1E8->SendGraphAction(apData); } ApplyAnimationVariables(*qword_142F271B8.Get(), apData); if (!v4) return result; apData->someFlag &= 0xFFFFFFFC; sub_1401A2220(&apData->eventName); result = apData->Perform() & 0xFF; return result; } bool TESActionData::ComputeResult() { using Tsub_1401A1D50 = char(void*, TESActionData*); POINTER_SKYRIMSE(Tsub_1401A1D50, sub_1401A1D50, 15006); result = 0; if (targetIdleForm) { if (!_strnicmp(eventName, "NA_", 3)) { result = 2; return true; } auto v3 = sub_3(); if (v3) { result = 1; sub_1401A1D50(v3, this); } } return result > 0; } #pragma optimize("", on)