From ead94dffe6021f11182ca8ac96f611016961299a Mon Sep 17 00:00:00 2001 From: Arnaud Jamin Date: Tue, 17 Oct 2023 12:35:56 -0400 Subject: [PATCH] Add runtime values in the behavior tree window Sort blackboard by name --- .../Characters/Creature1/BT_Creature1.uasset | Bin 19036 -> 15081 bytes .../Private/CogAIWindow_BehaviorTree.cpp | 85 +++++++++++++---- .../CogAI/Private/CogAIWindow_Blackboard.cpp | 87 ++++++++++++------ .../CogAI/Public/CogAIWindow_BehaviorTree.h | 2 +- TODO.txt | 7 -- 5 files changed, 123 insertions(+), 58 deletions(-) diff --git a/Content/Characters/Creature1/BT_Creature1.uasset b/Content/Characters/Creature1/BT_Creature1.uasset index b409787b8a7a7e680091336ec936119981c0b0c7..9a9370b9035e4b41712975b06b6acb6f3dcb280c 100644 GIT binary patch delta 2920 zcma)7U2Kz882&!&HdflM-P&($*LK|~-C%#MbF3}hU~G(S&?!uY3`C3p5=7z!1S15Z zkqa**Y%eGm!-Pn@G2w3^L=z$efK$34(IK5DoQntM(jhg=g@>|Dpt5{;C@wA6#i3A8%gb{S_AhDqoQd1 zbz2n0A?yKmfc8_VqKt9>oBNTqzyCIN?VI)^caPuPv-`kQX#CBBN0;~Zo;mf==}Xbg zzk-iE8)&uKH$T7%&c)bFYg62ytd)JA3QVdTnNSZJ=y-nLh+6RcEVYb6g)SN{d~w8M zjH>pfB1^CM-seno#$tCY6OL!a_W=W|$>uM~LM9pM%ZdEL$O}5sA+oF$-w8&#fY`DS z+F>qrWOMadHd?uab=sQ^G-SYX7jKH_<&DV#j*zx0E&4Ri(cBAD z_05`YGzR>FTK;e-~V3l5X<6;bPK zRF7h}*3T}Pv{S&2m=2q5wSIWk3pZ%;VXTiOoiteCr*$spely!3@Kc(?mg4-N#>5?` z0H3@x{QIiR;SQxZM8txN7|BH(_`vyhSf9()$#~eP$8r1h1URfB?f~rEkqmQm{F0*} zlESuehbV~`^BjpKUcz&Tl(v=U5CuL&AwP1!Z{hlSVForuB#K3&#ThN5hn}740eaorv$Q(tR_er8-{Jpr z6+9v!O4n(SN6=&^4bdl?@YEI*;D1r)9=8LD?8y<(y*6@BS3 zs)d$>J+!)VzKA(dIjmOT@X&A(UOTyI&)m0K+Kyg+oL}G`yam6JUJjJfjj)~WFYwbB zfq5dhc%DJ!X=xCOx`GWnz7g!!)oFAq_>391E{F`=l51$IszyYO9#PXq+oN9kxF)G) zWm3F8Uddqj;|6LEyJ%;F&`n=91RS~K&Zemb#6GG;h5EX7YO3_ohOmq~84l353+&{q zKSUR6;~C8HDlc_3O6L2G0Tl}`Nsd%ozn2b%G9uIxvNkQ_95|hQO#$Ab6N2+<1oej_ zjXYkDBzW{idsVBx`|n0&joZ^^-rhw&ENTbkQX<0acdvy6_@v^}@-4->u%Fw5hX- zx;tXiTm!f?S!bs^J}ZrOH1j6AmIbB>s+sCL!@SN-ovZ%SYstm6;a4VIP74)!J=3{t PGv%fh!h8LB_pyHg8DS@~ delta 4244 zcmb7Gdr(wW7{7N}9*gXPF1zdtc`eI=uv}tMSd@n^1OZX76jEH3OasA`9;;>II5lJW z`kc~6C!1^r7`jd(ZiPzwbN0 z^PTVB!{zQvyTu*5BULs*aKf7C@o-htjuWtXv412A0{#hwV_=&nYd)Fhj}Zjq3fFXk zkR;DL%zj#jRS>$dZ^1sUJpIwC!_Q9dn||Wed2rMxUGYWVKD(j*Snn%+10`)YC@jVC z!aT7tyB9s2H8@qYA#5b85^cFM#w7M%6}PJ$s6%L6xq3x=TYcy9HsQVfU!;wgn!IZt z683lcN??6dqc#$$%+m720ZsqMQB5i_6K=;?^ea2M+S?ku4}06&+uDWS*F9{oqTLLW zHH$J(kubGsT4zUB=h~I)+FBa}$tM<+-Rj?~DG@a@kVtJFSmRO*v-}gGQGWi4ySNX$ zHvK5%7ep3>M6MySh#^&Sl>6o96+~u-MVi7Q^TQ&|VUd=Q$j_*tHY`#X7O4-5%n6G$ zghl3tL@uMY#Q{jGoHu$@5~AT5ZH2?y6vOaL!J8JuyA_5vBkW2u!y;9LfJJ9lscevD zwm`Ek6)x)HEc80?`j5f!pR%BPlNrqyFTtvWxY)J`zrA)mHyi8FqQXvIdKo^J#^8(b zlCd7m6rA818esdt&R|c1WSoOjHFkmFR|bDyx+^^@i2nLL zccn)M(RaD;N+%&oF}{g+rE6q*HzgL^(qcyUjg#O*eO&B5`82-paI>)qS-cu{$ne@S z2H(_Ajy1}GBBnBvM=wE*AuhI$MHd9~bY^~0FBuo2i67%>89wKSEe6Th90J}vgL!k9 z%i!KqW(L6g&^i29Ak0sh!^f%uy!oke_@P-0#+m`2F2UHMkhe@$pIJSM!X?g>DbEa3 z9M=_PP3RJtLN3kn_~U9wHI{8mz$uy0V<--vq>XkLkDU&it|i(|EOx@R*r{&t1{L@T zQ`u1*^5c6WKZ-%V#2+h?DWA)bY}0%M+L8 zbm380@}s!{J4xVtBaTTv$LaQ`t;q9@f(a+IAP<;`W71CnXn!Ptf|8x~LV~Hp2&2Vm z0SZbRAUoxQf>T@)OE&VOcy}<@O3v+})}f()6-GJ`PT*s54mG9)xm`Kt2g??QowgLX zndFFi9JSuCg2Pl9O=^cWwZdvsI#jsSu-jB*EJYh@hAC&LQsDv@~3{+rf=q8I}Mc0GKPY7^t(LULnR=UZ9HaAthA?5a)K zCoZQ$q(;@%@y3$%8Jnh5?m2rWD%!I1OR`f{&DPW|tg=5hwKu1tXY-pWC1j`S3T3AP zd&ya_^{3t=bDkbNly{-|&_7U)TQH<$vURijm#0ODID9Z&!aeOx&&S_$>DBnFK- z;W@BVV>^Uh8P4GiRq$-&d;An3MSij>4gWtO3}lz9`c%;BvO=9B&YywW*YxWyUHaww znQve3JTUv6w=U=MVECj;rWR^Lp={8bW`J!`^O(2h4jusy^ENwRXu5kBQ_RY;!U1Nz7Zryj#;_ zaCW-J9+-ESugDPw58`{!K8Q?bbUSY zIi!yO|HPHTSNV&vXm+|Q@C?QlB;xNj=>hnxurgpiNm99h_rkW`+nxa zfqZLLublm15p>NAi@-58p9oJD&KFHVD?Na3NnnB`e|$6DW6C3@YlvDYc#E^3W};_A z2fRD61y9W~$*!>7Q|!Xzd5hU)tx{VBJZZL#tP_B-Y(=u& Pz(A26x@>A#;pzDg{P;@{ diff --git a/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_BehaviorTree.cpp b/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_BehaviorTree.cpp index fe1bb31..c1a7895 100644 --- a/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_BehaviorTree.cpp +++ b/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_BehaviorTree.cpp @@ -92,30 +92,20 @@ void UCogAIWindow_BehaviorTree::RenderContent() if (RootNodeInstanced != nullptr) { - RenderNode(BehaviorTreeComponent, RootNodeInstanced, false); + RenderNode(*BehaviorTreeComponent, const_cast(RootNodeInstanced), false); } } //-------------------------------------------------------------------------------------------------------------------------- -void UCogAIWindow_BehaviorTree::RenderNode(UBehaviorTreeComponent* BehaviorTreeComponent, const UBTNode* Node, bool OpenAllChildren) +void UCogAIWindow_BehaviorTree::RenderNode(UBehaviorTreeComponent& BehaviorTreeComponent, UBTNode* Node, bool OpenAllChildren) { - FString NodeNameStr; - if (const UBTTask_BlueprintBase* Wait = Cast(Node)) - { - NodeNameStr = Node->GetNodeName(); - } - else - { - NodeNameStr = Node->GetStaticDescription(); - } - - const char* NodeName = TCHAR_TO_ANSI(*NodeNameStr); + const char* NodeName = TCHAR_TO_ANSI(*Node->GetNodeName()); const bool ShowNode = Filter.PassFilter(NodeName); const UBTCompositeNode* CompositeNode = Cast(Node); bool IsActive = false; - for (const UBTNode* ActiveParentNode = BehaviorTreeComponent->GetActiveNode(); ActiveParentNode != nullptr; ActiveParentNode = ActiveParentNode->GetParentNode()) + for (const UBTNode* ActiveParentNode = BehaviorTreeComponent.GetActiveNode(); ActiveParentNode != nullptr; ActiveParentNode = ActiveParentNode->GetParentNode()) { if (Node == ActiveParentNode) { @@ -171,11 +161,66 @@ void UCogAIWindow_BehaviorTree::RenderNode(UBehaviorTreeComponent* BehaviorTreeC //------------------------ if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::BeginDisabled(); - ImGui::Text(NodeName); - ImGui::EndDisabled(); - ImGui::EndTooltip(); + FCogWindowWidgets::BeginTableTooltip(); + + if (ImGui::BeginTable("Effect", 2, ImGuiTableFlags_Borders)) + { + ImGui::TableSetupColumn("Property"); + ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); + + const ImVec4 TextColor(1.0f, 1.0f, 1.0f, 0.5f); + + //------------------------ + // Name + //------------------------ + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Name"); + ImGui::TableNextColumn(); + ImGui::Text("%s", NodeName); + + //------------------------ + // Static Description + //------------------------ + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Description"); + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*Node->GetStaticDescription())); + + //------------------------ + // Runtime Values + //------------------------ + TArray RunTimeValues; + uint8* NodeMemory = BehaviorTreeComponent.GetNodeMemory(Node, BehaviorTreeComponent.GetActiveInstanceIdx()); + Node->DescribeRuntimeValues(BehaviorTreeComponent, NodeMemory, EBTDescriptionVerbosity::Detailed, RunTimeValues); + + for (const FString& RuntimeValue : RunTimeValues) + { + ImGui::TableNextRow(); + + FString Left, Right; + if (RuntimeValue.Split(TEXT(": "), &Left, &Right)) + { + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, TCHAR_TO_ANSI(*Left)); + + ImGui::TableNextColumn(); + ImGui::Text("%s", TCHAR_TO_ANSI(*Right)); + } + else + { + ImGui::TableNextColumn(); + ImGui::TextColored(TextColor, "Value"); + ImGui::TableNextColumn(); + ImGui::Text(TCHAR_TO_ANSI(*RuntimeValue)); + } + } + + ImGui::EndTable(); + } + + FCogWindowWidgets::EndTableTooltip(); } //------------------------ @@ -213,7 +258,7 @@ void UCogAIWindow_BehaviorTree::RenderNode(UBehaviorTreeComponent* BehaviorTreeC { for (int32 i = 0; i < CompositeNode->GetChildrenNum(); ++i) { - const UBTNode* ChildNode = CompositeNode->GetChildNode(i); + UBTNode* ChildNode = CompositeNode->GetChildNode(i); RenderNode(BehaviorTreeComponent, ChildNode, OpenAllChildren); } } diff --git a/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_Blackboard.cpp b/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_Blackboard.cpp index 4d960fe..700787a 100644 --- a/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_Blackboard.cpp +++ b/Plugins/CogAI/Source/CogAI/Private/CogAIWindow_Blackboard.cpp @@ -82,6 +82,29 @@ void UCogAIWindow_Blackboard::RenderContent() return; } + TArray Keys; + uint8 Offset = 0; + for (UBlackboardData* It = BlackboardAsset; It; It = It->Parent) + { + for (int32 KeyID = 0; KeyID < It->Keys.Num(); KeyID++) + { + if (const FBlackboardEntry* Key = BlackboardAsset->GetKey(KeyID)) + { + Keys.Add(Key); + } + } + Offset += It->Keys.Num(); + } + + if (bSortByName) + { + Keys.Sort([](const FBlackboardEntry& Key1, const FBlackboardEntry& Key2) + { + return Key1.EntryName.Compare(Key1.EntryName) < 0; + }); + } + + if (ImGui::BeginTable("Blackboard", 3, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBodyUntilResize @@ -101,39 +124,43 @@ void UCogAIWindow_Blackboard::RenderContent() const FString CommonTypePrefix = UBlackboardKeyType::StaticClass()->GetName().AppendChar(TEXT('_')); - uint8 Offset = 0; - for (UBlackboardData* It = BlackboardAsset; It; It = It->Parent) + for (int32 KeyID = 0; KeyID < Keys.Num(); ++KeyID) { - for (int32 KeyID = 0; KeyID < It->Keys.Num(); KeyID++) + const FBlackboardEntry* Key = Keys[KeyID]; + if (Key == nullptr) { - const FBlackboardEntry* Key = BlackboardAsset->GetKey(KeyID); - if (Key == nullptr) - { - continue; - } - - const char* KeyName = TCHAR_TO_ANSI(*Key->EntryName.ToString()); - if (Filter.PassFilter(KeyName) == false) - { - continue; - } - - ImGui::TableNextRow(); - - ImGui::TableNextColumn(); - const FString FullKeyType = Key->KeyType ? GetNameSafe(Key->KeyType->GetClass()) : FString(); - const FString DescKeyType = FullKeyType.StartsWith(CommonTypePrefix) ? FullKeyType.RightChop(CommonTypePrefix.Len()) : FullKeyType; - ImGui::Text("%s", TCHAR_TO_ANSI(*DescKeyType)); - - ImGui::TableNextColumn(); - ImGui::Text("%s", KeyName); - - ImGui::TableNextColumn(); - const uint8* ValueData = Blackboard->GetKeyRawData(KeyID); - FString ValueDesc = Key->KeyType && ValueData ? *(Key->KeyType->WrappedDescribeValue(*Blackboard, ValueData)) : TEXT("Empty"); - ImGui::Text("%s", TCHAR_TO_ANSI(*ValueDesc)); + continue; } - Offset += It->Keys.Num(); + + const char* KeyName = TCHAR_TO_ANSI(*Key->EntryName.ToString()); + if (Filter.PassFilter(KeyName) == false) + { + continue; + } + + ImGui::TableNextRow(); + + //------------------------ + // Type + //------------------------ + ImGui::TableNextColumn(); + const FString FullKeyType = Key->KeyType ? GetNameSafe(Key->KeyType->GetClass()) : FString(); + const FString DescKeyType = FullKeyType.StartsWith(CommonTypePrefix) ? FullKeyType.RightChop(CommonTypePrefix.Len()) : FullKeyType; + ImGui::Text("%s", TCHAR_TO_ANSI(*DescKeyType)); + + //------------------------ + // Name + //------------------------ + ImGui::TableNextColumn(); + ImGui::Text("%s", KeyName); + + //------------------------ + // Value + //------------------------ + ImGui::TableNextColumn(); + const uint8* ValueData = Blackboard->GetKeyRawData(KeyID); + FString ValueDesc = Key->KeyType && ValueData ? *(Key->KeyType->WrappedDescribeValue(*Blackboard, ValueData)) : TEXT("Empty"); + ImGui::Text("%s", TCHAR_TO_ANSI(*ValueDesc)); } ImGui::EndTable(); diff --git a/Plugins/CogAI/Source/CogAI/Public/CogAIWindow_BehaviorTree.h b/Plugins/CogAI/Source/CogAI/Public/CogAIWindow_BehaviorTree.h index a340255..b541906 100644 --- a/Plugins/CogAI/Source/CogAI/Public/CogAIWindow_BehaviorTree.h +++ b/Plugins/CogAI/Source/CogAI/Public/CogAIWindow_BehaviorTree.h @@ -22,7 +22,7 @@ protected: virtual void RenderContent() override; - virtual void RenderNode(UBehaviorTreeComponent* BehaviorTreeComponent, const UBTNode* Node, bool OpenAllChildren); + virtual void RenderNode(UBehaviorTreeComponent& BehaviorTreeComponent, UBTNode* Node, bool OpenAllChildren); private: diff --git a/TODO.txt b/TODO.txt index 50b7e46..3332382 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,20 +1,15 @@ - CogImGui: Add a way to create and override CogImguiwidget - CogImGui: Try to find a global solution to prevent crash when breaking in a blueprint from an imgui action (reset the stack) -- CogDebug: Add log category description - - CogWindow: Add reset window position menu item or reset layout (window can get far away) - CogWindow: Try to remove CogWindow dependency to cogimgui. Should only depends on imgui (currently use setdpiscale of cogimgui) - CogWindow: Add reset window position menu item or reset layout (window can get far away) - - CogEngine: Save selection window settings (current actor and category) - CogEngine: More stats in the stats window - CogEngine: Overlay mode of stats. - CogEngine: Stat main menu widget could have a tooltip on each stat with a control to change set the emulation (FPS, Ping, Packetloss) - CogEngine: Skeleton window selectable have wrong height -- CogEngine: Property grid -- CogEngine: user settings - CogInput: Add multiple IMC on the input data asset. Maybe propose a current imc - CogInput: Add mouse over highlight on the buttons of the gamepad window @@ -24,5 +19,3 @@ - CogSample: Add a custom window in sample (changing the character faction) - CogSample: Create more abilities - CogSample: Add area of effects in the level - -- CogAI: Create a CogAI project with windows for BT and other AI tools \ No newline at end of file