From 2fab47f3adc1ab04e94d6c37130a3dd7e837e07d Mon Sep 17 00:00:00 2001 From: Joseph Scudellari <25158797+Joessarian@users.noreply.github.com> Date: Sat, 29 Mar 2025 03:25:34 -0400 Subject: [PATCH 1/2] Adjustments to externally requested actor info bars. 1. Prevents externally requested actor info bars from being removed by the HUDHandler and delegates their removal to any plugins making use of the TrueHUDAPI. 2. Can now add a boss or actor info bar for player 1 or other actors even when out of combat. --- .gitmodules | 4 ++++ README.md | 3 ++- extern/CommonLibVR | 1 + src/HUDHandler.cpp | 9 +++++---- src/HUDHandler.h | 1 + src/ModAPI.cpp | 4 ++++ src/Scaleform/TrueHUDMenu.h | 9 +++++++++ src/Widgets/InfoBarBase.cpp | 12 +++++++----- src/main.cpp | 4 ++-- 9 files changed, 35 insertions(+), 12 deletions(-) create mode 160000 extern/CommonLibVR diff --git a/.gitmodules b/.gitmodules index 990f00f..5f5acbc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,7 @@ [submodule "extern/GreenSock-AS2"] path = extern/GreenSock-AS2 url = https://github.com/greensock/GreenSock-AS2 +[submodule "extern/CommonLibVR"] + path = extern/CommonLibVR + url = https://github.com/alandtse/CommonLibVR.git + branch = ng diff --git a/README.md b/README.md index 1ca1d91..b548656 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ * [Visual Studio Community 2022](https://visualstudio.microsoft.com/) * Desktop development with C++ * [CommonLibSSE-NG](https://github.com/alandtse/CommonLibVR/tree/ng) - * Add the environment variable `CommonLibSSEPath_NG` with the value as the path to the folder containing CommonLibSSE-NG + * Add this as as an environment variable `CommonLibSSEPath` ## User Requirements * [Address Library for SKSE](https://www.nexusmods.com/skyrimspecialedition/mods/32444) @@ -17,6 +17,7 @@ ``` git clone https://github.com/ersh1/TrueHUD/ cd TrueHUD +# pull commonlib /extern to override the path settings git submodule init git submodule update diff --git a/extern/CommonLibVR b/extern/CommonLibVR new file mode 160000 index 0000000..8593e41 --- /dev/null +++ b/extern/CommonLibVR @@ -0,0 +1 @@ +Subproject commit 8593e41c1f780b5b16b227f4f62e574d01e0ac3d diff --git a/src/HUDHandler.cpp b/src/HUDHandler.cpp index b6864c3..c9dc06d 100644 --- a/src/HUDHandler.cpp +++ b/src/HUDHandler.cpp @@ -350,7 +350,7 @@ void HUDHandler::AddActorInfoBar(RE::ObjectRefHandle a_actorHandle) return; } - if (a_actorHandle.native_handle() == 0x100000) { + if (a_actorHandle.native_handle() == 0x100000 && !extAddedActorInfoBars.contains(a_actorHandle)) { return; } @@ -363,7 +363,7 @@ void HUDHandler::AddActorInfoBar(RE::ObjectRefHandle a_actorHandle) void HUDHandler::RemoveActorInfoBar(RE::ObjectRefHandle a_actorHandle, WidgetRemovalMode a_removalMode /*= kImmediate*/) { - if (a_actorHandle) { + if (a_actorHandle && !extAddedActorInfoBars.contains(a_actorHandle)) { AddHUDTask([a_actorHandle, a_removalMode](TrueHUDMenu& a_menu) { a_menu.RemoveActorInfoBar(a_actorHandle, a_removalMode); }); @@ -381,7 +381,7 @@ void HUDHandler::AddBossInfoBar(RE::ObjectRefHandle a_actorHandle) return; } - if (a_actorHandle.native_handle() == 0x100000) { + if (a_actorHandle.native_handle() == 0x100000 && !extAddedActorInfoBars.contains(a_actorHandle)) { return; } @@ -394,7 +394,7 @@ void HUDHandler::AddBossInfoBar(RE::ObjectRefHandle a_actorHandle) void HUDHandler::RemoveBossInfoBar(RE::ObjectRefHandle a_actorHandle, WidgetRemovalMode a_removalMode /*= kImmediate*/) { - if (a_actorHandle) { + if (a_actorHandle && !extAddedActorInfoBars.contains(a_actorHandle)) { AddHUDTask([a_actorHandle, a_removalMode](TrueHUDMenu& a_menu) { a_menu.RemoveBossInfoBar(a_actorHandle, a_removalMode); }); @@ -692,6 +692,7 @@ void HUDHandler::RemoveAllWidgets() AddHUDTask([](TrueHUDMenu& a_menu) { a_menu.RemoveAllWidgets(); }); + extAddedActorInfoBars.clear(); } bool HUDHandler::CheckActorForBoss(RE::ObjectRefHandle a_refHandle) diff --git a/src/HUDHandler.h b/src/HUDHandler.h index 1ac9828..8021cca 100644 --- a/src/HUDHandler.h +++ b/src/HUDHandler.h @@ -117,6 +117,7 @@ class HUDHandler : SpecialResourceCallback GetMaxSpecial = nullptr; bool bSpecialMode; bool bDisplaySpecialForPlayer; + std::set> extAddedActorInfoBars; protected: friend class TrueHUDMenu; diff --git a/src/ModAPI.cpp b/src/ModAPI.cpp index e9d2e74..20d058c 100644 --- a/src/ModAPI.cpp +++ b/src/ModAPI.cpp @@ -83,6 +83,7 @@ namespace Messaging { auto hudHandler = HUDHandler::GetSingleton(); if (hudHandler) { + hudHandler->extAddedActorInfoBars.insert(a_actorHandle); hudHandler->AddActorInfoBar(a_actorHandle); } } @@ -91,6 +92,7 @@ namespace Messaging { auto hudHandler = HUDHandler::GetSingleton(); if (hudHandler) { + hudHandler->extAddedActorInfoBars.erase(a_actorHandle); hudHandler->RemoveActorInfoBar(a_actorHandle, static_cast(a_removalMode)); } } @@ -99,6 +101,7 @@ namespace Messaging { auto hudHandler = HUDHandler::GetSingleton(); if (hudHandler) { + hudHandler->extAddedActorInfoBars.insert(a_actorHandle); hudHandler->AddBossInfoBar(a_actorHandle); } } @@ -107,6 +110,7 @@ namespace Messaging { auto hudHandler = HUDHandler::GetSingleton(); if (hudHandler) { + hudHandler->extAddedActorInfoBars.erase(a_actorHandle); hudHandler->RemoveBossInfoBar(a_actorHandle, static_cast(a_removalMode)); } } diff --git a/src/Scaleform/TrueHUDMenu.h b/src/Scaleform/TrueHUDMenu.h index df19357..52fae0c 100644 --- a/src/Scaleform/TrueHUDMenu.h +++ b/src/Scaleform/TrueHUDMenu.h @@ -24,6 +24,15 @@ namespace std }; } +template +struct HandleComp +{ + bool operator()(const RE::BSPointerHandle& a_lhs, const RE::BSPointerHandle& a_rhs) const + { + return std::hash>()(a_lhs) < std::hash>()(a_rhs); + } +}; + namespace Scaleform { class DebugLine diff --git a/src/Widgets/InfoBarBase.cpp b/src/Widgets/InfoBarBase.cpp index f634664..aaf34e6 100644 --- a/src/Widgets/InfoBarBase.cpp +++ b/src/Widgets/InfoBarBase.cpp @@ -117,6 +117,8 @@ namespace Scaleform auto softTargetHandle = hudMenu->GetSoftTarget(); bool bIsTeammate = Utils::IsPlayerTeammateOrSummon(actor); + bool bIsPlayer = actor == playerCharacter; + bool bExtManaged = HUDHandler::GetSingleton()->extAddedActorInfoBars.contains(actor->GetHandle()); TargetType targetType; if (targetHandle && _refHandle == targetHandle) { @@ -125,7 +127,7 @@ namespace Scaleform targetType = kTarget; } else if (actor->IsHostileToActor(playerCharacter)) { targetType = kEnemy; - } else if (bIsTeammate) { + } else if (bIsTeammate || bIsPlayer) { targetType = kTeammate; } else { targetType = kOther; @@ -153,9 +155,9 @@ namespace Scaleform const auto shouldBarBeDisplayed = [&]() { if (_barType == BarType::kBossInfoBar) { - return !bIsTeammate && actor->IsInCombat() && actor->IsHostileToActor(playerCharacter); + return (bExtManaged) || (!bIsTeammate && actor->IsInCombat() && actor->IsHostileToActor(playerCharacter)); } else if (_barType == BarType::kActorInfoBar) { - if (targetType > kTarget && !actor->IsInCombat()) { + if (!bExtManaged && targetType > kTarget && !actor->IsInCombat()) { return false; } switch (targetType) { @@ -181,7 +183,7 @@ namespace Scaleform SetWidgetState(WidgetStateMode::kHide); } else { bool r8 = false; - bool bHasLOS = targetType == kTarget ? true : playerCharacter->HasLineOfSight(actor, r8); + bool bHasLOS = targetType == kTarget || bIsTeammate || bIsPlayer ? true : playerCharacter->HasLineOfSight(actor, r8); bool bVisible = bHasLOS && !(actor->AsActorValueOwner()->GetActorValue(RE::ActorValue::kInvisibility) > 0); if (bVisible) { SetWidgetState(WidgetStateMode::kShow); @@ -197,7 +199,7 @@ namespace Scaleform uint32_t levelColor = Settings::uDefaultColor; uint32_t outlineColor = Settings::uDefaultColorOutline; - if (bIsTeammate) { + if (bIsTeammate || bIsPlayer) { levelColor = Settings::uTeammateColor; outlineColor = Settings::uTeammateColorOutline; } else if (playerLevel - targetLevel > Settings::uInfoBarLevelThreshold) { diff --git a/src/main.cpp b/src/main.cpp index d858eac..1195f0c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,9 +90,9 @@ extern "C" DLLEXPORT constinit auto SKSEPlugin_Version = []() { v.PluginVersion(Plugin::VERSION); v.PluginName(Plugin::NAME); v.AuthorName("Ersh"); - v.UsesAddressLibrary(true); + v.UsesAddressLibrary(); v.CompatibleVersions({ SKSE::RUNTIME_SSE_LATEST }); - v.HasNoStructUse(true); + v.UsesNoStructs(); return v; }(); From da8a26a36e7e8587eae8c9172db82dd75400fa2c Mon Sep 17 00:00:00 2001 From: Joseph Scudellari <25158797+Joessarian@users.noreply.github.com> Date: Mon, 31 Mar 2025 12:26:14 -0400 Subject: [PATCH 2/2] Info Bar LOS Check Update Ignore LOS checks for the player (unnecessary) or externally managed actors. --- src/Widgets/InfoBarBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Widgets/InfoBarBase.cpp b/src/Widgets/InfoBarBase.cpp index aaf34e6..b87be72 100644 --- a/src/Widgets/InfoBarBase.cpp +++ b/src/Widgets/InfoBarBase.cpp @@ -183,7 +183,7 @@ namespace Scaleform SetWidgetState(WidgetStateMode::kHide); } else { bool r8 = false; - bool bHasLOS = targetType == kTarget || bIsTeammate || bIsPlayer ? true : playerCharacter->HasLineOfSight(actor, r8); + bool bHasLOS = targetType == kTarget || bExtManaged || bIsPlayer ? true : playerCharacter->HasLineOfSight(actor, r8); bool bVisible = bHasLOS && !(actor->AsActorValueOwner()->GetActorValue(RE::ActorValue::kInvisibility) > 0); if (bVisible) { SetWidgetState(WidgetStateMode::kShow);