From f5d2b63c194432975f3711c762ffc4f1c7bd59db Mon Sep 17 00:00:00 2001 From: absol89 Date: Sat, 24 Aug 2024 17:40:21 +0200 Subject: [PATCH 01/86] Updated Vilkas script to be more compatible with magic effects in combat mods When a magic or explosion hit is registered it adds to the trainer counter instead of resetting the quest stage, doesn't matter which player or character hits Vilkas now. --- GameFiles/Skyrim/scripts/C00TrainerScript.pex | Bin 1852 -> 1441 bytes .../scripts/source/C00TrainerScript.psc | 32 +++++++++--------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/GameFiles/Skyrim/scripts/C00TrainerScript.pex b/GameFiles/Skyrim/scripts/C00TrainerScript.pex index a89d363b46548033a289e5e49403b03fe174149b..3bfc6e5d9f4a0ce24ec1ea73be584ec7fa774a5c 100644 GIT binary patch literal 1441 zcmZuw*>V#{6g_Q?HZL+UW;2@r6JjiZSwbp)vs`Rd2?mQwp2wprX(G8>%(TkILw+OQ zlh^!09`XlN-t&~xJu{XJbZchL-Os(<`tR32|0yj%fvf-5znfTZe`TTUm011EhNn2U zzq9i`31cluH%j7(Wun?kv0WQlLH(t%CWC7S`sZ*EN6-6xiR|8FGX99w1N~fENjhVZ zo|#%S3ba3zXq2LSpkKun^+QR;5~Wy*jPAuYHaZ-mGK_mY(P$h>UlP%g?2Y3vMO9Ca zy?5!gwg}!BEm#UidxJqDX=)M{KKhL;PQy?OM_n^bB0=!NB*$0|M{g73eB!ZSaSpG9 zM{muEBzx9|(Fj4um@%mAYGH*;xf~vK!gM&3NTxG3(MWoz?(SMSo;)qU_XT){@`tIU zwvc~7gL6DM(Xk%9^M)XmaUZp=pYA|V>Dq)w+#b3>4D|2ZTC1;~OCCJf|V9Nz5_xe2_ZHevfQ07v2#5re^ERpQvxk-}UChgQdnbZCc DGuipb literal 1852 zcmZWo+jiPU6y0OMfQ@ltlhjR{gfwZL_>$sl47KBcQII zgUCh3xr_oIi?2^x-@R*|Z@%8Het%YNqK;c`rJ`g1$oex-?o8^IcCyFD3E^P+Na`72o{>wu~(M+5149Z$B)k)L5(?tpsc*U?%~)NOzqpa~GsO_nr4lHt+Q7-EJtOh!L2m6%0dHBK;-^uTXIM z=V4&z@qCH7DZJoZo(I=5tZVJKeNb&F$xyLca4s88)SGC$0S!NJ`?8&sQbmST`#y5< zW!S19FMl8SLBuhQjay^1Jw|(Dv@=G#$-m}rWO?faX3W3HfK&p~;8r3z7%}@9vn*IR z3zTqsBuiMr9V>TnQ&wQa9Al~#Jfu9Ld_j3aSslw$JjFB0I%R{hX~i65YJq(gnHQKd zm`~~$^D*KoP_RWM%#(gBWO$fXk5pO3zb(xMMQ;K2ip$Rn~gtQ55$UkFh{s$`hE$jdQ diff --git a/GameFiles/Skyrim/scripts/source/C00TrainerScript.psc b/GameFiles/Skyrim/scripts/source/C00TrainerScript.psc index a52afdab1..5cc9b8e66 100644 --- a/GameFiles/Skyrim/scripts/source/C00TrainerScript.psc +++ b/GameFiles/Skyrim/scripts/source/C00TrainerScript.psc @@ -4,9 +4,9 @@ int numHits = 0 Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect) ; Debug.Trace("C00: Vilkas hit by magic.") - if (Game.GetPlayer() == akCaster) - GetOwningQuest().SetStage(100) - endif +; if (Game.GetPlayer() == akCaster) +; GetOwningQuest().SetStage(100) +; endif EndEvent Event OnEnterBleedout() @@ -24,30 +24,30 @@ Function BleedoutChecks() GetOwningQuest().SetStage(125) endif EndFunction - +; Change for SkyrimTogetherReborn 1.6.7+animation is to allow more mods by not magic checking the hit which can have combat or perk overhaul hidden effects Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) ; Debug.Trace("C00: Vilkas was hit.") ; Debug.Trace("C00: Vilkas hit datums -- " + akAggressor + " " + akSource + " " + akProjectile + " " + abPowerAttack + " " + abSneakAttack + " " + abBashAttack + " " + abHitBlocked) - if (akSource as Spell) +; if (akSource as Spell) ; Debug.Trace("C00: Vilkas hit by spell; bailing out and handling it in the magic effect handler.") - return - elseif (akSource as Explosion) +; return +; elseif (akSource as Explosion) ; Debug.Trace("C00: Vilkas hit by explosion; bailing out and handling it in the other handlers.") - return - endif -; if (Game.GetPlayer() == akAggressor) ; The original script didn't account for remote STR bystanders not hitting - if ((akSource as Spell) != None) - GetOwningQuest().SetStage(100) - return - endif +; return +; endif +; if (Game.GetPlayer() == akAggressor) +; if ((akSource as Spell) != None) +; GetOwningQuest().SetStage(100) +; return +; endif numHits += 1 if (numHits >= 3) GetOwningQuest().SetStage(150) endif -; else; Removing this part lets STR remote or pacifist players get the same quest stage and stopcombat at 3 hits +; else ; ; someone else hit him, stop the quest and have him berate you ; GetOwningQuest().SetStage(110) -; endif; No STR methods needed to reach stopcombat solution suggested in tiltedphoques/TiltedEvolution/issues/598 +; endif EndEvent Function ResetHits() From 55c553f531e7a7a224d5ae366205066e524204bb Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 6 Sep 2024 02:51:09 -0400 Subject: [PATCH 02/86] tweak: Version pinning (#710) --- xmake.lua | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/xmake.lua b/xmake.lua index 7d917ee0d..a959996df 100644 --- a/xmake.lua +++ b/xmake.lua @@ -30,6 +30,7 @@ if has_config("unitybuild") then add_rules("c++.unity_build", {batchsize = 12}) end +-- direct dependencies version pinning add_requires( "entt v3.10.0", "recastnavigation v1.6.0", @@ -41,7 +42,23 @@ add_requires( "mem 1.0.0", "glm 0.9.9+8", "sentry-native 0.7.1", - "zlib v1.3.1") + "zlib v1.3.1" +) +if is_plat("windows") then + add_requires( + "discord 3.2.1", + "imgui v1.89.7" + ) +end + +-- dependencies' dependencies version pinning +add_requireconfs("*.mimalloc", { version = "2.1.7", override = true }) +add_requireconfs("*.cmake", { version = "3.30.2", override = true }) +add_requireconfs("*.openssl", { version = "1.1.1-w", override = true }) +add_requireconfs("*.zlib", { version = "v1.3.1", override = true }) +if is_plat("linux") then + add_requireconfs("*.libcurl", { version = "8.7.1", override = true }) +end add_requireconfs("cpp-httplib", {configs = {ssl = true}}) add_requireconfs("sentry-native", { configs = { backend = "crashpad" } }) @@ -52,13 +69,6 @@ add_requireconfs("magnum-integration.magnum", { configs = { sdl2 = true }}) add_requireconfs("magnum-integration.imgui", { override = true }) --]] -if is_plat("windows") then - add_requires( - "discord 3.2.1", - "imgui v1.89.7" - ) -end - before_build(function (target) import("modules.version") local branch, commitHash = version() From a4b0de39d4c95e0522922013635b787edba4f54b Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 6 Sep 2024 11:27:24 -0400 Subject: [PATCH 03/86] tweak: update submodules to include version pinning (#711) --- Libraries/TiltedConnect | 2 +- Libraries/TiltedHooks | 2 +- Libraries/TiltedReverse | 2 +- Libraries/TiltedUI | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Libraries/TiltedConnect b/Libraries/TiltedConnect index dd0a55bf1..6b21f676d 160000 --- a/Libraries/TiltedConnect +++ b/Libraries/TiltedConnect @@ -1 +1 @@ -Subproject commit dd0a55bf1935eba85949df5bfa1fb32ae2e26d1e +Subproject commit 6b21f676dd5210b3ec1bab4d51f5f07afa83c535 diff --git a/Libraries/TiltedHooks b/Libraries/TiltedHooks index 854cec4a5..523bdfe2c 160000 --- a/Libraries/TiltedHooks +++ b/Libraries/TiltedHooks @@ -1 +1 @@ -Subproject commit 854cec4a515461df55d64d8f3bc89480536f2962 +Subproject commit 523bdfe2c6e1ddcf50da58055c353c2ef3c4a451 diff --git a/Libraries/TiltedReverse b/Libraries/TiltedReverse index 9d2dfa42c..136014238 160000 --- a/Libraries/TiltedReverse +++ b/Libraries/TiltedReverse @@ -1 +1 @@ -Subproject commit 9d2dfa42c5cbcc163e5017336701a7319571f53e +Subproject commit 1360142382fb59148cafa3d8f2257f15ce937729 diff --git a/Libraries/TiltedUI b/Libraries/TiltedUI index b5fc62088..dc37bcf75 160000 --- a/Libraries/TiltedUI +++ b/Libraries/TiltedUI @@ -1 +1 @@ -Subproject commit b5fc6208810e3cacb0feff76e7dba5f31856e0bd +Subproject commit dc37bcf75aea9153204588bcd099bbe007208649 From f142880244543edbd26b3542fe946582b0f44ab8 Mon Sep 17 00:00:00 2001 From: WeirdYunus <166413432+WeirdYunus@users.noreply.github.com> Date: Mon, 9 Sep 2024 21:55:59 +0300 Subject: [PATCH 04/86] Update tr.json (#709) --- Code/skyrim_ui/src/assets/i18n/tr.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Code/skyrim_ui/src/assets/i18n/tr.json b/Code/skyrim_ui/src/assets/i18n/tr.json index fa45ee874..10ea14342 100644 --- a/Code/skyrim_ui/src/assets/i18n/tr.json +++ b/Code/skyrim_ui/src/assets/i18n/tr.json @@ -4,6 +4,8 @@ "SEND": "Gönder", "MESSAGE": "Mesaj", "MESSAGE_TOO_LONG": "{{chatMessageLengthLimit}} harften daha uzun bir mesaj gönderemezsin." + "SET_TIME_ARGUMENT_COUNT": "Yanlış argümanlar, kullanımı: /settime SS DD, örnek: /settime 15 32.", + "SET_TIME_INVALID_ARGUMENTS": "Saat 0 ile 23 ve dakika 0 ile 59 arasında olmalıdır." }, "CONNECT": { "INFO": { @@ -149,6 +151,7 @@ "COMMANDS": { "AVAILABLE_COMMANDS": "Mevcut chat komutları: {{cmds}}", "COMMAND_NOT_FOUND": "'{{cmd}}' geçerli bir komut değil." + "NOT_ADMIN": "Bu komutu kullanmak için Admin olmanız gerek." }, "GROUP": { "LEVEL_UP": "{{name}} {{level}} oldu.", @@ -166,6 +169,8 @@ "WRONG_PASSWORD": "Girdiğiniz parola yanlış.", "NO_REASON": "Sunucu sebep vermeden bağlantıyı reddetti.", "SERVER_FULL": "Sunucu Dolu." + "BAD_UGRIDSTOLOAD": "Görünüşe göre Skyrim.ini dosyanız 'uGridsToLoad' için varsayılan değerde değil. BU ÇOK KÖTÜ BİR FİKİR, ve muhtemelen modu bozar. Lütfen bu ayarı varsayılana çekiniz (5), ya da Skyrim.ini dosyasını silip Skyrim'ı vanilla olarak başlatıp yenisini oluşturun. 'uExterior Cell Buffer' ve 'uInterior Cell Buffer' ayarları varsayılan olarak kalmalı. Bunu nasıl yapacağınızı bilmiyorsanız, Lütfen wiki sayfamıza bakın veya Discord sunucusu/Reddit üzerinden yardım isteyiniz.", + "NON_DEFAULT_INSTALL": "Görünüşe göre yüklemeniz tamamen vanilla değil, örneğin, Creation Club içeriği (Anniversary Güncellemesi ya da diğer türlüsü) ya da diğer modlar.\nModlar ile oynamanızı ÖNERMİYORUZ.\nBu modları silip deaktif etmenizi öneriyoruz (talimatlar wiki sayfasında bulunabilir).\n\nEn iyi deneyim için, bu mod listesine sahip olmanız gerek:\nSkyrim.esm\nUpdate.esm\nDawnguard.esm\nHearthFires.esm\nDragonborn.esm\n_ResourcePack.esl\nSkyrimTogether.esp" } }, "PLAYER_LIST": { From ab18db995bdd5c378dafdbb62b537b54c079ebf9 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 11 Sep 2024 04:17:54 -0400 Subject: [PATCH 05/86] Game exe path command line argument (#713) * feat: --exePath commandline argument ex. `SkyrimTogether.exe --exePath C:\Path\To\Game\SkyrimSE.exe` * tweak: add explicit target exe error * tweak: clang format * fix: properly terminate process when no exe path given * tweak: safer args bounds check + more explicit errors * tweak: remove global exePath & titlePath * tweak: clang format * tweak: const naming --- Code/immersive_launcher/Launcher.cpp | 36 ++++++-- Code/immersive_launcher/Launcher.h | 3 + Code/immersive_launcher/oobe/PathArgument.cpp | 82 +++++++++++++++++++ Code/immersive_launcher/oobe/PathArgument.h | 8 ++ 4 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 Code/immersive_launcher/oobe/PathArgument.cpp create mode 100644 Code/immersive_launcher/oobe/PathArgument.h diff --git a/Code/immersive_launcher/Launcher.cpp b/Code/immersive_launcher/Launcher.cpp index 0547a00de..185a7d9fd 100644 --- a/Code/immersive_launcher/Launcher.cpp +++ b/Code/immersive_launcher/Launcher.cpp @@ -10,10 +10,12 @@ #include "Utils/FileVersion.inl" #include "oobe/PathSelection.h" +#include "oobe/PathArgument.h" #include "oobe/SupportChecks.h" #include "steam/SteamLoader.h" #include "base/dialogues/win/TaskDialog.h" +#include "utils/Registry.h" #include @@ -64,11 +66,8 @@ void SetMaxstdio() int StartUp(int argc, char** argv) { bool askSelect = (GetAsyncKeyState(VK_SPACE) & 0x8000); - for (int i = 1; i < argc; i++) - { - if (std::strcmp(argv[i], "-r") == 0) - askSelect = true; - } + if (!HandleArguments(argc, argv, askSelect)) + return -1; // TODO(Force): Make some InitSharedResources func. g_SharedWindowIcon = LoadIconW(GetModuleHandleW(nullptr), MAKEINTRESOURCEW(102)); @@ -141,6 +140,33 @@ void InitClient() // Jump into client code. RunTiltedApp(); } + +bool HandleArguments(int aArgc, char** aArgv, bool& aAskSelect) +{ + for (int i = 1; i < aArgc; i++) + { + if (std::strcmp(aArgv[i], "-r") == 0) + aAskSelect = true; + else if (std::strcmp(aArgv[i], "--exePath") == 0) + { + if (i + 1 >= aArgc) + { + SetLastError(ERROR_BAD_PATHNAME); + Die(L"No exe path specified", true); + return false; + } + + if (!oobe::PathArgument(aArgv[i + 1])) + { + SetLastError(ERROR_BAD_ARGUMENTS); + Die(L"Failed to parse path argument", true); + return false; + } + } + } + + return true; +} } // namespace launcher // CreateProcess in suspended mode. diff --git a/Code/immersive_launcher/Launcher.h b/Code/immersive_launcher/Launcher.h index 4c1571d83..185cb3616 100644 --- a/Code/immersive_launcher/Launcher.h +++ b/Code/immersive_launcher/Launcher.h @@ -30,4 +30,7 @@ bool LoadProgram(LaunchContext&); int StartUp(int argc, char** argv); void InitClient(); + +bool HandleArguments(int, char**, bool&); + } // namespace launcher diff --git a/Code/immersive_launcher/oobe/PathArgument.cpp b/Code/immersive_launcher/oobe/PathArgument.cpp new file mode 100644 index 000000000..38daaaee6 --- /dev/null +++ b/Code/immersive_launcher/oobe/PathArgument.cpp @@ -0,0 +1,82 @@ +#include "PathArgument.h" + +#include "TargetConfig.h" + +#include "Utils/Error.h" +#include "utils/Registry.h" + +#include + +namespace oobe +{ +using namespace TiltedPhoques; + +namespace +{ +constexpr wchar_t kTiltedRegistryPath[] = LR"(Software\TiltedPhoques\TiltedEvolution\)" SHORT_NAME; + +#define DIE_NOW(err) \ + { \ + Die(err, true); \ + return false; \ + } + +bool ValidatePath(const std::wstring& acPath) +{ + const std::wstring cTitlePath = acPath.substr(0, acPath.find_last_of('\\')); + std::wstring errorText{}; + + if (acPath.find_last_of('\\') == std::string::npos || acPath.ends_with(*"\\")) + { + SetLastError(ERROR_BAD_PATHNAME); + errorText += L"Invalid path\n"; + } + + if (!acPath.ends_with(L".exe")) + { + SetLastError(ERROR_BAD_ARGUMENTS); + errorText += acPath.substr(acPath.find_last_of('\\') + 1, acPath.back()) + L" is not an executable file\n"; + } + else if (!acPath.ends_with(TARGET_NAME L".exe")) + { + SetLastError(ERROR_FILE_NOT_FOUND); + errorText += TARGET_NAME L".exe not found\n"; + } + + if (!std::filesystem::exists(acPath) || !std::filesystem::exists(cTitlePath)) + { + SetLastError(ERROR_BAD_PATHNAME); + errorText += L"Path does not exist\n"; + } + + if (!errorText.empty()) + { + errorText += L"\nPath: " + acPath; + DIE_NOW(errorText.c_str()) + } + + return true; +} +} // namespace + +bool PathArgument(const std::string& acPath) +{ + const std::wstring cExePath = std::wstring(acPath.begin(), acPath.end()); + const std::wstring cTitlePath = cExePath.substr(0, cExePath.find_last_of('\\')); + + if (!ValidatePath(cExePath)) + { + DIE_NOW(L"Failed to validate path") + } + + // Write to registry so oobe::SelectInstall can handle the rest + const bool result = Registry::WriteString(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitlePath", cTitlePath) && Registry::WriteString(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitleExe", cExePath); + + if (!result) + { + DIE_NOW(L"Failed to write to registry") + } + + return true; +} +} // namespace oobe diff --git a/Code/immersive_launcher/oobe/PathArgument.h b/Code/immersive_launcher/oobe/PathArgument.h new file mode 100644 index 000000000..8c2b8f1ba --- /dev/null +++ b/Code/immersive_launcher/oobe/PathArgument.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace oobe +{ +bool PathArgument(const std::string& acPath); +} From 5bb658b33a611661b6ffe7489b9990cfe59a25cd Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 14 Sep 2024 12:45:10 -0400 Subject: [PATCH 06/86] tweak: update addlib mod name (#714) --- Code/client/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/client/main.cpp b/Code/client/main.cpp index 580dcaf64..9b7341a51 100644 --- a/Code/client/main.cpp +++ b/Code/client/main.cpp @@ -16,7 +16,7 @@ static void ShowAddressLibraryError(const wchar_t* apGamePath) #if TP_SKYRIM64 auto errorDetail = fmt::format(L"Looking for it here: {}\\Data\\SKSE\\Plugins", apGamePath); - Base::TaskDialog dia(g_SharedWindowIcon, L"Error", L"Failed to load Skyrim Address Library", L"Make sure to use the All in one (Anniversary Edition) even if you don't have the Anniversary Edition upgrade", errorDetail.c_str()); + Base::TaskDialog dia(g_SharedWindowIcon, L"Error", L"Failed to load Skyrim Address Library", L"Make sure to use \"All in one (1.6.X)\"", errorDetail.c_str()); #elif TP_FALLOUT4 auto errorDetail = fmt::format(L"Looking for it here: {}\\Data\\F4SE\\Plugins", apGamePath); From 9441ae4090306ba95d060c0dcdef4b9373738cc6 Mon Sep 17 00:00:00 2001 From: Maxime <672982+maximegmd@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:25:06 +0200 Subject: [PATCH 07/86] Update windows.yml --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 791ad91ed..5723e146c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -30,7 +30,7 @@ jobs: - name: Setup xmake uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: '2.9.3' + xmake-version: '2.9.5' # Install node #- name: Setup nodejs From 26450effeb19b3ce5dca51c492eb79bd2dcfccdd Mon Sep 17 00:00:00 2001 From: Maxime <672982+maximegmd@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:25:24 +0200 Subject: [PATCH 08/86] Update linux.yml --- .github/workflows/linux.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 53d10aac4..c105d97b0 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -28,19 +28,12 @@ jobs: # Install dependencies - name: Update apt repositories run: sudo apt-get update - - - name: Install GCC12 - shell: bash - run: | - sudo apt update - sudo apt install gcc-12 g++-12 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 110 --slave /usr/bin/g++ g++ /usr/bin/g++-12 --slave /usr/bin/gcov gcov /usr/bin/gcov-12 # Install xmake - name: Setup xmake uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: '2.9.3' + xmake-version: '2.9.5' # Update xmake repository (in order to have the file that will be cached) - name: Update xmake repository From 68107c27cacb30c569aae6a1227da8b98065f8b0 Mon Sep 17 00:00:00 2001 From: Maxime <672982+maximegmd@users.noreply.github.com> Date: Sun, 29 Sep 2024 10:05:25 +0200 Subject: [PATCH 09/86] Attempt to fix sentry by using older version --- xmake.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake.lua b/xmake.lua index a959996df..d17717950 100644 --- a/xmake.lua +++ b/xmake.lua @@ -41,7 +41,7 @@ add_requires( "gtest v1.14.0", "mem 1.0.0", "glm 0.9.9+8", - "sentry-native 0.7.1", + "sentry-native 0.5", "zlib v1.3.1" ) if is_plat("windows") then From 2371e496041879cbfbc5d730a3d63ced6bfddcc1 Mon Sep 17 00:00:00 2001 From: Maxime <672982+maximegmd@users.noreply.github.com> Date: Sun, 29 Sep 2024 10:14:14 +0200 Subject: [PATCH 10/86] Update xmake.lua --- xmake.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake.lua b/xmake.lua index d17717950..6e40db890 100644 --- a/xmake.lua +++ b/xmake.lua @@ -41,7 +41,7 @@ add_requires( "gtest v1.14.0", "mem 1.0.0", "glm 0.9.9+8", - "sentry-native 0.5", + "sentry-native 0.4.15", "zlib v1.3.1" ) if is_plat("windows") then From 5bf8b5e92c3d17b86e0a53bba3d634d4ea911475 Mon Sep 17 00:00:00 2001 From: Daniil Zakharov Date: Sun, 29 Sep 2024 14:30:48 +0300 Subject: [PATCH 11/86] fix: attempt to temporarily fix failing linux CI --- .github/workflows/linux.yml | 14 ++++++++------ xmake.lua | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index c105d97b0..9dcceea44 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -18,7 +18,7 @@ jobs: if: "!contains(github.event.head_commit.message, 'ci skip')" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Checkout submodules run: | @@ -28,7 +28,7 @@ jobs: # Install dependencies - name: Update apt repositories run: sudo apt-get update - + # Install xmake - name: Setup xmake uses: xmake-io/github-action-setup-xmake@v1 @@ -40,13 +40,15 @@ jobs: run: xmake repo --update # Setup compilation mode and install project dependencies + # (continue-on-error + timeout is a temporary solution until sentry-native is fixed; shouldn't affect the building step) - name: Configure xmake and install dependencies - run: xmake config --arch=${{ matrix.arch }} --mode=${{ matrix.mode }} --yes + continue-on-error: true + run: timeout 15m xmake config --arch=${{ matrix.arch }} --mode=${{ matrix.mode }} --yes - # Build the game + # Build the server - name: Build - run: xmake - + run: xmake -y + # Create install #- name: Install # run: xmake install -o packaged diff --git a/xmake.lua b/xmake.lua index 6e40db890..a959996df 100644 --- a/xmake.lua +++ b/xmake.lua @@ -41,7 +41,7 @@ add_requires( "gtest v1.14.0", "mem 1.0.0", "glm 0.9.9+8", - "sentry-native 0.4.15", + "sentry-native 0.7.1", "zlib v1.3.1" ) if is_plat("windows") then From 394904d953047b1f71ac1fcc4b46a0e3e0df8e26 Mon Sep 17 00:00:00 2001 From: maximegmd <672982+maximegmd@users.noreply.github.com> Date: Sun, 29 Sep 2024 16:54:47 +0200 Subject: [PATCH 12/86] Update TiltedConnect --- Libraries/TiltedConnect | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/TiltedConnect b/Libraries/TiltedConnect index 6b21f676d..31b024eab 160000 --- a/Libraries/TiltedConnect +++ b/Libraries/TiltedConnect @@ -1 +1 @@ -Subproject commit 6b21f676dd5210b3ec1bab4d51f5f07afa83c535 +Subproject commit 31b024eab9337f11f3b5d0a41ec1173d2c0aeedb From 20b44d3ca2b1a65b601cd1534ac745eebe9bd859 Mon Sep 17 00:00:00 2001 From: Daniil Date: Wed, 2 Oct 2024 09:42:17 +0300 Subject: [PATCH 13/86] fix: bring back missing 'release' mode to the build config (#722) --- xmake.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake.lua b/xmake.lua index a959996df..c0378f318 100644 --- a/xmake.lua +++ b/xmake.lua @@ -23,7 +23,7 @@ add_vectorexts("sse", "sse2", "sse3", "ssse3") add_vectorexts("neon") -- build configurations -add_rules("mode.debug", "mode.releasedbg") +add_rules("mode.debug", "mode.releasedbg", "mode.release") if has_config("unitybuild") then add_rules("c.unity_build") From 652556b42092fb8d4478227a4de26f327ace4320 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 21 Aug 2024 16:27:30 -0400 Subject: [PATCH 14/86] Exeption handling fix so SetUnhandledExceptionFilter works. Enables various crashloggers to work with STR. CrashHandler is always constructed now, but is IS_MASTER aware and disables minidumps when IS_MASTER is true. Unless you turn the flag back on with a debugger. --- Code/client/CrashHandler.cpp | 149 ++++++++++++++++++++++++---------- Code/client/CrashHandler.h | 9 +- Code/client/TiltedOnlineApp.h | 4 - 3 files changed, 115 insertions(+), 47 deletions(-) diff --git a/Code/client/CrashHandler.cpp b/Code/client/CrashHandler.cpp index dfe707e3f..c11db473a 100644 --- a/Code/client/CrashHandler.cpp +++ b/Code/client/CrashHandler.cpp @@ -22,58 +22,123 @@ std::string SerializeTimePoint(const time_point& time, const std::string& format LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) { - static int alreadycrashed = 0; + static int alreadyCrashed = 0; + auto retval = EXCEPTION_CONTINUE_SEARCH; - if (pExceptionInfo->ExceptionRecord->ExceptionCode == 0xC0000005 && alreadycrashed++ == 0) - { - spdlog::error("Crash occurred!"); - MINIDUMP_EXCEPTION_INFORMATION M; - char dumpPath[MAX_PATH]; - - M.ThreadId = GetCurrentThreadId(); - M.ExceptionPointers = pExceptionInfo; - M.ClientPointers = 0; - - std::ostringstream oss; - oss << "crash_" << SerializeTimePoint(std::chrono::system_clock::now(), "UTC_%Y-%m-%d_%H-%M-%S") << ".dmp"; - - GetModuleFileNameA(NULL, dumpPath, sizeof(dumpPath)); - std::filesystem::path modulePath(dumpPath); - auto subPath = modulePath.parent_path(); - - CrashHandler::RemovePreviousDump(subPath); - - subPath /= oss.str(); - - auto hDumpFile = CreateFileA(subPath.string().c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - // baseline settings from https://stackoverflow.com/a/63123214/5273909 - auto dumpSettings = MiniDumpWithDataSegs | MiniDumpWithProcessThreadData | MiniDumpWithHandleData | MiniDumpWithThreadInfo | - /* - //MiniDumpWithPrivateReadWriteMemory | // this one gens bad dump - MiniDumpWithUnloadedModules | - MiniDumpWithFullMemoryInfo | - MiniDumpWithTokenInformation | - MiniDumpWithPrivateWriteCopyMemory | - */ - 0; + // Serialize + static std::mutex singleThreaded;; + const std::lock_guard lock{singleThreaded}; - MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, (MINIDUMP_TYPE)dumpSettings, (pExceptionInfo) ? &M : NULL, NULL, NULL); - - CloseHandle(hDumpFile); + // Check for severe, not continuable and not software-originated exception + if (pExceptionInfo->ExceptionRecord->ExceptionCode >= 0x80000000 && + (pExceptionInfo->ExceptionRecord->ExceptionFlags & EXCEPTION_SOFTWARE_ORIGINATE) == 0 && + alreadyCrashed++ == 0) + { + spdlog::critical (__FUNCTION__ ": crash occurred!"); + + auto present = IsDebuggerPresent() ? "already" : "not"; + spdlog::error(__FUNCTION__ ": debugger is {} present at critical exception time, code{:x}, address{}, flags {:x} ", + present, + pExceptionInfo->ExceptionRecord->ExceptionCode, + pExceptionInfo->ExceptionRecord->ExceptionAddress, + pExceptionInfo->ExceptionRecord->ExceptionFlags); + +#if (IS_MASTER) + volatile static bool bMiniDump = false; +#else + volatile static bool bMiniDump = true; +#endif + if (bMiniDump) + { + HANDLE hDumpFile = NULL; + try + { + MINIDUMP_EXCEPTION_INFORMATION M; + char dumpPath[MAX_PATH]; + + M.ThreadId = GetCurrentThreadId(); + M.ExceptionPointers = pExceptionInfo; + M.ClientPointers = 0; + + std::ostringstream oss; + oss << "crash_" << SerializeTimePoint(std::chrono::system_clock::now(), "UTC_%Y-%m-%d_%H-%M-%S") + << ".dmp"; + + GetModuleFileNameA(NULL, dumpPath, sizeof(dumpPath)); + std::filesystem::path modulePath(dumpPath); + auto subPath = modulePath.parent_path(); + + CrashHandler::RemovePreviousDump(subPath); + + subPath /= oss.str(); + + hDumpFile = CreateFileA(subPath.string().c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + + // baseline settings from https://stackoverflow.com/a/63123214/5273909 + auto dumpSettings = MiniDumpWithDataSegs | MiniDumpWithProcessThreadData | MiniDumpWithHandleData | + MiniDumpWithThreadInfo | + /* + //MiniDumpWithPrivateReadWriteMemory | // this one gens bad dump + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithTokenInformation | + MiniDumpWithPrivateWriteCopyMemory | + */ + 0; + + MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, (MINIDUMP_TYPE)dumpSettings, + (pExceptionInfo) ? &M : NULL, NULL, NULL); + } + catch (...) // Mini-dump is best effort only. + { + } + + if (!hDumpFile) + spdlog::critical(__FUNCTION__ ": coredump may have failed."); + else + { + CloseHandle(hDumpFile); + spdlog::critical(__FUNCTION__ ": coredump created -> flush logs."); + } + } - spdlog::error("Coredump created -> flush logs."); spdlog::default_logger()->flush(); - return EXCEPTION_EXECUTE_HANDLER; - } + // Something in STR breaks top-level unhandled exception filters. + // The Win API for them is pretty clunky (non-atomic, not chainable), + // but they can do some important things. If someone actually set one + // they probably meant it; make sure it actually runs. + // This will make more CrashLogger mods work with STR. + + // Get the current unhandled exception filter. If it has changed + // from when STR started up, invoke it here. + LPTOP_LEVEL_EXCEPTION_FILTER pCurrentUnhandledExceptionFilter = SetUnhandledExceptionFilter(CrashHandler::GetOriginalUnhandledExceptionFilter()); + SetUnhandledExceptionFilter(pCurrentUnhandledExceptionFilter); + if (pCurrentUnhandledExceptionFilter != CrashHandler::GetOriginalUnhandledExceptionFilter()) + { + spdlog::critical(__FUNCTION__ ": UnhandledExceptionFilter() workaround triggered."); - return EXCEPTION_CONTINUE_SEARCH; + singleThreaded.unlock(); // Might reenter, but is safe at this point. + if ((*pCurrentUnhandledExceptionFilter)(pExceptionInfo) == EXCEPTION_CONTINUE_EXECUTION) + retval = EXCEPTION_CONTINUE_EXECUTION; + singleThreaded.lock(); + } + } + return retval; } +LPTOP_LEVEL_EXCEPTION_FILTER CrashHandler::m_pUnhandled; CrashHandler::CrashHandler() { - AddVectoredExceptionHandler(1, &VectoredExceptionHandler); + // Record the original (or as close as we can get) top-level unhandled exception handler. + // We grab this so we can see if it is changed, presumably by a mod or even graphics drivers. + // Something in STR breaks unhandled exception handling, so we'll fake it if necessary. + // This is the only way to get the current setting, but the race is small. + m_pUnhandled = SetUnhandledExceptionFilter(NULL); + SetUnhandledExceptionFilter(m_pUnhandled); + + m_handler = AddVectoredExceptionHandler(1, &VectoredExceptionHandler); } CrashHandler::~CrashHandler() diff --git a/Code/client/CrashHandler.h b/Code/client/CrashHandler.h index bd4fe02ab..c2ade17b0 100644 --- a/Code/client/CrashHandler.h +++ b/Code/client/CrashHandler.h @@ -2,9 +2,16 @@ class CrashHandler { -public: + PVOID m_handler; + static LPTOP_LEVEL_EXCEPTION_FILTER m_pUnhandled; // For remembering "original" UnhandledExceptionFilter + + public: CrashHandler(); ~CrashHandler(); static void RemovePreviousDump(std::filesystem::path path); + static inline LPTOP_LEVEL_EXCEPTION_FILTER GetOriginalUnhandledExceptionFilter() + { + return m_pUnhandled; + } }; diff --git a/Code/client/TiltedOnlineApp.h b/Code/client/TiltedOnlineApp.h index 19f17649b..aeab47e2d 100644 --- a/Code/client/TiltedOnlineApp.h +++ b/Code/client/TiltedOnlineApp.h @@ -37,10 +37,6 @@ struct TiltedOnlineApp final : App private: void ApplyNvidiaFix() noexcept; -#if (!IS_MASTER) CrashHandler m_crashHandler; -#else - //ScopedCrashHandler m_crashHandler; -#endif ID3D11Device* m_pDevice = nullptr; }; From 760239fa5ee4e0e67d43b23f76ce27541309b800 Mon Sep 17 00:00:00 2001 From: rfortier Date: Sat, 24 Aug 2024 12:46:19 -0400 Subject: [PATCH 15/86] C++ exceptions are severe, but don't assert EXCEPTION_SOFTWARE_ORIGINATE flag, so need a special case. --- Code/client/CrashHandler.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Code/client/CrashHandler.cpp b/Code/client/CrashHandler.cpp index c11db473a..a80ffc776 100644 --- a/Code/client/CrashHandler.cpp +++ b/Code/client/CrashHandler.cpp @@ -31,14 +31,13 @@ LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) // Check for severe, not continuable and not software-originated exception if (pExceptionInfo->ExceptionRecord->ExceptionCode >= 0x80000000 && + pExceptionInfo->ExceptionRecord->ExceptionCode != 0xE06D7363 && // Sigh. C++ exceptions forgot the SOFTWARE_ORIGINATE flag. (pExceptionInfo->ExceptionRecord->ExceptionFlags & EXCEPTION_SOFTWARE_ORIGINATE) == 0 && alreadyCrashed++ == 0) { spdlog::critical (__FUNCTION__ ": crash occurred!"); - auto present = IsDebuggerPresent() ? "already" : "not"; - spdlog::error(__FUNCTION__ ": debugger is {} present at critical exception time, code{:x}, address{}, flags {:x} ", - present, + spdlog::error(__FUNCTION__ ": exception code is {:x}, at address {}, flags {:x} ", pExceptionInfo->ExceptionRecord->ExceptionCode, pExceptionInfo->ExceptionRecord->ExceptionAddress, pExceptionInfo->ExceptionRecord->ExceptionFlags); From 666d7bb4720e0822aee23e60c027f67e5e3e0f89 Mon Sep 17 00:00:00 2001 From: rfortier Date: Mon, 30 Sep 2024 14:25:11 -0400 Subject: [PATCH 16/86] Updated to latest /dev, restricted caught exceptions Rebased to current /dev Made the fix a bit safer by only catching EXCEPTION_ACCESS_VIOLATION, at the risk of not getting crahs dumps/logs for a few obscure and infrequest crash types. This is consistent with when crash dumps were triggered before this PR. --- Code/client/CrashHandler.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Code/client/CrashHandler.cpp b/Code/client/CrashHandler.cpp index a80ffc776..655a4a9be 100644 --- a/Code/client/CrashHandler.cpp +++ b/Code/client/CrashHandler.cpp @@ -30,9 +30,7 @@ LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) const std::lock_guard lock{singleThreaded}; // Check for severe, not continuable and not software-originated exception - if (pExceptionInfo->ExceptionRecord->ExceptionCode >= 0x80000000 && - pExceptionInfo->ExceptionRecord->ExceptionCode != 0xE06D7363 && // Sigh. C++ exceptions forgot the SOFTWARE_ORIGINATE flag. - (pExceptionInfo->ExceptionRecord->ExceptionFlags & EXCEPTION_SOFTWARE_ORIGINATE) == 0 && + if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && alreadyCrashed++ == 0) { spdlog::critical (__FUNCTION__ ": crash occurred!"); From 1a45f7c79367a72e56605d328acc6bca7ddd7bff Mon Sep 17 00:00:00 2001 From: Daniil Zakharov Date: Thu, 24 Oct 2024 01:28:18 +0300 Subject: [PATCH 17/86] Fix cell-change crash caused by use-after-free of BGSAttackDataMap Updated to `NiPointer` which uses refcount --- Code/client/Games/Skyrim/Components/BGSAttackDataForm.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/client/Games/Skyrim/Components/BGSAttackDataForm.h b/Code/client/Games/Skyrim/Components/BGSAttackDataForm.h index 002a409fe..e14b11969 100644 --- a/Code/client/Games/Skyrim/Components/BGSAttackDataForm.h +++ b/Code/client/Games/Skyrim/Components/BGSAttackDataForm.h @@ -1,6 +1,7 @@ #pragma once #include +#include struct BGSAttackDataMap : NiRefObject { @@ -8,5 +9,5 @@ struct BGSAttackDataMap : NiRefObject struct BGSAttackDataForm : BaseFormComponent { - BGSAttackDataMap* attackDataMap; + NiPointer attackDataMap; }; From b63023bf5a5bcfad28ad1aa4c8b7ac19111de7fb Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 23 Oct 2024 19:22:06 -0400 Subject: [PATCH 18/86] Remove redundant UnEquipAll() call which seems to trigger a Skyrim concurrency bug. --- Code/client/Games/Skyrim/Actor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Code/client/Games/Skyrim/Actor.cpp b/Code/client/Games/Skyrim/Actor.cpp index f587dcab1..8f67f5cb1 100644 --- a/Code/client/Games/Skyrim/Actor.cpp +++ b/Code/client/Games/Skyrim/Actor.cpp @@ -395,7 +395,9 @@ void Actor::SetActorInventory(const Inventory& aInventory) noexcept { spdlog::info("Setting inventory for actor {:X}", formID); - UnEquipAll(); + // The UnEquipAll() that used to be here is redundant, + // as RemoveAllItems() unequips every item if needed. + // Placing this UnEquipAll() here seems to trigger a Skyrim bug/race. SetInventory(aInventory); SetMagicEquipment(aInventory.CurrentMagicEquipment); From 49bfc73267a3b4ca55d66928c2e2793982416d62 Mon Sep 17 00:00:00 2001 From: rfortier Date: Mon, 21 Oct 2024 21:49:54 -0400 Subject: [PATCH 19/86] Don't accept OnRemoteSpawnDataReceived data for the local PlayerCharacter that the remote system is obviously not authoratative for. From the code comment: Only accept spawn position and inventory updates if not for local player The remote system is simply not authoritative for this info, and trying to take it from the remote can result in concurrent update corruption That's the real problem, either s_pRemoveAllItems or s_unequipAll have async behavior themselves or undocumented behavior that causes concurrency issues. --- .../Services/Generic/CharacterService.cpp | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Code/client/Services/Generic/CharacterService.cpp b/Code/client/Services/Generic/CharacterService.cpp index 0bb9f705f..d1c852cf6 100644 --- a/Code/client/Services/Generic/CharacterService.cpp +++ b/Code/client/Services/Generic/CharacterService.cpp @@ -512,9 +512,27 @@ void CharacterService::OnRemoteSpawnDataReceived(const NotifySpawnData& acMessag if (!pActor) return; - pActor->SetActorValues(acMessage.NewActorData.InitialActorValues); - pActor->SetActorInventory(acMessage.NewActorData.InitialInventory); - m_weaponDrawUpdates[pActor->formID] = {acMessage.NewActorData.IsWeaponDrawn}; + // Only accept spawn position and inventory updates if not for local player + // The remote system is simply not authoritative for this info, and trying + // to take it from the remote can result in concurrent update corruption + // That's the real problem, either s_pRemoveAllItems or s_unequipAll + // have async behavior themselves or undocumented behavior that + // causes concurrency issues. + if (pActor->GetExtension()->IsPlayer() && !pActor->GetExtension()->IsRemote()) + { +#if TP_SKYRIM64 + auto pNpc = Cast(pActor); + auto pName = pNpc ? static_cast(pNpc->fullName.value) : ""; + spdlog::warn(__FUNCTION__ ": rejecting non-authoritative remote spawn update for local player pActor{:X}, formID{:X}, name \"{}\"", + (uintptr_t)pActor, pActor->formID, pName); +#endif + } + else + { + pActor->SetActorValues(acMessage.NewActorData.InitialActorValues); + pActor->SetActorInventory(acMessage.NewActorData.InitialInventory); + m_weaponDrawUpdates[pActor->formID] = {acMessage.NewActorData.IsWeaponDrawn}; + } if (pActor->IsDead() != acMessage.NewActorData.IsDead) acMessage.NewActorData.IsDead ? pActor->Kill() : pActor->Respawn(); From ed79bf1d44ef5cd174872ff3f5349f48db4ccfb7 Mon Sep 17 00:00:00 2001 From: rfortier Date: Tue, 22 Oct 2024 17:47:17 -0400 Subject: [PATCH 20/86] Loosen the check ALL local NPCs should reject updated remote spawn data looping back to themselves. --- .../Services/Generic/CharacterService.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Code/client/Services/Generic/CharacterService.cpp b/Code/client/Services/Generic/CharacterService.cpp index d1c852cf6..e0ecf6633 100644 --- a/Code/client/Services/Generic/CharacterService.cpp +++ b/Code/client/Services/Generic/CharacterService.cpp @@ -512,13 +512,18 @@ void CharacterService::OnRemoteSpawnDataReceived(const NotifySpawnData& acMessag if (!pActor) return; - // Only accept spawn position and inventory updates if not for local player - // The remote system is simply not authoritative for this info, and trying - // to take it from the remote can result in concurrent update corruption - // That's the real problem, either s_pRemoveAllItems or s_unequipAll - // have async behavior themselves or undocumented behavior that + // Only accept spawn position and inventory updates for REMOTE Npcs. + // The remote system is simply not authoritative for local Npc info, and trying + // to take it from the remote can result in concurrent update corruption. + // This is true whether it is a local Player (and therefor remote from the + // Leader), or a local NPC that is with their leader or is owned instead by + // the local player and their own data, possibly out-of-date, is looping + // back in OnRemoteSpawnDataReceived + // + // The underlying problem, either s_pRemoveAllItems or s_unequipAll + // have async behavior themselves or undocumented behavior that // causes concurrency issues. - if (pActor->GetExtension()->IsPlayer() && !pActor->GetExtension()->IsRemote()) + if (!pActor->GetExtension()->IsRemote()) { #if TP_SKYRIM64 auto pNpc = Cast(pActor); From 85b032f7172db0f21397123a48fa07c4a5d837d2 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 23 Oct 2024 12:56:36 -0400 Subject: [PATCH 21/86] Better logging for debugging distributed multithreaded apps. --- Code/client/TiltedOnlineApp.cpp | 2 +- Code/server_runner/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/client/TiltedOnlineApp.cpp b/Code/client/TiltedOnlineApp.cpp index a6da26aa8..5fed4bf59 100644 --- a/Code/client/TiltedOnlineApp.cpp +++ b/Code/client/TiltedOnlineApp.cpp @@ -35,7 +35,7 @@ TiltedOnlineApp::TiltedOnlineApp() auto rotatingLogger = std::make_shared(logPath / "tp_client.log", 1048576 * 5, 3); // rotatingLogger->set_level(spdlog::level::debug); auto console = std::make_shared(); - console->set_pattern("%^[%H:%M:%S] [%l]%$ %v"); + console->set_pattern("%^[%H:%M:%S.%e] [%l] [tid %t] %$ %v"); auto logger = std::make_shared("", spdlog::sinks_init_list{console, rotatingLogger}); set_default_logger(logger); diff --git a/Code/server_runner/main.cpp b/Code/server_runner/main.cpp index 1fe0150da..2f7fb414a 100644 --- a/Code/server_runner/main.cpp +++ b/Code/server_runner/main.cpp @@ -73,7 +73,7 @@ struct LogInstance auto fileOut = std::make_shared(std::string("logs/") + kLogFileName, kLogFileSizeCap, 3); auto serverOut = std::make_shared(); - serverOut->set_pattern("%^[%H:%M:%S] [%l]%$ %v"); + serverOut->set_pattern("%^[%H:%M:%S.%e] [%l] [tid %t] %$ %v"); auto globalOut = std::make_shared("", sinks_init_list{serverOut, fileOut}); globalOut->set_level(level::from_str(sLogLevel.value())); From 6202d302d05d10c47833f1e1b1e85302a9d536ea Mon Sep 17 00:00:00 2001 From: rfortier Date: Sat, 26 Oct 2024 10:12:25 -0400 Subject: [PATCH 22/86] Fix typo --- Code/client/CrashHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/client/CrashHandler.cpp b/Code/client/CrashHandler.cpp index 655a4a9be..d7f5e96a1 100644 --- a/Code/client/CrashHandler.cpp +++ b/Code/client/CrashHandler.cpp @@ -26,7 +26,7 @@ LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) auto retval = EXCEPTION_CONTINUE_SEARCH; // Serialize - static std::mutex singleThreaded;; + static std::mutex singleThreaded; const std::lock_guard lock{singleThreaded}; // Check for severe, not continuable and not software-originated exception From 90946c7288fda7f8988a59ca3b05101a9a826090 Mon Sep 17 00:00:00 2001 From: rfortier Date: Sat, 26 Oct 2024 13:32:41 -0400 Subject: [PATCH 23/86] Revert "Loosen the check ALL local NPCs should reject updated remote spawn data looping back to themselves." This reverts commit ed79bf1d44ef5cd174872ff3f5349f48db4ccfb7. --- .../Services/Generic/CharacterService.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Code/client/Services/Generic/CharacterService.cpp b/Code/client/Services/Generic/CharacterService.cpp index e0ecf6633..d1c852cf6 100644 --- a/Code/client/Services/Generic/CharacterService.cpp +++ b/Code/client/Services/Generic/CharacterService.cpp @@ -512,18 +512,13 @@ void CharacterService::OnRemoteSpawnDataReceived(const NotifySpawnData& acMessag if (!pActor) return; - // Only accept spawn position and inventory updates for REMOTE Npcs. - // The remote system is simply not authoritative for local Npc info, and trying - // to take it from the remote can result in concurrent update corruption. - // This is true whether it is a local Player (and therefor remote from the - // Leader), or a local NPC that is with their leader or is owned instead by - // the local player and their own data, possibly out-of-date, is looping - // back in OnRemoteSpawnDataReceived - // - // The underlying problem, either s_pRemoveAllItems or s_unequipAll - // have async behavior themselves or undocumented behavior that + // Only accept spawn position and inventory updates if not for local player + // The remote system is simply not authoritative for this info, and trying + // to take it from the remote can result in concurrent update corruption + // That's the real problem, either s_pRemoveAllItems or s_unequipAll + // have async behavior themselves or undocumented behavior that // causes concurrency issues. - if (!pActor->GetExtension()->IsRemote()) + if (pActor->GetExtension()->IsPlayer() && !pActor->GetExtension()->IsRemote()) { #if TP_SKYRIM64 auto pNpc = Cast(pActor); From c53d7c86a93333cc758a31a02ff0a44f619bebbf Mon Sep 17 00:00:00 2001 From: rfortier Date: Sat, 26 Oct 2024 13:33:22 -0400 Subject: [PATCH 24/86] Revert "Don't accept OnRemoteSpawnDataReceived data for the local PlayerCharacter that the remote system is obviously not authoratative for." This reverts commit 49bfc73267a3b4ca55d66928c2e2793982416d62. --- .../Services/Generic/CharacterService.cpp | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/Code/client/Services/Generic/CharacterService.cpp b/Code/client/Services/Generic/CharacterService.cpp index d1c852cf6..0bb9f705f 100644 --- a/Code/client/Services/Generic/CharacterService.cpp +++ b/Code/client/Services/Generic/CharacterService.cpp @@ -512,27 +512,9 @@ void CharacterService::OnRemoteSpawnDataReceived(const NotifySpawnData& acMessag if (!pActor) return; - // Only accept spawn position and inventory updates if not for local player - // The remote system is simply not authoritative for this info, and trying - // to take it from the remote can result in concurrent update corruption - // That's the real problem, either s_pRemoveAllItems or s_unequipAll - // have async behavior themselves or undocumented behavior that - // causes concurrency issues. - if (pActor->GetExtension()->IsPlayer() && !pActor->GetExtension()->IsRemote()) - { -#if TP_SKYRIM64 - auto pNpc = Cast(pActor); - auto pName = pNpc ? static_cast(pNpc->fullName.value) : ""; - spdlog::warn(__FUNCTION__ ": rejecting non-authoritative remote spawn update for local player pActor{:X}, formID{:X}, name \"{}\"", - (uintptr_t)pActor, pActor->formID, pName); -#endif - } - else - { - pActor->SetActorValues(acMessage.NewActorData.InitialActorValues); - pActor->SetActorInventory(acMessage.NewActorData.InitialInventory); - m_weaponDrawUpdates[pActor->formID] = {acMessage.NewActorData.IsWeaponDrawn}; - } + pActor->SetActorValues(acMessage.NewActorData.InitialActorValues); + pActor->SetActorInventory(acMessage.NewActorData.InitialInventory); + m_weaponDrawUpdates[pActor->formID] = {acMessage.NewActorData.IsWeaponDrawn}; if (pActor->IsDead() != acMessage.NewActorData.IsDead) acMessage.NewActorData.IsDead ? pActor->Kill() : pActor->Respawn(); From a6fff0cc6a246e3f0a15507383c83fd0a5435958 Mon Sep 17 00:00:00 2001 From: Daniil Date: Fri, 1 Nov 2024 15:27:46 +0300 Subject: [PATCH 25/86] Change `D3D11CreateDevice` invocation in NvidiaUtil to a dynamic one (#728) Black screen fix still applies. Dynamic invocation is needed in order not to link `d3d11.dll` at compile-time (compile-time linking breaks ENB and other mods that use d3d11.dll as a proxy) Co-authored-by: rfortier --- Code/client/NvidiaUtil.cpp | 17 +++++++++++++---- Code/client/NvidiaUtil.h | 2 +- Code/client/TiltedOnlineApp.cpp | 7 ++++--- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Code/client/NvidiaUtil.cpp b/Code/client/NvidiaUtil.cpp index 27dd513c7..cc9b5d8e3 100644 --- a/Code/client/NvidiaUtil.cpp +++ b/Code/client/NvidiaUtil.cpp @@ -7,10 +7,19 @@ bool IsNvidiaOverlayLoaded() } // This makes the Nvidia overlay happy. -// The call to D3D11CreateDevice probably causes some of their +// The call to `D3D11CreateDevice` probably causes some of their // internal hooks to be called and do the required init work before the game window opens. -HRESULT CreateEarlyDxDevice(ID3D11Device* apOutDevice, D3D_FEATURE_LEVEL* apOutFeatureLevel) +// +// We do dynamic invocation in order not to link `d3d11.dll` at compile-time +HRESULT CreateEarlyDxDevice(ID3D11Device** appOutDevice, D3D_FEATURE_LEVEL* apOutFeatureLevel) { - return D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &apOutDevice, - apOutFeatureLevel, nullptr); + HMODULE d3d11Module = GetModuleHandleW(L"d3d11.dll"); + if (!d3d11Module) + return E_FAIL; + + const auto pD3D11CreateDeviceFn = + reinterpret_cast(GetProcAddress(d3d11Module, "D3D11CreateDevice")); + + return pD3D11CreateDeviceFn(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, + appOutDevice, apOutFeatureLevel, nullptr); } diff --git a/Code/client/NvidiaUtil.h b/Code/client/NvidiaUtil.h index 6a5666510..b1b253884 100644 --- a/Code/client/NvidiaUtil.h +++ b/Code/client/NvidiaUtil.h @@ -5,4 +5,4 @@ bool IsNvidiaOverlayLoaded(); -HRESULT CreateEarlyDxDevice(ID3D11Device* apOutDevice, D3D_FEATURE_LEVEL* apOutFeatureLevel); +HRESULT CreateEarlyDxDevice(ID3D11Device** appOutDevice, D3D_FEATURE_LEVEL* apOutFeatureLevel); diff --git a/Code/client/TiltedOnlineApp.cpp b/Code/client/TiltedOnlineApp.cpp index 5fed4bf59..a55f6bd65 100644 --- a/Code/client/TiltedOnlineApp.cpp +++ b/Code/client/TiltedOnlineApp.cpp @@ -59,6 +59,7 @@ bool TiltedOnlineApp::BeginMain() LoadScriptExender(); + // TODO: Figure out a way to un-blacklist NvCamera64.dll (see DllBlocklist.cpp). Then this hack can be removed if (IsNvidiaOverlayLoaded()) ApplyNvidiaFix(); @@ -118,11 +119,11 @@ void TiltedOnlineApp::UninstallHooks() void TiltedOnlineApp::ApplyNvidiaFix() noexcept { - auto d3dFeatureLevel = D3D_FEATURE_LEVEL_11_0; - HRESULT hr = CreateEarlyDxDevice(m_pDevice, &d3dFeatureLevel); + auto d3dFeatureLevelOut = D3D_FEATURE_LEVEL_11_0; + HRESULT hr = CreateEarlyDxDevice(&m_pDevice, &d3dFeatureLevelOut); if (FAILED(hr)) spdlog::error("D3D11CreateDevice failed. Detected an NVIDIA GPU, error code={0:x}", hr); - if (d3dFeatureLevel < D3D_FEATURE_LEVEL_11_0) + if (d3dFeatureLevelOut < D3D_FEATURE_LEVEL_11_0) spdlog::warn("Unexpected D3D11 feature level detected (< 11.0), may cause issues"); } From 40ba37b404cb1c3718a47aa09956a06501396eb2 Mon Sep 17 00:00:00 2001 From: rfortier Date: Thu, 22 Feb 2024 16:55:47 -0500 Subject: [PATCH 26/86] Remove limit to BehaviorVars on the wire. STR is up against the limit, using 62 of a hardwired 64 boolean behavior vars to be synced. This fix removes the limit before it becomes a barrier. Since "unlimited" will bite us, note the base code has some lengths encoded in 16-bit ints that will bite eventually. Trying to sync even a fraction of that many will cause problems, though. Reimplemented the Boolean long long as a (bit) Vector. This made all vars (bools, ints, floats) vectors, so some code simplification of the wire protocol is accessible. The Booleans are just passed "as is," no attempt to detect which ones changed as the space required to send the delta is more than just sending the bits. Overall impact on wire protocol: sending humanoids will be slightly longer, as the 64-bits available is almost full. But that's longer by a byte (or maybe two since I used String to simplify the code). Everything else sent will be shorter and less overhead. There's no avoiding iterating the bits of the Vector. But the overhead when translating the array of to an array of bits and back is about the same. There was a bunch of extra overhead if Serialization::WriteBool() were to be used, so optimized that part out. Overall, should be better on the wire, and neutral-to-better on CPU. 2nd commit msg: Reworked creating and applying Behavior variable diffs and serializing them. Simpler, easier to read, should usually save bytes on the wire. --- Code/client/Games/References.cpp | 13 +- Code/encoding/Structs/AnimationVariables.cpp | 214 +++++++++---------- Code/encoding/Structs/AnimationVariables.h | 4 +- Code/tests/encoding.cpp | 18 +- 4 files changed, 122 insertions(+), 127 deletions(-) diff --git a/Code/client/Games/References.cpp b/Code/client/Games/References.cpp index b0b836a17..477ea6189 100644 --- a/Code/client/Games/References.cpp +++ b/Code/client/Games/References.cpp @@ -227,10 +227,9 @@ void TESObjectREFR::SaveAnimationVariables(AnimationVariables& aVariables) const if (!pVariableSet) return; - aVariables.Booleans = 0; - - aVariables.Floats.resize(pDescriptor->FloatLookupTable.size()); - aVariables.Integers.resize(pDescriptor->IntegerLookupTable.size()); + aVariables.Booleans.assign(pDescriptor->BooleanLookUpTable.size(), false); + aVariables.Floats.assign(pDescriptor->FloatLookupTable.size(), 0.f); + aVariables.Integers.assign(pDescriptor->IntegerLookupTable.size(), 0); #if TP_FALLOUT4 // TODO: maybe send a var with the variables indicating first or third person? @@ -251,14 +250,14 @@ void TESObjectREFR::SaveAnimationVariables(AnimationVariables& aVariables) const continue; if (pFirstPersonVariables->data[*firstPersonIdx] != 0) - aVariables.Booleans |= (1ull << i); + aVariables.Booleans[i] = true; continue; } #endif if (pVariableSet->data[idx] != 0) - aVariables.Booleans |= (1ull << i); + aVariables.Booleans[i] = true; } for (size_t i = 0; i < pDescriptor->FloatLookupTable.size(); ++i) @@ -361,7 +360,7 @@ void TESObjectREFR::LoadAnimationVariables(const AnimationVariables& aVariables) if (pVariableSet->size > idx) { - pVariableSet->data[idx] = (aVariables.Booleans & (1ull << i)) != 0; + pVariableSet->data[idx] = aVariables.Booleans[i]; } } diff --git a/Code/encoding/Structs/AnimationVariables.cpp b/Code/encoding/Structs/AnimationVariables.cpp index c23bfcf8f..b37d51bec 100644 --- a/Code/encoding/Structs/AnimationVariables.cpp +++ b/Code/encoding/Structs/AnimationVariables.cpp @@ -12,141 +12,123 @@ bool AnimationVariables::operator!=(const AnimationVariables& acRhs) const noexc return !this->operator==(acRhs); } +// std::vector implementation is unspecified, but often packed reasonably. +// The spec does not guarantee contiguous memory, though, so somewhat laborious +// translation needed. Should be better than winding down several layers to +// TiltedPhoques::Serialization::WriteBool, though. +// +void AnimationVariables::VectorBool_to_String(const Vector& bools, TiltedPhoques::String& chars) const +{ + chars.assign((bools.size() + 7) >> 3, 0); + + auto citer = chars.begin(); + auto biter = bools.begin(); + for (uint32_t mask = 1; biter < bools.end(); mask = 1, citer++) + for (; mask < 0x100 && biter < bools.end(); mask <<= 1) + *citer |= *biter++ ? mask : 0; +} + +// The Vector must be the correct size when called. +// +void AnimationVariables::String_to_VectorBool(const TiltedPhoques::String& chars, Vector& bools) +{ + bools.assign(bools.size(), false); + + auto citer = chars.begin(); + auto biter = bools.begin(); + for (uint32_t mask = 1; biter < bools.end(); mask = 1, citer++) + for (; mask < 0x100 && biter < bools.end(); mask <<= 1) + *biter++ = (*citer & mask) ? true : false; +} + + void AnimationVariables::Load(std::istream& aInput) { - aInput.read(reinterpret_cast(&Booleans), sizeof(Booleans)); + // Booleans are bitpacked and a bit different, not guaranteed contiguous. + TiltedPhoques::String chars((Booleans.size() + 7) >> 3, 0); + + aInput.read(reinterpret_cast(chars.data()), chars.size()); + String_to_VectorBool(chars, Booleans); aInput.read(reinterpret_cast(Integers.data()), Integers.size() * sizeof(uint32_t)); aInput.read(reinterpret_cast(Floats.data()), Floats.size() * sizeof(float)); } void AnimationVariables::Save(std::ostream& aOutput) const { - aOutput.write(reinterpret_cast(&Booleans), sizeof(Booleans)); + // Booleans bitpacked and not guaranteed contiguous. + TiltedPhoques::String chars; + VectorBool_to_String(Booleans, chars); + + aOutput.write(reinterpret_cast(chars.data()), chars.size()); aOutput.write(reinterpret_cast(Integers.data()), Integers.size() * sizeof(uint32_t)); aOutput.write(reinterpret_cast(Floats.data()), Floats.size() * sizeof(float)); } +// Wire format description. +// +// Sends 3 VarInts, the count of Booleans, Integers and Floats, in that order. Then sends a bitstream of the +// sum of those counts. For the Booleans, these represent the bit values for the Booleans. For the Integers and +// Floats, it represents a truth table for whether the value has changed. If values HAVE changed, they follow on +// the stream. +// +// void AnimationVariables::GenerateDiff(const AnimationVariables& aPrevious, TiltedPhoques::Buffer::Writer& aWriter) const { - uint64_t changes = 0; - uint32_t idx = 0; - - if (Booleans != aPrevious.Booleans) - { - changes |= (1ull << idx); - } - ++idx; - - auto integers = aPrevious.Integers; - if (integers.empty()) - integers.assign(Integers.size(), 0); - - for (auto i = 0u; i < Integers.size(); ++i) - { - if (Integers[i] != integers[i]) - { - changes |= (1ull << idx); - } - ++idx; - } - - auto floats = aPrevious.Floats; - if (floats.empty()) - floats.assign(Floats.size(), 0.f); - - for (auto i = 0u; i < Floats.size(); ++i) - { - if (Floats[i] != floats[i]) - { - changes |= (1ull << idx); - } - ++idx; - } - + const size_t sizeChangedVector = Booleans.size() + Integers.size() + Floats.size(); + auto changedVector = Booleans; + changedVector.reserve(sizeChangedVector); + + for (size_t i = 0; i < Integers.size(); i++) + changedVector.push_back(aPrevious.Integers.size() != Integers.size() || aPrevious.Integers[i] != Integers[i]); + for (size_t i = 0; i < Floats.size(); i++) + changedVector.push_back(aPrevious.Floats.size() != Floats.size() || aPrevious.Floats[i] != Floats[i]); + + // Now serialize: VarInts Booleans.size(), Integers.size(), Floats.size(), + // then the change table bits, then changed Integers, then changed Floats. + TiltedPhoques::Serialization::WriteVarInt(aWriter, Booleans.size()); TiltedPhoques::Serialization::WriteVarInt(aWriter, Integers.size()); TiltedPhoques::Serialization::WriteVarInt(aWriter, Floats.size()); - const auto cDiffBitCount = 1 + Integers.size() + Floats.size(); - - aWriter.WriteBits(changes, cDiffBitCount); - - idx = 0; - if (changes & (1ull << idx)) - { - aWriter.WriteBits(Booleans, 64); - } - ++idx; - - for (const auto value : Integers) - { - if (changes & (1ull << idx)) - { - TiltedPhoques::Serialization::WriteVarInt(aWriter, value & 0xFFFFFFFF); - } - ++idx; - } - - for (const auto value : Floats) - { - if (changes & (1ull << idx)) - { - aWriter.WriteBits(*reinterpret_cast(&value), 32); - } - ++idx; - } + TiltedPhoques::String chars; + VectorBool_to_String(changedVector, chars); + TiltedPhoques::Serialization::WriteString(aWriter, chars); + + auto biter = changedVector.begin() + Booleans.size(); + for (size_t i = 0; i < Integers.size(); i++) + if (*biter++) + TiltedPhoques::Serialization::WriteVarInt(aWriter, Integers[i]); + for (size_t i = 0; i < Floats.size(); i++) + if (*biter++) + TiltedPhoques::Serialization::WriteFloat(aWriter, Floats[i]); } +// Reads 3 VarInts that represent the size of the Booleans, Integers and Floats. +// That's followed by a bitstream in a string of the Booleans values combined +// with a Changed? truth table for Integers and Floats. +// The Changed? table is scanned and for each true bit, the corresponsing Integer +// or Float is deserialized. +// void AnimationVariables::ApplyDiff(TiltedPhoques::Buffer::Reader& aReader) { - const auto cIntegersSize = TiltedPhoques::Serialization::ReadVarInt(aReader); - if (cIntegersSize > 0xFF) - throw std::runtime_error("Too many integers received !"); - - if (Integers.size() != cIntegersSize) - { - Integers.assign(cIntegersSize, 0); - } - - const auto cFloatsSize = TiltedPhoques::Serialization::ReadVarInt(aReader); - if (cFloatsSize > 0xFF) - throw std::runtime_error("Too many floats received !"); - - if (Floats.size() != cFloatsSize) - { - Floats.assign(cFloatsSize, 0.f); - } - - const auto cDiffBitCount = 1 + Integers.size() + Floats.size(); - - uint64_t changes = 0; - uint32_t idx = 0; - - aReader.ReadBits(changes, cDiffBitCount); - - if (changes & (1ull << idx)) - { - aReader.ReadBits(Booleans, 64); - } - ++idx; - - for (auto& value : Integers) - { - if (changes & (1ull << idx)) - { - value = TiltedPhoques::Serialization::ReadVarInt(aReader) & 0xFFFFFFFF; - } - ++idx; - } - - for (auto& value : Floats) - { - if (changes & (1ull << idx)) - { - uint64_t tmp = 0; - aReader.ReadBits(tmp, 32); - uint32_t data = tmp & 0xFFFFFFFF; - value = *reinterpret_cast(&data); - } - ++idx; - } + size_t booleansSize = TiltedPhoques::Serialization::ReadVarInt(aReader); + size_t integersSize = TiltedPhoques::Serialization::ReadVarInt(aReader); + size_t floatsSize = TiltedPhoques::Serialization::ReadVarInt(aReader); + if (Integers.size() != integersSize) + Integers.assign(integersSize, 0); + if (Floats.size() != floatsSize) + Floats.assign(floatsSize, 0.f); + + TiltedPhoques::Vector changedVector(booleansSize + integersSize + floatsSize); + auto chars = TiltedPhoques::Serialization::ReadString(aReader); + String_to_VectorBool(chars, changedVector); + + Booleans.assign(changedVector.begin(), changedVector.begin() + booleansSize); + + auto biter = changedVector.begin() + booleansSize; + for (size_t i = 0; i < integersSize; i++) + if (*biter++) + Integers[i] = TiltedPhoques::Serialization::ReadVarInt(aReader); + for (size_t i = 0; i < floatsSize; i++) + if (*biter++) + Floats[i] = TiltedPhoques::Serialization::ReadFloat(aReader); } diff --git a/Code/encoding/Structs/AnimationVariables.h b/Code/encoding/Structs/AnimationVariables.h index 23ae912e5..331137139 100644 --- a/Code/encoding/Structs/AnimationVariables.h +++ b/Code/encoding/Structs/AnimationVariables.h @@ -6,7 +6,7 @@ using TiltedPhoques::Vector; struct AnimationVariables { - uint64_t Booleans{0}; + Vector Booleans{}; Vector Integers{}; Vector Floats{}; @@ -18,4 +18,6 @@ struct AnimationVariables void GenerateDiff(const AnimationVariables& aPrevious, TiltedPhoques::Buffer::Writer& aWriter) const; void ApplyDiff(TiltedPhoques::Buffer::Reader& aReader); + void VectorBool_to_String(const Vector& bools, TiltedPhoques::String& chars) const; + void String_to_VectorBool(const TiltedPhoques::String& chars, Vector& bools); }; diff --git a/Code/tests/encoding.cpp b/Code/tests/encoding.cpp index bd35f5160..ca09deb6b 100644 --- a/Code/tests/encoding.cpp +++ b/Code/tests/encoding.cpp @@ -276,7 +276,12 @@ TEST_CASE("Differential structures", "[encoding.differential]") GIVEN("AnimationVariables") { AnimationVariables vars, recvVars; - vars.Booleans = 0x12345678ull; + + vars.Booleans.resize(76); + String testString("\xDE\xAD\xBE\xEF" + "\xDE\xAD\xBE\xEF\x76\xB"); + vars.String_to_VectorBool(testString, vars.Booleans); + vars.Floats.push_back(1.f); vars.Floats.push_back(7.f); vars.Floats.push_back(12.f); @@ -305,7 +310,11 @@ TEST_CASE("Differential structures", "[encoding.differential]") REQUIRE(vars.Integers == recvVars.Integers); } - vars.Booleans = 0x9456123ull; + vars.Booleans.resize(33); + vars.Booleans[16] = false; + vars.Booleans[17] = false; + vars.Booleans[18] = false; + vars.Booleans[19] = false; vars.Floats[3] = 42.f; vars.Integers[0] = 18; vars.Integers[3] = 0; @@ -444,7 +453,10 @@ TEST_CASE("Packets", "[encoding.packets]") auto& move = update.UpdatedMovement; AnimationVariables vars; - vars.Booleans = 0x12345678ull; + vars.Booleans.resize(76); + String testString("\xDE\xAD\xBE\xEF\x76\xB"); + vars.String_to_VectorBool(testString, vars.Booleans); + vars.Floats.push_back(1.f); vars.Floats.push_back(7.f); vars.Floats.push_back(12.f); From d242b01be2fd4c0cbe3155cb139796d99aaca8b0 Mon Sep 17 00:00:00 2001 From: rfortier Date: Sun, 5 May 2024 15:19:56 -0400 Subject: [PATCH 27/86] A bit more space efficiency for negative integers. --- Code/encoding/Structs/AnimationVariables.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/encoding/Structs/AnimationVariables.cpp b/Code/encoding/Structs/AnimationVariables.cpp index b37d51bec..b968f4de1 100644 --- a/Code/encoding/Structs/AnimationVariables.cpp +++ b/Code/encoding/Structs/AnimationVariables.cpp @@ -96,7 +96,7 @@ void AnimationVariables::GenerateDiff(const AnimationVariables& aPrevious, Tilte auto biter = changedVector.begin() + Booleans.size(); for (size_t i = 0; i < Integers.size(); i++) if (*biter++) - TiltedPhoques::Serialization::WriteVarInt(aWriter, Integers[i]); + TiltedPhoques::Serialization::WriteVarInt(aWriter, Integers[i] & 0xFFFFFFFF); for (size_t i = 0; i < Floats.size(); i++) if (*biter++) TiltedPhoques::Serialization::WriteFloat(aWriter, Floats[i]); From 68bb27d1f8778900bc18bd495f1664386c05ee46 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 8 May 2024 14:00:45 -0400 Subject: [PATCH 28/86] Fixes a potential out-of-bounds reference to aVariables.Booleans now that it's a Vector; initial load-in animation variables might be empty. --- Code/client/Games/References.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/client/Games/References.cpp b/Code/client/Games/References.cpp index 477ea6189..e1096207b 100644 --- a/Code/client/Games/References.cpp +++ b/Code/client/Games/References.cpp @@ -360,7 +360,7 @@ void TESObjectREFR::LoadAnimationVariables(const AnimationVariables& aVariables) if (pVariableSet->size > idx) { - pVariableSet->data[idx] = aVariables.Booleans[i]; + pVariableSet->data[idx] = aVariables.Booleans.size() > i ? aVariables.Booleans[i] : false; } } From 253db37ae8ac0a252a44c95dd3cc205b804446b1 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 28 Jun 2023 20:37:35 +0200 Subject: [PATCH 29/86] Merge Spvvd's BehaviorVar.cpp and related changes.feat: manual hash replacer --- Code/client/ModCompat/BehaviorVar.cpp | 292 ++++++++++++++++++ Code/client/ModCompat/BehaviorVar.h | 26 ++ .../Services/Debug/Views/AnimDebugView.cpp | 5 + Code/client/World.cpp | 4 + .../AnimationGraphDescriptorManager.cpp | 25 ++ .../Structs/AnimationGraphDescriptorManager.h | 5 + 6 files changed, 357 insertions(+) create mode 100644 Code/client/ModCompat/BehaviorVar.cpp create mode 100644 Code/client/ModCompat/BehaviorVar.h diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp new file mode 100644 index 000000000..5edc00089 --- /dev/null +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -0,0 +1,292 @@ +#include + +#include + +#include +#include + +BehaviorVar* BehaviorVar::single = nullptr; + +BehaviorVar* BehaviorVar::Get() +{ + if (!BehaviorVar::single) + BehaviorVar::single = new BehaviorVar(); + return BehaviorVar::single; +} + +bool dirExists(std::string aPath) +{ + return std::filesystem::is_directory(aPath); +} + +std::vector loadDirs(const std::string& acPATH) +{ + std::vector result; + for (auto& p : std::filesystem::directory_iterator(acPATH)) + if (p.is_directory()) + result.push_back(p.path().string()); + return result; +} + +BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) +{ + // Enumerate all files in the directory and push bools, ints and floats + // to their respective vectors + + std::string hashFile; + std::vector floatVarsFile; + std::vector intVarsFile; + std::vector boolVarsFile; + + for (auto& p : std::filesystem::directory_iterator(aDir)) + { + std::string path = p.path().string(); + std::string base_filename = path.substr(path.find_last_of("/\\") + 1); + + spdlog::info("base_path: {}", base_filename); + + if (base_filename.find("__hash.txt") != std::string::npos) + { + hashFile = path; + + spdlog::info("name file: {}", hashFile); + } + else if (base_filename.find("__float.txt") != std::string::npos) + { + floatVarsFile.push_back(path); + + spdlog::info("float file: {}", path); + } + else if (base_filename.find("__int.txt") != std::string::npos) + { + intVarsFile.push_back(path); + + spdlog::info("int file: {}", path); + } + else if (base_filename.find("__bool.txt") != std::string::npos) + { + boolVarsFile.push_back(path); + + spdlog::info("bool file: {}", path); + } + } + + // Check that there is a hash replacer within the folder + if (hashFile == "") + return nullptr; + + // Prepare reading files + uint64_t orgHash; + uint64_t newHash; + std::set floatVar; + std::set intVar; + std::set boolVar; + + std::string tempString; // Temp string + + // Read the hash replacer file + std::ifstream file(hashFile); + getline(file, tempString); + file.close(); + + // split string to get replacer + size_t equalPos = tempString.find('=>'); + + if (equalPos != std::string::npos) + { + std::string orgHashStr = tempString.substr(0, equalPos); + std::string newHashStr = tempString.substr(equalPos + 1); + + if (orgHashStr == "" || newHashStr == "") + return nullptr; + + orgHash = std::strtoull(orgHashStr.c_str(), nullptr, 10); + newHash = std::strtoull(newHashStr.c_str(), nullptr, 10); + } + else + { + return nullptr; + } + + spdlog::info("Replacer found for {} => {}", orgHash, newHash); + + // Read float behavior variables + spdlog::info("reading float var"); + for (auto item : floatVarsFile) + { + std::ifstream file2(item); + while (std::getline(file2, tempString)) + { + floatVar.insert(tempString); + + spdlog::info(tempString); + } + file2.close(); + } + + // Read integer behavior variables + spdlog::info("reading int var"); + for (auto item : intVarsFile) + { + std::ifstream file3(item); + while (std::getline(file3, tempString)) + { + intVar.insert(tempString); + + spdlog::info(tempString); + } + file3.close(); + } + + // Read boolean behavior variables + spdlog::info("reading bool var"); + for (auto item : boolVarsFile) + { + std::ifstream file4(item); + while (std::getline(file4, tempString)) + { + boolVar.insert(tempString); + + spdlog::info(tempString); + } + file4.close(); + } + + // convert set to vector + std::vector floatVector; + std::vector intVector; + std::vector boolVector; + + for (auto item : floatVar) + { + floatVector.push_back(item); + } + + for (auto item : intVar) + { + intVector.push_back(item); + } + + for (auto item : boolVar) + { + boolVector.push_back(item); + } + + // create the sig + Replacer* result = new Replacer(); + + result->orgHash = orgHash; + result->newHash = newHash; + result->syncBooleanVar = boolVector; + result->syncFloatVar = floatVector; + result->syncIntegerVar = intVector; + + return result; +} + +void BehaviorVar::Init() +{ + // Check if the behaviors folder exists + const std::string behaviorPath = TiltedPhoques::GetPath().string() + "/behaviors"; + + if (!dirExists(behaviorPath)) + return; + + std::vector behaviorDirs = loadDirs(behaviorPath); + + for (auto dir : behaviorDirs) + { + Replacer* sig = loadReplacerFromDir(dir); + if (sig) + { + behaviorPool.push_back(*sig); + } + } + + // Replace loaded descriptors + BehaviorVar::ReplaceDescriptors(); +} + +void BehaviorVar::ReplaceDescriptors() +{ + // Replace all in pool + for (const auto& sig : behaviorPool) + { + spdlog::info("Replacing behavior hash {} with {}", sig.orgHash, sig.newHash); + + auto pDescriptor = AnimationGraphDescriptorManager::Get().GetDescriptor(sig.orgHash); + + if (pDescriptor == nullptr) + continue; + + // Remake the anim graph descriptor and insert new bools, floats, ints + TiltedPhoques::Vector boolVar; + TiltedPhoques::Vector floatVar; + TiltedPhoques::Vector intVar; + + for (auto var : pDescriptor->BooleanLookUpTable) + { + boolVar.push_back(var); + } + + for (auto var : pDescriptor->FloatLookupTable) + { + floatVar.push_back(var); + } + + for (auto var : pDescriptor->IntegerLookupTable) + { + intVar.push_back(var); + } + + // TODO: Insert new bools, floats, ints + + auto mDescriptor = new AnimationGraphDescriptor({0}, {0}, {0}); + mDescriptor->BooleanLookUpTable = boolVar; + mDescriptor->FloatLookupTable = floatVar; + mDescriptor->IntegerLookupTable= intVar; + + // Update the existing descriptor + AnimationGraphDescriptorManager::Get().Update(sig.orgHash, sig.newHash, *mDescriptor); + + //AnimationGraphDescriptorManager::Get().UpdateKey(sig.orgHash, sig.newHash); + } +} + +void BehaviorVar::Debug() +{ + auto descriptors = AnimationGraphDescriptorManager::Get().GetDescriptors(); + + // Descriptor hash dump + spdlog::info("Dumping descriptor hashes:"); + for (const auto& pair : descriptors) + { + spdlog::info("Hash: {}", pair.first); + } + + // Loaded behavior dump + spdlog::info("Dumping behavior sigs:"); + for (const auto& sig : behaviorPool) + { + spdlog::info("orgHash: {} => newHash: {}", sig.orgHash, sig.newHash); + + // bools + spdlog::info("bools:"); + for (const auto& var : sig.syncBooleanVar) + { + spdlog::info(var); + } + // bools + spdlog::info("floats:"); + for (const auto& var : sig.syncFloatVar) + { + spdlog::info(var); + } + // bools + spdlog::info("integers:"); + for (const auto& var : sig.syncIntegerVar) + { + spdlog::info(var); + } + } +} diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h new file mode 100644 index 000000000..8a25e1f97 --- /dev/null +++ b/Code/client/ModCompat/BehaviorVar.h @@ -0,0 +1,26 @@ +#pragma once + +struct BehaviorVar +{ + struct Replacer + { + uint64_t orgHash; + uint64_t newHash; + std::vector syncBooleanVar; + std::vector syncFloatVar; + std::vector syncIntegerVar; + }; + + static BehaviorVar* Get(); + + void Init(); + void ReplaceDescriptors(); + void Debug(); + + private: + static BehaviorVar* single; + + Replacer* loadReplacerFromDir(std::string aDir); + + std::vector behaviorPool; // Pool for loaded behaviours +}; diff --git a/Code/client/Services/Debug/Views/AnimDebugView.cpp b/Code/client/Services/Debug/Views/AnimDebugView.cpp index 801b3eb6c..2beeb9233 100644 --- a/Code/client/Services/Debug/Views/AnimDebugView.cpp +++ b/Code/client/Services/Debug/Views/AnimDebugView.cpp @@ -25,6 +25,8 @@ #include #include +#include + uint64_t DisplayGraphDescriptorKey(BSAnimationGraphManager* pManager) noexcept { auto hash = pManager->GetDescriptorKey(); @@ -81,7 +83,10 @@ void DebugService::DrawAnimDebugView() } if (ImGui::Button("Show cached hash")) + { spdlog::info("{}", pActor->GetExtension()->GraphDescriptorHash); + BehaviorVar::Get()->Debug(); + } if (ImGui::Button("Clear all")) { diff --git a/Code/client/World.cpp b/Code/client/World.cpp index f974efcab..3643973e7 100644 --- a/Code/client/World.cpp +++ b/Code/client/World.cpp @@ -25,6 +25,8 @@ #include #include +#include + World::World() : m_runner(m_dispatcher) , m_transport(*this, m_dispatcher) @@ -52,6 +54,8 @@ World::World() ctx().emplace(*this, m_transport, m_dispatcher); ctx().emplace(*this, m_transport, m_dispatcher); ctx().emplace(*this, m_dispatcher, m_transport); + + BehaviorVar::Get()->Init(); } World::~World() = default; diff --git a/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp b/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp index a037fb8a8..0d19fb448 100644 --- a/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp +++ b/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp @@ -16,6 +16,31 @@ const AnimationGraphDescriptor* AnimationGraphDescriptorManager::GetDescriptor(u return nullptr; } +const TiltedPhoques::Map AnimationGraphDescriptorManager::GetDescriptors() const noexcept +{ + return m_descriptors; +} + +void AnimationGraphDescriptorManager::UpdateKey(uint64_t aKey, uint64_t newKey) noexcept +{ + auto it = m_descriptors.find(aKey); + if (it != m_descriptors.end()) + { + m_descriptors[newKey] = it->second; + m_descriptors.erase(it); + } +} + +void AnimationGraphDescriptorManager::Update(uint64_t aKey, uint64_t newKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept +{ + const auto it = m_descriptors.find(aKey); + if (it != std::end(m_descriptors)) + { + m_descriptors.insert_or_assign(newKey, aAnimationGraphDescriptor); + m_descriptors.erase(it); + } +} + AnimationGraphDescriptorManager::Builder::Builder(AnimationGraphDescriptorManager& aManager, uint64_t aKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept { aManager.Register(aKey, std::move(aAnimationGraphDescriptor)); diff --git a/Code/encoding/Structs/AnimationGraphDescriptorManager.h b/Code/encoding/Structs/AnimationGraphDescriptorManager.h index 7f135a47f..3478a2658 100644 --- a/Code/encoding/Structs/AnimationGraphDescriptorManager.h +++ b/Code/encoding/Structs/AnimationGraphDescriptorManager.h @@ -9,6 +9,11 @@ struct AnimationGraphDescriptorManager static AnimationGraphDescriptorManager& Get() noexcept; const AnimationGraphDescriptor* GetDescriptor(uint64_t aKey) const noexcept; + + const TiltedPhoques::Map GetDescriptors() const noexcept; + void UpdateKey(uint64_t aKey, uint64_t newKey) noexcept; + void Update(uint64_t aKey, uint64_t newKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept; + struct Builder { Builder(AnimationGraphDescriptorManager& aManager, uint64_t aKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept; From 232e9ec5564d01c9238f8b72d9e2c3e4653b4e21 Mon Sep 17 00:00:00 2001 From: rfortier Date: Mon, 29 Jan 2024 17:06:48 -0500 Subject: [PATCH 30/86] Combine Spvvd's BehaviorVar improvements with Edho08's detection of modded behavior. We want to detect this at runtime (like Edho did) so we can merge the STR team's behavior vars with the modded behavior vars (and not require mods to know what the STR devs picked to sync). This will also give substantial version independence, where this feature should work with multiple versions of STR. --- Code/client/Games/References.cpp | 18 ++ Code/client/ModCompat/BehaviorVar.cpp | 299 +++++++++++++++++++------- Code/client/ModCompat/BehaviorVar.h | 8 + Code/client/World.cpp | 2 + 4 files changed, 252 insertions(+), 75 deletions(-) diff --git a/Code/client/Games/References.cpp b/Code/client/Games/References.cpp index e1096207b..3ca0a2d10 100644 --- a/Code/client/Games/References.cpp +++ b/Code/client/Games/References.cpp @@ -39,6 +39,8 @@ #include #include +std::mutex mutex_lock; + #if TP_SKYRIM64 #include #include @@ -219,6 +221,14 @@ void TESObjectREFR::SaveAnimationVariables(AnimationVariables& aVariables) const auto pDescriptor = AnimationGraphDescriptorManager::Get().GetDescriptor(pExtendedActor->GraphDescriptorHash); + // Modded behavior check if descriptor wasn't found + extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager * pManager, Actor * pActor); + if (!pDescriptor) + { + std::lock_guard guard(mutex_lock); + pDescriptor = BehaviorVarPatch(pManager, pActor); + } + if (!pDescriptor) return; @@ -338,6 +348,14 @@ void TESObjectREFR::LoadAnimationVariables(const AnimationVariables& aVariables) auto pDescriptor = AnimationGraphDescriptorManager::Get().GetDescriptor(pExtendedActor->GraphDescriptorHash); + // Modded behavior check if descriptor wasn't found + extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager * pManager, Actor * pActor); + if (!pDescriptor) + { + std::lock_guard guard(mutex_lock); + pDescriptor = BehaviorVarPatch(pManager, pActor); + } + if (!pDescriptor) return; diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 5edc00089..823ab26a7 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -1,12 +1,14 @@ -#include - -#include #include -#include +#include -BehaviorVar* BehaviorVar::single = nullptr; +#if 0 +#include +#endif + +#include +BehaviorVar* BehaviorVar::single = nullptr; BehaviorVar* BehaviorVar::Get() { if (!BehaviorVar::single) @@ -14,6 +16,140 @@ BehaviorVar* BehaviorVar::Get() return BehaviorVar::single; } +const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apManager, Actor* apActor) +{ + return BehaviorVar::Get()->Patch(apManager, apActor); +} + +const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apManager, Actor* apActor) +{ + // Make sure this isn't called so many times we need to filter out "never works" cases. + invocations++; + + // Check if the animation descriptor has already been built. + uint32_t hexFormID = apActor->formID; + auto pExtendedActor = apActor->GetExtension(); + auto hash = pExtendedActor->GraphDescriptorHash; + const AnimationGraphDescriptor* pGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(hash); + + // If we found the descriptor we're done. + if (pGraph) + return pGraph; + spdlog::info("Patch: actor with formID {:x} with hash of {} has modded behavior", hexFormID, hash); + + // Get all animation variables for this actor, then create a reversemap to go from strings to aniamation enum. + auto pDumpVar = apManager->DumpAnimationVariables(false); + std::map reversemap; + spdlog::info("Known behavior variables for formID {:x}:", hexFormID); + for (auto& item : pDumpVar) + { + spdlog::info("{}:{}", item.first, item.second); + reversemap.insert({static_cast(item.second), item.first}); + } + + // See if these animation variables include a signature variable for one of the replacers. + auto iter = behaviorPool.begin(); + for (; iter < behaviorPool.end(); iter++) + if (reversemap.find(iter->signatureVar) != reversemap.end()) + break; + if (iter >= behaviorPool.end()) + { + spdlog::info("No replacer found"); + return nullptr; + } + + spdlog::info("Found match, behavior replacer signature {}", iter->signatureVar); + + // Build the set of BehaviorVar strings as sets (not vectors) to eliminate dups + TiltedPhoques::Set boolVar; + TiltedPhoques::Set floatVar; + TiltedPhoques::Set intVar; + + // If we can find the original behavior that is being modded, + // get the descriptor and seed the behavior vars with it. + // That way mod developers only need to know what vars their + // mod adds, they don't have to know what the STR devs picked + + if (iter->orgHash) + { + const AnimationGraphDescriptor* pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(iter->orgHash); + if (pTmpGraph) + { + boolVar.insert(pTmpGraph->BooleanLookUpTable.begin(), pTmpGraph->BooleanLookUpTable.end()); + floatVar.insert(pTmpGraph->FloatLookupTable.begin(), pTmpGraph->FloatLookupTable.end()); + intVar.insert(pTmpGraph->IntegerLookupTable.begin(), pTmpGraph->IntegerLookupTable.end()); + spdlog::info("Original descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", + iter->orgHash, boolVar.size(), floatVar.size(), intVar.size()); + } + } + + bool found; + for (auto& item : iter->syncBooleanVar) + { + found = reversemap.find(item) != reversemap.end(); + if (!found) + spdlog::info("boolVar {} not found in reversemap", item); + else + { + spdlog::info("boolVar {}:{} found in reversemap", item, reversemap[item]); + if (boolVar.find(reversemap[item]) == boolVar.end()) + boolVar.insert(reversemap[item]); + else + spdlog::info("boolVar {} already in descriptor", item); + } + } + spdlog::info("Now have {} boolVar descriptors after searching {} BehavivorVar strings", boolVar.size(), iter->syncBooleanVar.size()); + + for (auto& item : iter->syncFloatVar) + { + found = reversemap.find(item) != reversemap.end(); + if (!found) + spdlog::info("floatVar {} not found in reversemap", item); + else + { + spdlog::info("floatVar {}:{} found in reversemap", item, reversemap[item]); + if (floatVar.find(reversemap[item]) == floatVar.end()) + floatVar.insert(reversemap[item]); + else + spdlog::info("floatVar {} already in descriptor", item); + } + } + spdlog::info("Now have {} floatVar descriptors after searching {} BehavivorVar strings", floatVar.size(), + iter->syncFloatVar.size()); + + for (auto& item : iter->syncIntegerVar) + { + found = reversemap.find(item) != reversemap.end(); + if (!found) + spdlog::info("intVar {} not found in reversemap", item); + else + { + spdlog::info("intVar {}:{} found in reversemap", item, reversemap[item]); + if (intVar.find(reversemap[item]) == intVar.end()) + intVar.insert(reversemap[item]); + else + spdlog::info("intVar {} already in descriptor", item); + } + } + spdlog::info("Now have {} intVar descriptors after searching {} BehaviorVar strings", intVar.size(), + iter->syncIntegerVar.size()); + + // Reshape the sets to vectors + TiltedPhoques::Vector boolVector(boolVar.begin(), boolVar.end()); + TiltedPhoques::Vector floatVector(floatVar.begin(), floatVar.end()); + TiltedPhoques::Vector intVector(intVar.begin(), intVar.end()); + + // Construct a new descriptor + auto panimGraphDescriptor = new AnimationGraphDescriptor(); + panimGraphDescriptor->BooleanLookUpTable = boolVector; + panimGraphDescriptor->FloatLookupTable = floatVector; + panimGraphDescriptor->IntegerLookupTable = intVector; + + // Add the new graph to the var graph + new AnimationGraphDescriptorManager::Builder(AnimationGraphDescriptorManager::Get(), hash, *panimGraphDescriptor); + return AnimationGraphDescriptorManager::Get().GetDescriptor(hash); +} + bool dirExists(std::string aPath) { return std::filesystem::is_directory(aPath); @@ -34,6 +170,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) // to their respective vectors std::string hashFile; + std::string signatureFile; std::vector floatVarsFile; std::vector intVarsFile; std::vector boolVarsFile; @@ -45,11 +182,17 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) spdlog::info("base_path: {}", base_filename); - if (base_filename.find("__hash.txt") != std::string::npos) + if (base_filename.find("__sig.txt") != std::string::npos) + { + signatureFile = path; + + spdlog::info("signature variable file: {}", signatureFile); + } + else if (base_filename.find("__hash.txt") != std::string::npos) { hashFile = path; - spdlog::info("name file: {}", hashFile); + spdlog::info("hash file: {}", hashFile); } else if (base_filename.find("__float.txt") != std::string::npos) { @@ -71,115 +214,112 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) } } - // Check that there is a hash replacer within the folder - if (hashFile == "") + // Check that there is a signature file (an identifying variable) + // When an Actor's animation descriptor isn't found, we search + // its animation/behavior varibles for this to match it to modded behavior + if (signatureFile == "") return nullptr; - // Prepare reading files +#if 0 uint64_t orgHash; uint64_t newHash; - std::set floatVar; - std::set intVar; - std::set boolVar; +#endif + // Prepare reading files + std::string sigVar; + std::vector floatVar; + std::vector intVar; + std::vector boolVar; std::string tempString; // Temp string - // Read the hash replacer file - std::ifstream file(hashFile); - getline(file, tempString); - file.close(); - - // split string to get replacer - size_t equalPos = tempString.find('=>'); - - if (equalPos != std::string::npos) - { - std::string orgHashStr = tempString.substr(0, equalPos); - std::string newHashStr = tempString.substr(equalPos + 1); - - if (orgHashStr == "" || newHashStr == "") - return nullptr; - - orgHash = std::strtoull(orgHashStr.c_str(), nullptr, 10); - newHash = std::strtoull(newHashStr.c_str(), nullptr, 10); - } - else - { + std::ifstream fileSig(signatureFile); + getline(fileSig, sigVar); // grab the signature variable + fileSig.close(); + erase_if(sigVar, isspace); // removes any inadvertant whitespace + if (sigVar.size() == 0) return nullptr; + spdlog::info("Replacer found signature variable {}", sigVar); + + // Check to see if there is a hash file. + // This is recommended, and shouild contain the ORIGINAL hash, + // before modding, of the behavior. It's not reasonable for a mod + // developer to have to "know" the complete set of variables the STR + // devs have selected, so we'll want to get them from the original behaviors + // via the original hash. If provided, we'll start with those vars and the + // mod developer only lists the added ones they need. + // + // The orginal version of this patch by Spvvd also included the "new" hash, + // but that seems to be another thing a mod dev has no easy way to get their hands + // on. So stripped off the need to provide the new hash, we'll just calculate it. + // + unsigned long long orgHash = 0; + if (hashFile.size()) + { + std::ifstream file(hashFile); + getline(file, tempString); + file.close(); + erase_if(tempString, isspace); // removes any inadvertant whitespace + orgHash = std::strtoull(tempString.c_str(), nullptr, 10); + spdlog::info("Replacer specifies original hash {} for {}", orgHash, sigVar); } - spdlog::info("Replacer found for {} => {}", orgHash, newHash); - + // Build lists of variables to sync // Read float behavior variables spdlog::info("reading float var"); for (auto item : floatVarsFile) { - std::ifstream file2(item); - while (std::getline(file2, tempString)) + std::ifstream file(item); + while (std::getline(file, tempString)) { - floatVar.insert(tempString); + floatVar.push_back(tempString); - spdlog::info(tempString); + spdlog::info(" " + tempString); } - file2.close(); + file.close(); } // Read integer behavior variables spdlog::info("reading int var"); for (auto item : intVarsFile) { - std::ifstream file3(item); - while (std::getline(file3, tempString)) + std::ifstream file(item); + while (std::getline(file, tempString)) { - intVar.insert(tempString); + intVar.push_back(tempString); - spdlog::info(tempString); + spdlog::info(" " + tempString); } - file3.close(); + file.close(); } // Read boolean behavior variables spdlog::info("reading bool var"); for (auto item : boolVarsFile) { - std::ifstream file4(item); - while (std::getline(file4, tempString)) + std::ifstream file(item); + while (std::getline(file, tempString)) { - boolVar.insert(tempString); + boolVar.push_back(tempString); - spdlog::info(tempString); + spdlog::info(" " + tempString); } - file4.close(); + file.close(); } - // convert set to vector - std::vector floatVector; - std::vector intVector; - std::vector boolVector; - - for (auto item : floatVar) - { - floatVector.push_back(item); - } - - for (auto item : intVar) - { - intVector.push_back(item); - } - - for (auto item : boolVar) - { - boolVector.push_back(item); - } // create the sig Replacer* result = new Replacer(); + #if 0 + // This should become dead + //result->newHash = newHash; +#endif + result->orgHash = orgHash; - result->newHash = newHash; - result->syncBooleanVar = boolVector; - result->syncFloatVar = floatVector; - result->syncIntegerVar = intVector; + result->signatureVar = sigVar; + result->syncBooleanVar = boolVar; + result->syncFloatVar = floatVar; + result->syncIntegerVar = intVar; return result; } @@ -204,7 +344,7 @@ void BehaviorVar::Init() } // Replace loaded descriptors - BehaviorVar::ReplaceDescriptors(); + // BehaviorVar::ReplaceDescriptors(); } void BehaviorVar::ReplaceDescriptors() @@ -240,6 +380,15 @@ void BehaviorVar::ReplaceDescriptors() } // TODO: Insert new bools, floats, ints +#if 0 + const AnimationGraphDescriptor* pGraph = + AnimationGraphDescriptorManager::Get().GetDescriptor(sig.orgHash); + + BSAnimationGraphManager* apManager; + IAnimationGraphManagerHolder::GetBSAnimationGraph(&apManager); + auto dumpVar = apManager->DumpAnimationVariables(true); + //std::unordered_map reverseMap; +#endif auto mDescriptor = new AnimationGraphDescriptor({0}, {0}, {0}); mDescriptor->BooleanLookUpTable = boolVar; diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index 8a25e1f97..992dc26e2 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -1,17 +1,22 @@ #pragma once +#include + struct BehaviorVar { struct Replacer { uint64_t orgHash; uint64_t newHash; + std::string signatureVar; std::vector syncBooleanVar; std::vector syncFloatVar; std::vector syncIntegerVar; }; static BehaviorVar* Get(); + const AnimationGraphDescriptor* Patch(BSAnimationGraphManager* apManager, Actor* apActor); + void ReplaceDescriptor(BSAnimationGraphManager* apManager, Actor* apActor); void Init(); void ReplaceDescriptors(); @@ -19,8 +24,11 @@ struct BehaviorVar private: static BehaviorVar* single; + uint64_t invocations = 0; Replacer* loadReplacerFromDir(std::string aDir); std::vector behaviorPool; // Pool for loaded behaviours }; + +extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apManager, Actor* apActor); diff --git a/Code/client/World.cpp b/Code/client/World.cpp index 3643973e7..484c35e16 100644 --- a/Code/client/World.cpp +++ b/Code/client/World.cpp @@ -25,6 +25,7 @@ #include #include +// MOD BEHAVIORS: add modded behaviors #include World::World() @@ -56,6 +57,7 @@ World::World() ctx().emplace(*this, m_dispatcher, m_transport); BehaviorVar::Get()->Init(); + // MOD BEHAVIORS: add modded behaviors } World::~World() = default; From c71369815ac95e79ccab47d00215901169551498 Mon Sep 17 00:00:00 2001 From: Spvvd Date: Tue, 21 Mar 2023 22:20:22 +0100 Subject: [PATCH 31/86] Update README.md with credits. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index f9a84df33..40d16bab0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ +# Tilted Online Nemesis + +The first couple of commits on the fork are to retain the work of Edho08 and Spvvd and give appropriate credit to them for their initial efforts to support animation mods with Skyrim Together Reborn. +Subsequent commits are the efforts of rfortier (Ujave on Discord) and MostExcellent / MagicWizardMan. + +Sometimes animations still don't sync, restarting game+server or rerunning Nemesis and syncing the output with your friends can fix it in most cases. + +Works only with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR! + # Tilted Online ![Build status](https://github.com/tiltedphoques/TiltedEvolution/workflows/Build%20windows/badge.svg?branch=master) [![Build linux](https://github.com/tiltedphoques/TiltedEvolution/actions/workflows/linux.yml/badge.svg)](https://github.com/tiltedphoques/TiltedEvolution/actions/workflows/linux.yml) [![Discord](https://img.shields.io/discord/247835175860305931.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/skyrimtogether) From 4ee920cbd4025d362bc91b1ec543744de0374d1b Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 31 Jan 2024 18:06:33 -0500 Subject: [PATCH 32/86] Support full conditional compile of MODDED_BEHAVIOR_COMPATIBILITY Solve player 1st person woes Lighten intrusion into STR main body (References.cpp) Fixed sorting of AnimationGraphDescriptor behavior variables, this will help when Pandora is more widely adopted (and stops reordering behavior variables, maybe we can get to mod order independence). Added failList of modded behavior lookups that fail, so we don't repeat expensive failed calls. Even some built-in ones can fail, like wisps. Deleted dead code, marked some I'm not sure about for deletion. Update README.md with a decent description of the content and goals of the fork. Cleanups, comments about how it works. --- Code/client/Games/References.cpp | 16 +- Code/client/ModCompat/BehaviorVar.cpp | 331 ++++++++++-------- Code/client/ModCompat/BehaviorVar.h | 9 +- .../Services/Debug/Views/AnimDebugView.cpp | 8 +- Code/client/World.cpp | 8 +- Code/client/xmake.lua | 1 + .../AnimationGraphDescriptorManager.cpp | 10 + README.md | 18 +- 8 files changed, 232 insertions(+), 169 deletions(-) diff --git a/Code/client/Games/References.cpp b/Code/client/Games/References.cpp index 3ca0a2d10..3bbbf8a1c 100644 --- a/Code/client/Games/References.cpp +++ b/Code/client/Games/References.cpp @@ -39,7 +39,6 @@ #include #include -std::mutex mutex_lock; #if TP_SKYRIM64 #include @@ -51,6 +50,10 @@ std::mutex mutex_lock; #include #endif +#ifdef MODDED_BEHAVIOR_COMPATIBILITY +extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* pManager, Actor* pActor); +#endif MODDED_BEHAVIOR_COMPATIBILITY + using ScopedReferencesOverride = ScopedOverride; thread_local uint32_t ScopedReferencesOverride::s_refCount = 0; @@ -221,13 +224,12 @@ void TESObjectREFR::SaveAnimationVariables(AnimationVariables& aVariables) const auto pDescriptor = AnimationGraphDescriptorManager::Get().GetDescriptor(pExtendedActor->GraphDescriptorHash); +#ifdef MODDED_BEHAVIOR_COMPATIBILITY // Modded behavior check if descriptor wasn't found extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager * pManager, Actor * pActor); if (!pDescriptor) - { - std::lock_guard guard(mutex_lock); pDescriptor = BehaviorVarPatch(pManager, pActor); - } +#endif MODDED_BEHAVIOR_COMPATIBILITY if (!pDescriptor) return; @@ -348,13 +350,11 @@ void TESObjectREFR::LoadAnimationVariables(const AnimationVariables& aVariables) auto pDescriptor = AnimationGraphDescriptorManager::Get().GetDescriptor(pExtendedActor->GraphDescriptorHash); +#ifdef MODDED_BEHAVIOR_COMPATIBILITY // Modded behavior check if descriptor wasn't found - extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager * pManager, Actor * pActor); if (!pDescriptor) - { - std::lock_guard guard(mutex_lock); pDescriptor = BehaviorVarPatch(pManager, pActor); - } +#endif MODDED_BEHAVIOR_COMPATIBILITY if (!pDescriptor) return; diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 823ab26a7..0c38cb3ea 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -1,12 +1,23 @@ +#ifdef MODDED_BEHAVIOR_COMPATIBILITY + #include #include +#include -#if 0 -#include +#if TP_SKYRIM64 +#include +#include // Camera 1st person is only in Skyrim? +#include #endif -#include +#include +std::mutex mutex_lock; + +// How long we failList a behavior hash that can't be translated. +// See explanation in BehaviorVar::Patch +using namespace std::literals; +const std::chrono::steady_clock::duration FAILLIST_DURATION(5min); BehaviorVar* BehaviorVar::single = nullptr; BehaviorVar* BehaviorVar::Get() @@ -16,6 +27,8 @@ BehaviorVar* BehaviorVar::Get() return BehaviorVar::single; } +// A simple function can be declared, caller file doesn't have to include our +// class/struct header. const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apManager, Actor* apActor) { return BehaviorVar::Get()->Patch(apManager, apActor); @@ -23,27 +36,62 @@ const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apMana const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apManager, Actor* apActor) { - // Make sure this isn't called so many times we need to filter out "never works" cases. - invocations++; - + // Serialize, Actors are multi-threaded. Might not be strictly necessary, I think we're on + // the main game loop, but if so it won't hurt anything. + std::lock_guard guard(mutex_lock); + // Check if the animation descriptor has already been built. uint32_t hexFormID = apActor->formID; auto pExtendedActor = apActor->GetExtension(); auto hash = pExtendedActor->GraphDescriptorHash; const AnimationGraphDescriptor* pGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(hash); +#if TP_SKYRIM64 + // If it is the player-character AND they are in 1st person, we don't have the data to mod them; + // Used the base game animation graphs until a Master Behavior actor enters the room. Could be an NPC, + // but will always happen no later than when the 2nd person joins the server and room. + // Remote players are ALWAYS in 3rd person by definition + if (hexFormID == 0x14 && PlayerCamera::Get()->IsFirstPerson()) + { + hash = AnimationGraphDescriptor_Master_Behavior::m_key; + pGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(hash); + } +#endif + // If we found the descriptor we're done. if (pGraph) return pGraph; - spdlog::info("Patch: actor with formID {:x} with hash of {} has modded behavior", hexFormID, hash); + + // If BehaviorVar replacement fails, the hash is failListed for a period of time. + // This handles a number of special cases for us. Many behaviors are not synced; the + // game just ignores them and let's the multiple clients each handle it. + // Examples are the "Root" behavior (not synced as a behavior, but handled), + // or any number of lower-priority actors such as Wisps (location is always synced, + // but otherwise behavior sync not needed). + // + // FailListed for minutes to avoid performance hit of constantly checking for + // modded behavior. Only failListed for minutes to occasionally get log messages + // so we can think about fixing it. Or the case of dynamic behavior and behavior + // signature changes that might work later (yes, mods like that exist) + if (failListed(hash)) + return nullptr; + + // Up to here the routine is pretty cheap, and WILL be called a bunch of times + // if the only humanoid Actor is the Dragonborn/player in 1st person. + // With that case filtered out, keep a counter to see if we need to defend against other + // cases (like a modded behavior where we CAN't find the signature var). + if (invocations++ == 100) + spdlog::warn("BehaviorVar::Patch: warning, more than 100 invocations, investigate why"); + + spdlog::info("BehaviorVar::Patch: actor with formID {:x} with hash of {} has modded behavior", hexFormID, hash); // Get all animation variables for this actor, then create a reversemap to go from strings to aniamation enum. auto pDumpVar = apManager->DumpAnimationVariables(false); std::map reversemap; - spdlog::info("Known behavior variables for formID {:x}:", hexFormID); + spdlog::debug("Known behavior variables for formID {:x}:", hexFormID); for (auto& item : pDumpVar) { - spdlog::info("{}:{}", item.first, item.second); + spdlog::debug(" {}:{}", item.first, item.second); reversemap.insert({static_cast(item.second), item.first}); } @@ -54,102 +102,135 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa break; if (iter >= behaviorPool.end()) { - spdlog::info("No replacer found"); + spdlog::warn("No replacer found for behavior hash {:x} (found on formID {:x}), adding to fail list", hash, hexFormID); + failList(hash); return nullptr; } - spdlog::info("Found match, behavior replacer signature {}", iter->signatureVar); // Build the set of BehaviorVar strings as sets (not vectors) to eliminate dups - TiltedPhoques::Set boolVar; - TiltedPhoques::Set floatVar; - TiltedPhoques::Set intVar; + // Also, we want the set sorted, to make sure we get the same hash if mods + // end up rearranging order, so these have to be std::set s. TiltedPhoques::Set + // uses a hash map instead of a sorted tree, and I don't want to have to figure + // out how to override that. + std::set boolVar; + std::set floatVar; + std::set intVar; // If we can find the original behavior that is being modded, // get the descriptor and seed the behavior vars with it. // That way mod developers only need to know what vars their // mod adds, they don't have to know what the STR devs picked - - if (iter->orgHash) + const AnimationGraphDescriptor* pTmpGraph = nullptr; + if (iter->orgHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(iter->orgHash))) { - const AnimationGraphDescriptor* pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(iter->orgHash); - if (pTmpGraph) - { - boolVar.insert(pTmpGraph->BooleanLookUpTable.begin(), pTmpGraph->BooleanLookUpTable.end()); - floatVar.insert(pTmpGraph->FloatLookupTable.begin(), pTmpGraph->FloatLookupTable.end()); - intVar.insert(pTmpGraph->IntegerLookupTable.begin(), pTmpGraph->IntegerLookupTable.end()); - spdlog::info("Original descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", - iter->orgHash, boolVar.size(), floatVar.size(), intVar.size()); - } + boolVar.insert(pTmpGraph->BooleanLookUpTable.begin(), pTmpGraph->BooleanLookUpTable.end()); + floatVar.insert(pTmpGraph->FloatLookupTable.begin(), pTmpGraph->FloatLookupTable.end()); + intVar.insert(pTmpGraph->IntegerLookupTable.begin(), pTmpGraph->IntegerLookupTable.end()); + spdlog::info("Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", + iter->orgHash, boolVar.size(), floatVar.size(), intVar.size()); } - bool found; + // Check requested behavior vars for those that ARE legit + // behavior vars for this Actor AND are not yet synced + int foundCount = 0; for (auto& item : iter->syncBooleanVar) { - found = reversemap.find(item) != reversemap.end(); - if (!found) - spdlog::info("boolVar {} not found in reversemap", item); - else + bool found = reversemap.find(item) != reversemap.end(); + if (found && boolVar.find(reversemap[item]) == boolVar.end()) { - spdlog::info("boolVar {}:{} found in reversemap", item, reversemap[item]); - if (boolVar.find(reversemap[item]) == boolVar.end()) - boolVar.insert(reversemap[item]); - else - spdlog::info("boolVar {} already in descriptor", item); + if (foundCount++ == 0) + spdlog::info("Boolean variables added to sync:"); + boolVar.insert(reversemap[item]); + spdlog::info(" {}", item); } + } - spdlog::info("Now have {} boolVar descriptors after searching {} BehavivorVar strings", boolVar.size(), iter->syncBooleanVar.size()); + if (foundCount) + spdlog::info("Now have {} boolVar descriptors after searching {} BehavivorVar strings", boolVar.size(), iter->syncBooleanVar.size()); - for (auto& item : iter->syncFloatVar) + foundCount = 0; + for (auto& item : iter->syncFloatVar) { - found = reversemap.find(item) != reversemap.end(); - if (!found) - spdlog::info("floatVar {} not found in reversemap", item); - else + bool found = reversemap.find(item) != reversemap.end(); + if (found && floatVar.find(reversemap[item]) == floatVar.end()) { - spdlog::info("floatVar {}:{} found in reversemap", item, reversemap[item]); - if (floatVar.find(reversemap[item]) == floatVar.end()) - floatVar.insert(reversemap[item]); - else - spdlog::info("floatVar {} already in descriptor", item); + if (foundCount++ == 0) + spdlog::info("Float variables added to sync:"); + floatVar.insert(reversemap[item]); + spdlog::info(" {}", item); } - } - spdlog::info("Now have {} floatVar descriptors after searching {} BehavivorVar strings", floatVar.size(), - iter->syncFloatVar.size()); - - for (auto& item : iter->syncIntegerVar) - { - found = reversemap.find(item) != reversemap.end(); - if (!found) - spdlog::info("intVar {} not found in reversemap", item); - else + } + if (foundCount) + spdlog::info("Now have {} floatVar descriptors after searching {} BehavivorVar strings", floatVar.size(), iter->syncFloatVar.size()); + + foundCount = 0; + for (auto& item : iter->syncIntegerVar) + { + bool found = reversemap.find(item) != reversemap.end(); + if (found && intVar.find(reversemap[item]) == intVar.end()) { - spdlog::info("intVar {}:{} found in reversemap", item, reversemap[item]); - if (intVar.find(reversemap[item]) == intVar.end()) - intVar.insert(reversemap[item]); - else - spdlog::info("intVar {} already in descriptor", item); + if (foundCount++ == 0) + spdlog::info("Int variables added to sync:"); + intVar.insert(reversemap[item]); + spdlog::info(" {}", item); } - } - spdlog::info("Now have {} intVar descriptors after searching {} BehaviorVar strings", intVar.size(), - iter->syncIntegerVar.size()); - - // Reshape the sets to vectors + } + if (foundCount) + spdlog::info("Now have {} intVar descriptors after searching {} BehavivorVar strings", intVar.size(), iter->syncIntegerVar.size()); + + // Ensure we aren't over the limits. If we are, we won't update + // the animation. Performance will be terrible unless we kill some of the logging + // or keep track of failed signatures. + std::string msgString; + if (boolVar.size() > 64) + msgString = "boolean"; + + else if ((floatVar.size() + intVar.size()) > 64) + msgString = "float+integer"; + + if (msgString.size() > 0) + { + spdlog::error("Too many {} behavior vars to sync for actor, max is 64.", msgString); + spdlog::error("Actor with formID {:x}, signature {}, original hash {} cannot be synced", + hexFormID, iter->orgHash, iter->signatureVar); + spdlog::error("Fail listing behavior hash {:x} found on formID {:x}", hash, hexFormID); + failList(hash); + return nullptr; + } + + // Reshape the (sorted, unique) sets to vectors TiltedPhoques::Vector boolVector(boolVar.begin(), boolVar.end()); TiltedPhoques::Vector floatVector(floatVar.begin(), floatVar.end()); TiltedPhoques::Vector intVector(intVar.begin(), intVar.end()); // Construct a new descriptor auto panimGraphDescriptor = new AnimationGraphDescriptor(); + + // This is a bit grubby, but it IS a struct with public members. + // Maybe the devs will help us out by agreeing to an additional constructor. panimGraphDescriptor->BooleanLookUpTable = boolVector; panimGraphDescriptor->FloatLookupTable = floatVector; panimGraphDescriptor->IntegerLookupTable = intVector; - // Add the new graph to the var graph + // Add the new graph to the known behavior graphs new AnimationGraphDescriptorManager::Builder(AnimationGraphDescriptorManager::Get(), hash, *panimGraphDescriptor); return AnimationGraphDescriptorManager::Get().GetDescriptor(hash); } +// Check if the behavior hash is on the failed liist +boolean BehaviorVar::failListed(uint64_t hash) +{ + auto iter = failedBehaviors.find(hash); + return iter != failedBehaviors.end() && std::chrono::steady_clock::now() < iter->second; +} + +//Place the behavior hash on the failed list +void BehaviorVar::failList(uint64_t hash) +{ + failedBehaviors.insert_or_assign(hash, std::chrono::steady_clock::now() + FAILLIST_DURATION); +} + bool dirExists(std::string aPath) { return std::filesystem::is_directory(aPath); @@ -169,6 +250,16 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) // Enumerate all files in the directory and push bools, ints and floats // to their respective vectors + // The hashFile *__hash.txt file should contain the hashed signature of the ORIGINAL GAME + // actor. That enables us to look up the synced animation variables selected by + // the STR devs and include them in the updated behavior/animation sync. Mod + // devs don't have to know anything but what they've added, and this support for + // Nemesis will work with more versions of the game. + // + // The signatureFile *__sig.txt should contain the name of a uniquely named variable for the + // modded actor, that we can use to connect the actor to their modded behavior variables. + // It's not actually sync'ed, just there so we can find the match. For example, currently + // bSTRMaster is used for humanoid/Player actors, and bSTRDragon for dragon behavior. std::string hashFile; std::string signatureFile; std::vector floatVarsFile; @@ -180,56 +271,52 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) std::string path = p.path().string(); std::string base_filename = path.substr(path.find_last_of("/\\") + 1); - spdlog::info("base_path: {}", base_filename); + spdlog::debug("base_path: {}", base_filename); if (base_filename.find("__sig.txt") != std::string::npos) { signatureFile = path; - spdlog::info("signature variable file: {}", signatureFile); + spdlog::debug("signature variable file: {}", signatureFile); } else if (base_filename.find("__hash.txt") != std::string::npos) { hashFile = path; - spdlog::info("hash file: {}", hashFile); + spdlog::debug("hash file: {}", hashFile); } else if (base_filename.find("__float.txt") != std::string::npos) { floatVarsFile.push_back(path); - spdlog::info("float file: {}", path); + spdlog::debug("float file: {}", path); } else if (base_filename.find("__int.txt") != std::string::npos) { intVarsFile.push_back(path); - spdlog::info("int file: {}", path); + spdlog::debug("int file: {}", path); } else if (base_filename.find("__bool.txt") != std::string::npos) { boolVarsFile.push_back(path); - spdlog::info("bool file: {}", path); + spdlog::debug("bool file: {}", path); } } // Check that there is a signature file (an identifying variable) - // When an Actor's animation descriptor isn't found, we search - // its animation/behavior varibles for this to match it to modded behavior + // When an Actor's behavior is modified, it's animation signature doesn't match + // any of the base STR built-in descriptors. We try to match up on a distinguishing + // animation variable added by the animation. But without such a distinquishing if (signatureFile == "") return nullptr; -#if 0 - uint64_t orgHash; - uint64_t newHash; -#endif // Prepare reading files std::string sigVar; std::vector floatVar; std::vector intVar; std::vector boolVar; - std::string tempString; // Temp string std::ifstream fileSig(signatureFile); @@ -238,7 +325,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) erase_if(sigVar, isspace); // removes any inadvertant whitespace if (sigVar.size() == 0) return nullptr; - spdlog::info("Replacer found signature variable {}", sigVar); + spdlog::info("BehaviorVar::loadReplacerFromDir found signature variable {}", sigVar); // Check to see if there is a hash file. // This is recommended, and shouild contain the ORIGINAL hash, @@ -252,7 +339,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) // but that seems to be another thing a mod dev has no easy way to get their hands // on. So stripped off the need to provide the new hash, we'll just calculate it. // - unsigned long long orgHash = 0; + uint64_t orgHash = 0; if (hashFile.size()) { std::ifstream file(hashFile); @@ -265,7 +352,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) // Build lists of variables to sync // Read float behavior variables - spdlog::info("reading float var"); + spdlog::debug("reading float var"); for (auto item : floatVarsFile) { std::ifstream file(item); @@ -273,13 +360,13 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) { floatVar.push_back(tempString); - spdlog::info(" " + tempString); + spdlog::debug(" " + tempString); } file.close(); } // Read integer behavior variables - spdlog::info("reading int var"); + spdlog::debug("reading int vars"); for (auto item : intVarsFile) { std::ifstream file(item); @@ -287,13 +374,13 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) { intVar.push_back(tempString); - spdlog::info(" " + tempString); + spdlog::debug(" " + tempString); } file.close(); } // Read boolean behavior variables - spdlog::info("reading bool var"); + spdlog::debug("reading bool vars"); for (auto item : boolVarsFile) { std::ifstream file(item); @@ -301,20 +388,14 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) { boolVar.push_back(tempString); - spdlog::info(" " + tempString); + spdlog::debug(" " + tempString); } file.close(); } - - // create the sig + // Create the replacer Replacer* result = new Replacer(); - #if 0 - // This should become dead - //result->newHash = newHash; -#endif - result->orgHash = orgHash; result->signatureVar = sigVar; result->syncBooleanVar = boolVar; @@ -342,64 +423,6 @@ void BehaviorVar::Init() behaviorPool.push_back(*sig); } } - - // Replace loaded descriptors - // BehaviorVar::ReplaceDescriptors(); -} - -void BehaviorVar::ReplaceDescriptors() -{ - // Replace all in pool - for (const auto& sig : behaviorPool) - { - spdlog::info("Replacing behavior hash {} with {}", sig.orgHash, sig.newHash); - - auto pDescriptor = AnimationGraphDescriptorManager::Get().GetDescriptor(sig.orgHash); - - if (pDescriptor == nullptr) - continue; - - // Remake the anim graph descriptor and insert new bools, floats, ints - TiltedPhoques::Vector boolVar; - TiltedPhoques::Vector floatVar; - TiltedPhoques::Vector intVar; - - for (auto var : pDescriptor->BooleanLookUpTable) - { - boolVar.push_back(var); - } - - for (auto var : pDescriptor->FloatLookupTable) - { - floatVar.push_back(var); - } - - for (auto var : pDescriptor->IntegerLookupTable) - { - intVar.push_back(var); - } - - // TODO: Insert new bools, floats, ints -#if 0 - const AnimationGraphDescriptor* pGraph = - AnimationGraphDescriptorManager::Get().GetDescriptor(sig.orgHash); - - BSAnimationGraphManager* apManager; - IAnimationGraphManagerHolder::GetBSAnimationGraph(&apManager); - auto dumpVar = apManager->DumpAnimationVariables(true); - //std::unordered_map reverseMap; -#endif - - auto mDescriptor = new AnimationGraphDescriptor({0}, {0}, {0}); - mDescriptor->BooleanLookUpTable = boolVar; - mDescriptor->FloatLookupTable = floatVar; - mDescriptor->IntegerLookupTable= intVar; - - // Update the existing descriptor - AnimationGraphDescriptorManager::Get().Update(sig.orgHash, sig.newHash, *mDescriptor); - - //AnimationGraphDescriptorManager::Get().UpdateKey(sig.orgHash, sig.newHash); - } } void BehaviorVar::Debug() @@ -439,3 +462,5 @@ void BehaviorVar::Debug() } } } + +#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index 992dc26e2..573f83b4f 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -1,4 +1,5 @@ #pragma once +#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include @@ -16,10 +17,10 @@ struct BehaviorVar static BehaviorVar* Get(); const AnimationGraphDescriptor* Patch(BSAnimationGraphManager* apManager, Actor* apActor); - void ReplaceDescriptor(BSAnimationGraphManager* apManager, Actor* apActor); + boolean failListed(uint64_t hash); + void failList(uint64_t hash); void Init(); - void ReplaceDescriptors(); void Debug(); private: @@ -29,6 +30,10 @@ struct BehaviorVar Replacer* loadReplacerFromDir(std::string aDir); std::vector behaviorPool; // Pool for loaded behaviours + std::map failedBehaviors; }; extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apManager, Actor* apActor); + + +#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/Services/Debug/Views/AnimDebugView.cpp b/Code/client/Services/Debug/Views/AnimDebugView.cpp index 2beeb9233..04315c16b 100644 --- a/Code/client/Services/Debug/Views/AnimDebugView.cpp +++ b/Code/client/Services/Debug/Views/AnimDebugView.cpp @@ -25,7 +25,9 @@ #include #include +#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include +#endif MODDED_BEHAVIOR_COMPATIBILITY uint64_t DisplayGraphDescriptorKey(BSAnimationGraphManager* pManager) noexcept { @@ -82,11 +84,13 @@ void DebugService::DrawAnimDebugView() return; } - if (ImGui::Button("Show cached hash")) + if (ImGui::Button("Show cached hash")) { spdlog::info("{}", pActor->GetExtension()->GraphDescriptorHash); +#ifdef MODDED_BEHAVIOR_COMPATIBILITY BehaviorVar::Get()->Debug(); - } +#endif MODDED_BEHAVIOR_COMPATIBILITY + } if (ImGui::Button("Clear all")) { diff --git a/Code/client/World.cpp b/Code/client/World.cpp index 484c35e16..b9f70f77a 100644 --- a/Code/client/World.cpp +++ b/Code/client/World.cpp @@ -25,8 +25,9 @@ #include #include -// MOD BEHAVIORS: add modded behaviors -#include +#ifdef MODDED_BEHAVIOR_COMPATIBILITY +#include +#endif MODDED_BEHAVIOR_COMPATIBILITY World::World() : m_runner(m_dispatcher) @@ -56,8 +57,9 @@ World::World() ctx().emplace(*this, m_transport, m_dispatcher); ctx().emplace(*this, m_dispatcher, m_transport); +#ifdef MODDED_BEHAVIOR_COMPATIBILITY BehaviorVar::Get()->Init(); - // MOD BEHAVIORS: add modded behaviors +#endif MODDED_BEHAVIOR_COMPATIBILITY } World::~World() = default; diff --git a/Code/client/xmake.lua b/Code/client/xmake.lua index 9c2028ef0..88a4a6ee6 100644 --- a/Code/client/xmake.lua +++ b/Code/client/xmake.lua @@ -4,6 +4,7 @@ target(name) set_kind("static") set_group("Client") add_defines(def) + add_includedirs(".") set_pcxxheader("TiltedOnlinePCH.h") diff --git a/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp b/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp index 0d19fb448..7ce38522f 100644 --- a/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp +++ b/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp @@ -21,6 +21,7 @@ const TiltedPhoques::Map AnimationGraphDescr return m_descriptors; } +#ifdef MODDED_BEHAVIOR_KEEP_UNUSED void AnimationGraphDescriptorManager::UpdateKey(uint64_t aKey, uint64_t newKey) noexcept { auto it = m_descriptors.find(aKey); @@ -40,6 +41,7 @@ void AnimationGraphDescriptorManager::Update(uint64_t aKey, uint64_t newKey, Ani m_descriptors.erase(it); } } +#endif AnimationGraphDescriptorManager::Builder::Builder(AnimationGraphDescriptorManager& aManager, uint64_t aKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept { @@ -53,3 +55,11 @@ void AnimationGraphDescriptorManager::Register(uint64_t aKey, AnimationGraphDesc m_descriptors[aKey] = std::move(aAnimationGraphDescriptor); } + +#ifdef MODDED_BEHAVIOR_KEEP_UNUSED +void AnimationGraphDescriptorManager::ReRegister(uint64_t aKey, + AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept +{ + m_descriptors[aKey] = std::move(aAnimationGraphDescriptor); +} +#endif diff --git a/README.md b/README.md index 40d16bab0..a3fed5486 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,23 @@ Subsequent commits are the efforts of rfortier (Ujave on Discord) and MostExcell Sometimes animations still don't sync, restarting game+server or rerunning Nemesis and syncing the output with your friends can fix it in most cases. -Works only with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR! +Works only with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR. It might work with the latest Skyrim and the correct address library, but it has barely been tested. +And the STR team has not released 1.6 yet. + +This is a continuation of Edho08's original work, later updated by Spvvd and Ragley. This version by RFortier and MostExcellent addeds these goals: +* Pure feature branch to make it easily rebaseable. +* Minimal intrusion in the base code. +* Feature is conditionally compiled. Enabled by a single commit in this history which will show the one line to change to turn it off. +* Tries to remove as much of the complexity for modders as possible. To mod a behavior you don't need to know any your new hash of your modded behavior, the game calculates them. +* It's to your advantage to know the _original game behavior hash_ you are moddifying, though; if you do, you only need to list the behavior variables your mod needs, +the rest that the game devs selected will be picked up automatically for you. This helps give your mod STR version-independence, and more importantly means combining +your mod with others will work. + +# TODO +* Currently, BehaviorVar.cpp works, but it's blobby; when I get some time I'll simplify it. +* Build up the fomod for a proper mod installer again, and document the simplified behaviorvar support. + + # Tilted Online ![Build status](https://github.com/tiltedphoques/TiltedEvolution/workflows/Build%20windows/badge.svg?branch=master) [![Build linux](https://github.com/tiltedphoques/TiltedEvolution/actions/workflows/linux.yml/badge.svg)](https://github.com/tiltedphoques/TiltedEvolution/actions/workflows/linux.yml) [![Discord](https://img.shields.io/discord/247835175860305931.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/skyrimtogether) From 0ac06324bc10d471c999d237e3d103bb22a49d12 Mon Sep 17 00:00:00 2001 From: rfortier Date: Mon, 12 Feb 2024 11:48:17 -0500 Subject: [PATCH 33/86] Update README.md --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a3fed5486..82d8d1312 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,21 @@ Subsequent commits are the efforts of rfortier (Ujave on Discord) and MostExcell Sometimes animations still don't sync, restarting game+server or rerunning Nemesis and syncing the output with your friends can fix it in most cases. Works only with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR. It might work with the latest Skyrim and the correct address library, but it has barely been tested. -And the STR team has not released 1.6 yet. +And the STR team has not released 1.6.x yet. -This is a continuation of Edho08's original work, later updated by Spvvd and Ragley. This version by RFortier and MostExcellent addeds these goals: +This version by RFortier and MostExcellent adds these goals: * Pure feature branch to make it easily rebaseable. * Minimal intrusion in the base code. -* Feature is conditionally compiled. Enabled by a single commit in this history which will show the one line to change to turn it off. -* Tries to remove as much of the complexity for modders as possible. To mod a behavior you don't need to know any your new hash of your modded behavior, the game calculates them. -* It's to your advantage to know the _original game behavior hash_ you are moddifying, though; if you do, you only need to list the behavior variables your mod needs, -the rest that the game devs selected will be picked up automatically for you. This helps give your mod STR version-independence, and more importantly means combining -your mod with others will work. +* Feature is conditionally compiled. Enabled by a single commit in the history which will show the one(-ish) line to change to turn it off. Or, don't include that commit. +* Tries to remove as much of the complexity for modders as possible. To mod a behavior you don't need to know the new hashes of your modded behaviors, the game calculates them. +That's pretty important because _every_ mod that changes behavior changes the hash, and the order of mods may also change the hash. So a mod author can't know the new hash for the mods a user selects, +it is only known for a specific modlist in a specific order. +* It's to your advantage to know the _original STR game behavior hash_ you are moddifying, though; if you do, you only need to list the behavior variables your mod needs, +the rest that the STR dev team selects will be picked up automatically for you. This helps give your mod STR version-independence. # TODO * Currently, BehaviorVar.cpp works, but it's blobby; when I get some time I'll simplify it. -* Build up the fomod for a proper mod installer again, and document the simplified behaviorvar support. - +* Build up a fomod for a proper mod installer again, put a proper precompiled release up, and document the simplified behaviorvar support. # Tilted Online From 24ab7d5207c582142944bfa8c6145746199b12ae Mon Sep 17 00:00:00 2001 From: rfortier Date: Thu, 22 Feb 2024 16:55:47 -0500 Subject: [PATCH 34/86] Simplify modded behavior for modders. Move SkyrimTogetherReborn\behaviors directory up a level to SkyrimTogetherRebornBehaviors. This gets modders out of the business of changing things in SkyrimTogetherReborn directory, and should make it it easire for mod authors to patch. Created default behavior mod directories for the supported creatures, so modders don't have to find hashes or signatures, they can just drop in behaviorvars they need. Translated Code\encoding\Struct\* files using code generation PowerShell script. Eventually will run automatically. Eventually may get STR Dev permission to eliminate it. Now when finding modded behavior with game base behaviors, translates the "old" numeric BehaviorVar values back to strings, then looks up the string to get the new numeric value. This means mod developers no longer need to know which variables STR Devs require. Better warning messages when lookups fail to aid hunting down the issue. --- Code/client/ModCompat/BehaviorOrig.Fallout4 | Bin 0 -> 187954 bytes Code/client/ModCompat/BehaviorOrig.Skyrim | Bin 0 -> 226116 bytes Code/client/ModCompat/BehaviorOrig.cpp | 39 + .../client/ModCompat/BehaviorOrigGenerate.ps1 | 94 ++ Code/client/ModCompat/BehaviorVar.cpp | 136 +- Code/client/ModCompat/BehaviorVar.h | 12 +- Code/client/ModCompat/BehaviorVarsMap.cpp | 49 + Code/client/ModCompat/BehaviorVarsMap.h | 36 + Code/client/ModCompat/magic_enum.hpp | 1472 +++++++++++++++++ .../Atronach_Frost/Vanilla__bool.txt | 0 .../Atronach_Frost/Vanilla__float.txt | 0 .../Atronach_Frost/Vanilla__hash.txt | 1 + .../Atronach_Frost/Vanilla__int.txt | 0 .../Atronach_Frost/Vanilla__sig.txt | 1 + .../Atronach_Storm/Vanilla__bool.txt | 0 .../Atronach_Storm/Vanilla__float.txt | 0 .../Atronach_Storm/Vanilla__hash.txt | 1 + .../Atronach_Storm/Vanilla__int.txt | 0 .../Atronach_Storm/Vanilla__sig.txt | 1 + .../Bear/Vanilla__bool.txt | 0 .../Bear/Vanilla__float.txt | 0 .../Bear/Vanilla__hash.txt | 1 + .../Bear/Vanilla__int.txt | 0 .../Bear/Vanilla__sig.txt | 1 + .../Chaurus/Vanilla__bool.txt | 0 .../Chaurus/Vanilla__float.txt | 0 .../Chaurus/Vanilla__hash.txt | 1 + .../Chaurus/Vanilla__int.txt | 0 .../Chaurus/Vanilla__sig.txt | 1 + .../Chicken/Vanilla__bool.txt | 0 .../Chicken/Vanilla__float.txt | 0 .../Chicken/Vanilla__hash.txt | 1 + .../Chicken/Vanilla__int.txt | 0 .../Chicken/Vanilla__sig.txt | 1 + .../Cow/Vanilla__bool.txt | 0 .../Cow/Vanilla__float.txt | 0 .../Cow/Vanilla__hash.txt | 1 + .../Cow/Vanilla__int.txt | 0 .../Cow/Vanilla__sig.txt | 1 + .../Deer/Vanilla__bool.txt | 0 .../Deer/Vanilla__float.txt | 0 .../Deer/Vanilla__hash.txt | 1 + .../Deer/Vanilla__int.txt | 0 .../Deer/Vanilla__sig.txt | 1 + .../Dog/Vanilla__bool.txt | 0 .../Dog/Vanilla__float.txt | 0 .../Dog/Vanilla__hash.txt | 1 + .../Dog/Vanilla__int.txt | 0 .../Dog/Vanilla__sig.txt | 1 + .../Dragon_BHR_Master/ULTIDRAGON__bool.txt | 7 + .../Dragon_BHR_Master/ULTIDRAGON__float.txt | 1 + .../Dragon_BHR_Master/ULTIDRAGON__int.txt | 0 .../Dragon_BHR_Master/Vanilla__bool.txt | 25 + .../Dragon_BHR_Master/Vanilla__float.txt | 27 + .../Dragon_BHR_Master/Vanilla__hash.txt | 1 + .../Dragon_BHR_Master/Vanilla__int.txt | 3 + .../Dragon_BHR_Master/Vanilla__sig.txt | 1 + .../Draugr/Vanilla__bool.txt | 0 .../Draugr/Vanilla__float.txt | 0 .../Draugr/Vanilla__hash.txt | 1 + .../Draugr/Vanilla__int.txt | 0 .../Draugr/Vanilla__sig.txt | 1 + .../DwarvenSpider/Vanilla__bool.txt | 0 .../DwarvenSpider/Vanilla__float.txt | 0 .../DwarvenSpider/Vanilla__hash.txt | 1 + .../DwarvenSpider/Vanilla__int.txt | 0 .../DwarvenSpider/Vanilla__sig.txt | 1 + .../Falmer_Master/Vanilla__bool.txt | 0 .../Falmer_Master/Vanilla__float.txt | 0 .../Falmer_Master/Vanilla__hash.txt | 1 + .../Falmer_Master/Vanilla__int.txt | 0 .../Falmer_Master/Vanilla__sig.txt | 1 + .../FrostbiteSpider/Vanilla__bool.txt | 0 .../FrostbiteSpider/Vanilla__float.txt | 0 .../FrostbiteSpider/Vanilla__hash.txt | 1 + .../FrostbiteSpider/Vanilla__int.txt | 0 .../FrostbiteSpider/Vanilla__sig.txt | 1 + .../Giant/Vanilla__bool.txt | 0 .../Giant/Vanilla__float.txt | 0 .../Giant/Vanilla__hash.txt | 1 + .../Giant/Vanilla__int.txt | 0 .../Giant/Vanilla__sig.txt | 1 + .../Goat/Vanilla__bool.txt | 0 .../Goat/Vanilla__float.txt | 0 .../Goat/Vanilla__hash.txt | 1 + .../Goat/Vanilla__int.txt | 0 .../Goat/Vanilla__sig.txt | 1 + .../Hargraven_Master/Vanilla__bool.txt | 0 .../Hargraven_Master/Vanilla__float.txt | 0 .../Hargraven_Master/Vanilla__hash.txt | 1 + .../Hargraven_Master/Vanilla__int.txt | 0 .../Hargraven_Master/Vanilla__sig.txt | 1 + .../Horker/Vanilla__bool.txt | 0 .../Horker/Vanilla__float.txt | 0 .../Horker/Vanilla__hash.txt | 1 + .../Horker/Vanilla__int.txt | 0 .../Horker/Vanilla__sig.txt | 1 + .../Horse/Vanilla__bool.txt | 0 .../Horse/Vanilla__float.txt | 0 .../Horse/Vanilla__hash.txt | 1 + .../Horse/Vanilla__int.txt | 0 .../Horse/Vanilla__sig.txt | 1 + .../Mammoth/Vanilla__bool.txt | 0 .../Mammoth/Vanilla__float.txt | 0 .../Mammoth/Vanilla__hash.txt | 1 + .../Mammoth/Vanilla__int.txt | 0 .../Mammoth/Vanilla__sig.txt | 1 + .../Mudcrab/Vanilla__bool.txt | 0 .../Mudcrab/Vanilla__float.txt | 0 .../Mudcrab/Vanilla__hash.txt | 1 + .../Mudcrab/Vanilla__int.txt | 0 .../Mudcrab/Vanilla__sig.txt | 1 + .../Rabbit/Vanilla__bool.txt | 0 .../Rabbit/Vanilla__float.txt | 0 .../Rabbit/Vanilla__hash.txt | 1 + .../Rabbit/Vanilla__int.txt | 0 .../Rabbit/Vanilla__sig.txt | 1 + .../SabreCat/Vanilla__bool.txt | 0 .../SabreCat/Vanilla__float.txt | 0 .../SabreCat/Vanilla__hash.txt | 1 + .../SabreCat/Vanilla__int.txt | 0 .../SabreCat/Vanilla__sig.txt | 1 + .../Scrib/Vanilla__bool.txt | 0 .../Scrib/Vanilla__float.txt | 0 .../Scrib/Vanilla__hash.txt | 1 + .../Scrib/Vanilla__int.txt | 0 .../Scrib/Vanilla__sig.txt | 1 + .../Skeever/Vanilla__bool.txt | 0 .../Skeever/Vanilla__float.txt | 0 .../Skeever/Vanilla__hash.txt | 1 + .../Skeever/Vanilla__int.txt | 0 .../Skeever/Vanilla__sig.txt | 1 + .../Spriggan/Vanilla__bool.txt | 0 .../Spriggan/Vanilla__float.txt | 0 .../Spriggan/Vanilla__hash.txt | 1 + .../Spriggan/Vanilla__int.txt | 0 .../Spriggan/Vanilla__sig.txt | 1 + .../Steam/Vanilla__bool.txt | 0 .../Steam/Vanilla__float.txt | 0 .../Steam/Vanilla__hash.txt | 1 + .../Steam/Vanilla__int.txt | 0 .../Steam/Vanilla__sig.txt | 1 + .../Troll/Vanilla__bool.txt | 0 .../Troll/Vanilla__float.txt | 0 .../Troll/Vanilla__hash.txt | 1 + .../Troll/Vanilla__int.txt | 0 .../Troll/Vanilla__sig.txt | 1 + .../VampireBrute/Vanilla__bool.txt | 0 .../VampireBrute/Vanilla__float.txt | 0 .../VampireBrute/Vanilla__hash.txt | 1 + .../VampireBrute/Vanilla__int.txt | 0 .../VampireBrute/Vanilla__sig.txt | 1 + .../VampireLord/Vanilla__bool.txt | 0 .../VampireLord/Vanilla__float.txt | 0 .../VampireLord/Vanilla__hash.txt | 1 + .../VampireLord/Vanilla__int.txt | 0 .../VampireLord/Vanilla__sig.txt | 1 + .../Werewolf/Vanilla__bool.txt | 0 .../Werewolf/Vanilla__float.txt | 0 .../Werewolf/Vanilla__hash.txt | 1 + .../Werewolf/Vanilla__int.txt | 0 .../Werewolf/Vanilla__sig.txt | 1 + .../Wolf/Vanilla__bool.txt | 0 .../Wolf/Vanilla__float.txt | 0 .../Wolf/Vanilla__hash.txt | 1 + .../Wolf/Vanilla__int.txt | 0 .../Wolf/Vanilla__sig.txt | 1 + .../humanoid_Master/TDM__bool.txt | 7 + .../humanoid_Master/TDM__float.txt | 19 + .../humanoid_Master/TDM__int.txt | 1 + .../humanoid_Master/TUDMSPID__bool.txt | 6 + .../humanoid_Master/TUDMSPID__float.txt | 12 + .../humanoid_Master/TUDMSPID__int.txt | 18 + .../humanoid_Master/TUDM__bool.txt | 6 + .../humanoid_Master/TUDM__float.txt | 11 + .../humanoid_Master/TUDM__int.txt | 23 + .../humanoid_Master/Vanilla__bool.txt | 60 + .../humanoid_Master/Vanilla__float.txt | 13 + .../humanoid_Master/Vanilla__hash.txt | 1 + .../humanoid_Master/Vanilla__int.txt | 14 + .../humanoid_Master/Vanilla__name.txt | 1 + .../humanoid_Master/Vanilla__sig.txt | 2 + 182 files changed, 2128 insertions(+), 29 deletions(-) create mode 100644 Code/client/ModCompat/BehaviorOrig.Fallout4 create mode 100644 Code/client/ModCompat/BehaviorOrig.Skyrim create mode 100644 Code/client/ModCompat/BehaviorOrig.cpp create mode 100644 Code/client/ModCompat/BehaviorOrigGenerate.ps1 create mode 100644 Code/client/ModCompat/BehaviorVarsMap.cpp create mode 100644 Code/client/ModCompat/BehaviorVarsMap.h create mode 100644 Code/client/ModCompat/magic_enum.hpp create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__sig.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__bool.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__float.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__hash.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__int.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__name.txt create mode 100644 GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__sig.txt diff --git a/Code/client/ModCompat/BehaviorOrig.Fallout4 b/Code/client/ModCompat/BehaviorOrig.Fallout4 new file mode 100644 index 0000000000000000000000000000000000000000..5a11586a74a6fa9d474d8db4df94d9edc9f6596a GIT binary patch literal 187954 zcmeHwZF5%1k)=Lw#Qq09&Ds&O>jnA^&v+s*-L&y^yE_2eGyXy#B!Mghj3gSjC+4s3 zZl0S;W!BBibMGU>)6GHoWBJXQ{Mnc9pYQxAzulAHoXBtR{o|ci^54@S9!v_jLNy%bf%H`A|NIXW-w%som+$|GMa( z^;i3e_J<;UU!H0GJ(D)qroO(A|3jbuK0Qa}o=A^Q&*j>)@OkUa19|`Z^7EI{<_G!Y z|CmN%SLB~gQl5x(JTJc8o9TbNXLwVL(KTuFQhK1hd?9c5QpV?4WZ9ePbMdqG{)Idb z-|z4IO~&%&^i0V4#YO)xTF*qn57RrG$p8HyKb^==k7XpE%m1R!c=Flw+ZQ`e<@_n7 zXD0U+8i{^Cmoa)dNqsHzV14!(#%lVr{C<1~oeLc^$Tn&7IYYlOXBdrRc@9?5f&9fd zx~5+XWAbpCbIjEn`TT3?AG87z{zHDk+d>xB0Cf9U`V39LJgBzfJB%Q-Vbon)m(^Up zmeD;te*#t&Ru0y^j|1$1t-Eo3{UFbQ&fJ^Uw9UD#E@%Q~2`h#{D6O4iCD`plw{Gs|AeOFC>E$?t9lGJWlzf{*> zie^A_UCUpIyeA?TpTo*f+YGw_`(>@sLamkd7_*2GcRloe|9R2@)jjC6t)gSm4CoiE z2ka!?7q$dijU8%V<`g5K`-y9)?izbjf1uCk$s75q77g#IJ-3m<+QjF^@$>#YpPq0w z%@FL4wnIM*SbPJ5S~Jm__KveR(^qQhg)z>iY{BXrsHE zYOt;c%sS-lPxFPRjH8Jj<1aK4;{}VG~)ifq2JCCFV z-WOv6S^qixdrc%^o)4!ngckn#;`jJJx9)$ECyl!Xq~J67Ezj(i=QHGQ^(k!+D~9!5zsYB9TUd?9VqszPPehA!pMVXCegAxA`)?;%(9$zm z5o$v)BVV-b4`n9z<K(y;sQ#_fz&}e%Smo1Jy2}ar|c&`Kb7bEnyi*~*CRqbH&bOd^>tJ?kjqFt|X{T#rCAsT>X)u;D*cOWweTev^X z|Gwyrwdr;3Kt79|7JJA;Su5CU&P4wnPrth@TJhHlDZTb_DcXx0Lov>U{iSHv>(fEdW;Rwgc6!}nGVG0e4YRdcjZ?2*)~Xt%UZ1R0HAcNg#eK-F zz};yrpNU`lujl%7W2e`rW7(&%YO!KZ&euNMM{W|`f-HEnh>c!I^Z`5kY}zZ~nZu{4 z_lKKguZ2uR6el8gZ|CmR&tt(4G-`M*zfs@NqAXiaI=?r`ZVXT1N9olQ(aYB&_eHYh zH+OpdJQS}HkxAYQ@SbYb=bp$-qN|lWSY>!>@a=3z%rbio_BXsIeS!yHNwksbbsB5f z@B&!In>)QGA8t4zy>^e1s-EYu==J=bSX=CF@HepU-j_GRPHcP4Cq%Dzhy6K9Q9aZV z{Df#RBxoG`O4b;#0F2`&L_2Nw)i~hJw5nd6Ybfw6+kd{7_c)O^f~Tgwlu@UC@L1kob=7**TT^YLp6}mht(Xp~=2?Hgom$${dYwZI2#xi2k1za*PpJNVIjw4V zBZo3B=G#6HS&#?cQX?gufnNXgeIJMvXw5iEy`FVG?59M(4kvpCi~$}6=5fB_J|((! zTl#i#WW&@t%kp33-s(iR{Mh$wUx zZ2Wpno45T^G!$6L*uK}fdHbsGpAr4bGx0$5ryBdu7WL3aKzomI&=L4-Q3K~~Z5*t9 zuYor2RUGvh(Lrl>N8T5>1^j^h!P;9i_L;08#i%oma3HG;e$P=_x1SNMgN27zG+*nV z5$lHjTC8oWWgbh~X!ZIQqrE$#tH5r~#Lucnuh+XM$Nl^pjik?s2JTLt9efNhAwD9| zo;?{`#pSUEKPMV^IPGfprZGj71?*Et<8z{WyOS>fuMIotU0J~=(|G943V!5;$b~;^ zUZ}}r`iOntRC=H>y^l^kTb~mh#ZLXb%sTdJ^w6H(>*MauZ{_pw9gn2tcRPQQ5mi=8 zF;E@H-X4zaf#~guH1m``C;Iuld`?*?eMYZ?&}2lsKuzPO`bgNlakCb>{;eg`CfHIiIj}O0 zJ!0*S2+bEnj}+~-ae5{r20!v!k&5@WUi4ZOSG!_Fz{#;{zLBr+wpYxsyyWfb-&9NX}pFG$oJ5^c9wBeB=vT4MJ5Zjsm{%76_(v<&~+eYIOei^o_D zcmiVMN0a4`USEvNZjrqkYxxgidG4HR-z~CZ$DUX3-0SVw@<0&M(WkvdFzQ{2fz-RO z-NcZUdz1cyqlCq}MfCOXLI&_|?2W)_V_e+FXbYy3AdF5BpdjqNL$A$Y#f>XF|a_5E%7^bhi$;HK0Q zP`N;J_vKyJ=$_8~!zup3h#|)UD+{_1rGa7pTHXh`_E`Q8;3N+ZFCpYSY>a} zebXd;Vl7Mgf2@1;qu{T{+z`wpU>%_zV-DCmpi~Z2C z)=UuN0gzX8@7xNXT*QpmCqL`jlqU?&$tAss7GZ!k`c_h17 zM8z_<3eT$>xwqpkuM?aFk~Q+h+i5h;SX=mmte5b@H)Uw!8&SHrh zM31X>mTPl^Xelthc?6L&%We?e?DMl&PQ#%**O}f2^1XUxy8EyU2A~14ty&>xiCLyX zt*O~!u$+X5yaK@hCW8JuI>vGml(CHc*LU}f1RH^V_lArytHIjzyEbx-5zWJghSgX9 zctjR&68&;y)MD~HXZ>F8t!=Dx>)!g=6S0C7|E*Dgo5b3A4-C=78pqB9R06R*Mn=bx zXCo{s{{Hqa+yomejB`0Uqgg0nTBkbOR` zmuwY2A$DwcVn)~C;hzw#dm`Q@Vy(HS@mrZKta#*510lD0V;YF@!@7AOeBzqPsyGdy@$v=RDRW`MEjx~SPkgHzW6>h3;Zdu zej_&Q_CKS-EC=DTEG)}N7}-dce*j+TP_)Jnb{~=2!~Bf+chJ7f*YYd`XA?WVmgOHr zuK_s}BVWsM5TX`vPLF3LEOC0D5lvjf>3v4@FTTSP|Hg6nLxBgD zSvW9ZBlclPvqi@6y$~T@hJ!=A4GRlT6V?ThKVo;x95M*NCvTgBbM$*16Y~En3m3;B zBN5A7rnmp;nYhjSVtD4eu&@UbUukvz zb~rg8BP06PBhB%%kIwV^yw4h4_nuxC?`pfAU0H{bvgp`j*7+`O$i=w(nO30o6gd`E z_3M1cjBW0Sch*(E_FPDhok!o#7=a#ZiR0`wZ{`Wt(b`%cuEXMcJf=d%4T)!5Ue(T! zc*fyX?F@-$99}>AbLN6EdX6(1YC2zCjMu9w+_b&p(^($V#9V;~pL~wHW|_T~`Wr4I zxs0E4U)JnKuY+Tq+wzF?+BiyDGZw5;7*SN@66Rb8XW8Paj#6S?Cga+=YzoG#)m3(k zNqc*&j`3}Wf+_(sT~~|77`TZ0a$CpvxEQfUgd@(CSzyM>MLCX?b=Vc%M4S51yT z8EesL6l_fYH_s$-2^tLs-7ledg@b9N8shFEp!JW9^K24nZuW8IAL zb5Eznx*6M-Eq*7Xk8>Dao|(R@#LE#CgN=ee2X6p7&KL3r7&@MeoC18!ndR@UYGsa3 zeaNVJ9*fP9^SO+l8a=;ke+)-`cL@5tXCF~?czEx=re!|v?-!De{4~urhK6njNskD` zdB)3xQ}SM3{j2rbwn9n-nFkYOc{2* zKI2s@VQl9zTnArK%i^5(TJD6^xAd$+g(xz-e2gzT9)?x1#HusYX(H1~kqygYLd0Wp z*6ZdPIf#E$62s3cuEw|_hMiaKj2mKzdDYIiA%>dcjjKFp%pp#yMFlu&jqHtkyXOdz z#VGUD#?kW3=V<$$A7Yq!#Wz9EmiQrtp!*vx^Fs_l_xR67wb#hXe)S{5aq>Iz{>I&| z84HG=FY!aX&Lvuijvrzud55+#G`!}AI2w+(v~xl|^PMB$Ze?R#L+v#&MEvd9DTbos zq=4>(MUI-!+riGN9y7H3kMgM_`D^z8;LH++jr&^5b3L~!3?bi)h2y7Ydai}xk#)ua z!_nhj7qQp4B8-J&sCty+9#zM}u}YZrEF8nvdlru4>AqUrC$UN{Kf{=#>X&2T7}CCJ zMF2zFVMB670I#0W2$h}S#*lN)!ZCz=WZ@VNj;Lg0v2Y9*A0>1w z9IJsbe`n6ZFw3N89d8h&Fs#W*g*YeznY>t*w!9iJ41c zr*y{mtobum|8g1rj8(s26^^wceS8ypUcGaV?~E-of5xg=*4B!!Dwk#c>~orLu^E5H zDqq&~XRP+ctQZ}D`vp1bJz zj<@B_D&)}5=3u+q+ViG+K5aAZqxZR%dB@)CihM^z;uNduqlB(qjo|g1S|>*_qxzn{ zK0b&HrM>~fj2$6+BpCiPiM9}%;-)fqu68R1t5NA#Ovbfw4pQ*~?K`Vh;Zm%9uX~P$ zWiFGkY~Bth%jzw;dS4CJgK;;EVRH$Y4`oc6x2qV@Uc-P8-8slD@tW`C}y%uf8K{AeO>6A{!XgT9xF``>hoh8O;ReYniXKY<>#k@C$lL1AT zvzOMdeg}nZu@j5IxiG#9Xh>w^fU7?il-KxY#(QO!#`@OlSjWiq`gIkYSg(gR?~dcv z*Z||Xy3?}Oab1dzzL8Nsk#V2vALF^Ax8Y2Rp>!Qj#q_Vzx4AYkrVDR@yzk%2S1=jg zc03!9v0Nr&J}#!yb4k5D#3}bU9|Y*Lk8dZZ*V#?^#9o)zFdvNfT7&3wjtlD@I{#ww z37?;5%;>shj84Zb{fhUE2QiP$in_0MpJsCw|m}>k9TkRTtXgih7EeVJl+f++zcP*D4}Ay*p+ZfK2E3F zo$3HQ=e*yA9g8spXpX}$Jn%9IIl~4kc{OG^o&m{n;r$JlQFoRNkC~3BJIjHuJieYY zV2I!-Y0X$Ld~k^kUHf%iKcz7zCV?Eymy-<})bC?dw=8(A+uPF82# zjS^_16%K!&wd$jmT$$q)HY^i9w{zB-<-Z?J`OI@>X|BO6|J_&39A6(-9?OUC_#>7L zub95~bYufqHvF0RgE(crZ`)hJ%{U2`4R4Z+A;Hhe`9U7)yN>`i3 z^W9_awQFlWwTNZ8_qAE}IGTUVlO&&xnVuSbtj!%Z!J8 z&b3)Q8{VsSy4zY<20X9LVp;EFZ5GRM2j;f6HjCfvfZ4;&(4UZ)^WD8p#=J!5({&ZI zyBshhKEhZzw$tXD9Q;YX0|7q(>wJIWHSKxK+O5rY{6aGAJDa(Ni^VxtU3>UyR#C*O ztB~d2Nm)}LbxSzMu6^vqQY{mz57x+uc63>0&mYIWt*?(lMZ}t3+OD%)A9YJu+RY^9 zTA^FQ^RAJBRlFx_4|kK`E=bj8+$qwv9{q0M<;!>Jpn{~6ht(MCqi(I%;rabRs8{Kp z66dx$Ul6EwueEC{q?B#%`mkIhh4#IEj#boirXugxkk;$w`Z_7d={3?lhB}i8t$SU} z_PdwDbP`&0Pb_)9od?gKYu{DoT);{p+XDY0a~akTm7Vw*PX>Ct?b8M$7x-c4TZ|)N zcs$T~y))I%27m{F+q{uI^h*98cz)(p;i(|6{%q$Tc7AzoE#Z0MoC~1;da9&(4L``I z5i?(tuZXwM8m@x8hiKMC@WG)9$EIBpW++b|GXTjz(t3iyb?$8}s~f zimUgU*=4yHkg2(5&t=yIu7%Ucln=ljeOG!9hJII`49jCD_u0tzn(NWOd93rfXIUB* zkEHE;7KWW>Sjj_#lM(h&KiT<){)WrE6ujIn%JFzWN0nt|RQ9kR5tfHBN?J1(EE@yS zL}Zk7)p?Z)%gPwz<0vKaQYfE9slf}+u{C-;T zI86r@1NVm*O2E!Bv{mA`Tpic3GYmVNpWXN4TFiMOmZec!O2co|-obiAv_W2YWIlDsig24H>p{Axc~#z*wWxQ^!hkE_H%zz%`I1rH1y9h?aAAQT$`q6lVv zo3}31UKV^-csw66F0wQ-Im(ItcZHL1i9dCH%GLDl-Qy^{pC56R?cgeW7Ty<}1)dj> z#b*)~JeTj@Y_X2T_pb-?(N!=;9Lh4431Z9z}taF{bK~ zlK5Hd?(_M;Z{~MC^bzP%Ov2EUD$k9fB$zG4VRvQrPUU@dY#9jGob z&EmRRAC7}~CJ=l9oy~|JF$833PJbsOhWsjfHyt^KgCNRzA&8Kln{I8mX5rq~Cl}9| zYbC2ZvA!+EW*pJ5Q)00Kt>QZOqSvyek&JR}M0yRx>WD3(1~Rl_q`~*(8uMY;!Z?R6DbF247Ay{~sy6z4 z(pu$;3x*w7t6Xov&;z^~^s25b>Gw=;mwU-j0&kc5nQ;MUOiri$(QY8_>Qh-g$S5JN zO4UquD*~_LiM2qiHl(YtWAz{W$=35;qkPo8+RIw?cC2dk<+RHHt1~Z})qAMbRkRj( zlJ3uDu~~gbyq#!XQ>Z;>^&G5qoF`V-u^CUv>O1-qF?o##wES-qGp47=+j}#AEaLog zyPeN`@%6Py{V0&M-Y>o*J|yx0_34K)=VtX;MaQnRx+85~i#@U$R(s#x+j={mjn#Q< z$}qBekIOQQtR7@!cWkHjOm$Wf(pP*}TrRsQA@0@A<=ReEGZd^!r0*GGgjkEt?@r+C zG_MG8t5=UkZ!hcH#f-l~78fEcWM`d-j;nTSt;n?Kw3cBDYIcWJ zmas|=mZ5?@CtE>hb9LNV4N3H2xh}JslDFqIS+z-w7h~RerL(NUB+7Bk@9TGZ?XPV? zwoJU@1S{9pz$P^`y{9^_C1IEjyu$U>HmoiMT9~VCSOrRq+PZ2RR)I3MNABpZSP+Zk zSse=WeSHm0j|@g#TB__|9)vQ({k=J?I%Q2=$lB_Zr5X-apAyF+uFoZzYim|EsSD{* z>)1=PbZhEDdiz^Ttm;B~Y&**6>Oy)Sc=U{nWyRi$eF3KdXx3iLf?-uEXgAh{^tu~+ zUcGZ~J;#>$-W*nqvbHLO)upVf31PM~R&UO+nv9wNTkrL9vzm}z8#QwWeo$SHG1tMX z%tHXyj`$MiU}C4h%7(v$NC5~Mev4V%W+no>=#h*2kh2e}(bzoWAWQkFvkWfZqj#TK zko)#An_xTH1bO7&rwjtb%-gKVn8(Zg&NuRh_r<>2Y37D=_WN9nnJSK{N7-T?)KVS7 ze3y$DK`n>n(lgI1ThIJfef$vP?zsnHXh}CBrvpFGq5Hl6HMZ~gg&v9QG2T8h9dpI! z8ppB^Hp8ZQ7Q)(!9+r);33|+O5ISyz)mr%3f6i@KJw?R&StbILp_<2X5WIEf`B?RY zw_~TXv04e2kXbmMZD7$}X5m7WS_WJ2>xF!dZ>uWrF zkkvI*yKO%rEQeu~v}P<=W`p8VXOsVeEGX4Lukm6z4I|bSS&xWrv7CmwUW?~1z{kbN zVg4^uuf;MQx>_rCl4a)&sTZjG2|K~kRv99s=hHmY`9dty0jDb*d3`v$7QMEH(h2=t2?JPr*F<&g( zp>99w4a;oc?QuGiz5~l}sAX8YUe`txzRSX884ODjZd~-9#lh}lk1GcjYRrP@_idm8 zsxKz(Ptw}X=(n-x_vqXn`cuj1_h(o{oL|p+&}-tnb^UyngRog;C(lNRS+Vh6wXq6= zop9Ns61_%7glLU@o?8i)p#aYVJ~L(-c`0h0RWn%bfqQSU_1ynsSqBm6G2N)Mh1iLf zajiv;HSU0xrO2`lq8yJQ`W%Q}W7lU5v(qp8%omn%P-{xgzu-9tm&?E4c?p|lRrEVJ zG`7mBV7Amx*zB_^dMmn=RngnedEQBHB{$2z=(TT6^*PHg$bPWe0(Sl-X2eH0T98}h z1VOhTRwEG4Fl8rMo=kg~oznVDyb_!dF`hoK_S{OIqr!3mu+H)1K1YS0TnTUL5Aqjh z3tL7Y>iBWqn~iy|Sy08p` zT4v7KK+pR8f+(fVR6%>TyT`q1U9Jiwatj%=Rq*NFI>!Fj@7`O+v2D&+!IOI(UYoN5 zDZK`-%UbERb=%bM??)k?GaL+eeP+$qv18s-pZn3X7wdUr<}q<8 z*7M$rcg!fW^el75+cCbH<*m4c%=5F16>pb$ewML<%#GV((T;`ZnpfpUmY(ITFc~)1 zy{6go^GLJ26>G)DnPse4`#j1#PesQnk1@+qIS`I*%^0&h6(&Q+m}RTj^Q$rLt(djq zW87OWYhR6VZ>6kNHO9RbZJMjm$9%izd_8!T7|R>(%<@&D-FIw1BepDKWz#xkmceq_ zI%Ss20-2XT37O@&)T3wkP|YT=vpd%@>OQYbljk=aRkyRTQ#mT;*qCaT<5IOVrkZ86 zRPBtZX1Oct@XJF!zeIu4d)veY?J{Opdm&5>gF zv)U@b8e{oNET^T*vts!yIaev(y4u^r+zt`Eu56aY;;Tm4mNybf>z$z%YnY5)+t!_V z&GK3BRNS(+bmle7X)zh|_psGG@>eXgr9SPslhem6n`K6@jF&a6BRj2Q4Wq|S>{yfi zhkLNb$`QkP4E;Ghk6#bP&PS~CnxIF})-%DhKM`LB{2Y85+!o_ID{KL*4zjwymLkr@ zN08v70dH%%~W zh_62-cK)@T7LD6?o^P?{v)e~%1i429A{MItNsnK~&jL3EzX5N<-(My4Z11uJ#0-|< zr_y?_p!1GdwAAqo3@6XFcN4sPj7R3N;(Vt!oyLh+9Xb%B3XAajcxX*Vy7{-gXSzm; z=e0BByo%lpEns;DRXg)(7+zkrGqfP*7x?&(86#bGHABoJJJZdjtvRNDUE4Wo!7%it zIF{k)HFgDytvO-;dLA7y9R0Fr9jgn4OxU0k>Botj;)pq7>=DD<-wyd>Xne;MF)W^Q zJdwNL*t|0*nE^3d-CIjbAY6VNb>hmB{7LJBp(f95ctwdtp2C zp+x47q~=5|Den7#WSqH)8?7EsGh}jl?E^=Nc5hST$UQ`UYXZaEG1emn%)LW>(i+^k z_Y2q7nfAI`W2g)>?=#C8LOy16`dH;$PL7>hwGSki_dNGBe@^wF7_Hb>U{;n1&G2xv zyCb>|{7c)6m3j;p&u#CEjIl?}k)I#bW(yLd*Qu2hDF^}Fe=+zzYO#71mBR?N=L+vc(A?Hc@Es}O${tTH>n+WLs1Z;n zJGaT_y)&FUx3`m6d?#V(w$?G%`TwL7Be@T@TxR^^d#X^)n)y?Gfr7PSnnH+bK?rug~KYE9<1rLaoN7}3O7zRO|j zF_Fw}sot{6%1utJ?k$q9NX@^wCo}ceY1UkOSv{p$1J=6t@lo{`pQlphdk(9r%p+IV z53rg_@PhrR;jD_X(*T>j-rI^bcJ+NVtXfigd`CRKWARy$pQ}$~wUUQoG2Eh#H|VnZ z$dQpmtUjL~UJ2v?mHcMF1IHUJE>PCPActN$Man?PMG~G zeoAw7rx81sc{9F}oy>eN?cx}Ft0c8s*nM|fG z#i}c#9P|r&$G+6vJSrnQR&Ci=BC{Gx&51+wgy?hqDekP|a;&CZs;fU7(eP1cwJy5%zZxUa(bO!uGvQG zUZdCCEC30;KF2p%s z>1wwbS2AK^@TlMq@_PoLU%mZ~J*wV@aUx^esv4WIBkQZN89TD38ku zv{n*%gLd{)%=WlF?Wn-tjXj7pWK~75=O%o}Ic0Ga-ewHf=4zQw`opxBB1ZwYxxy#K z%z>@_jnuerqbH_4uSBE35g}vp*TWrT>bF6ko=896rcWPp#kP|x=Gy%JWQalM;Z=g+ zgHHbEg$^oX^TV_<_Gh{Y^c8&LH95%++2n`vuQHvd7wxguT$-&sd<9aZ(E}Jo^?&>Q zJbw0(V9v3}<~w&@FGtgumm2Li-cM_Q=ewyszxP$U=d)~(-d{yzI!YSIf}3j`BFSEF%*&pm9Tkei<0aQ52 zUNc7zwa@-Db7 za$+&f`Yb0F*>EX3-YkxB#4TsQY{0^^16x)w0$#Y-L z#-X>U(VL10aOLH(is~rG_tB0kWSL|mdgnGH<8~~ktY;iqy>*OM+*gg6q&lKJlMFTi zwrVrhlINL0L)LSVtopj#wE)@^Ih5OO=Qzp9@-i%jb)_8wa%F| zmY257qv2-T&J$e2qOshx_zp{K7t2?Ra-#iQmf3rhQRaI7jODdOiMCfPvuEH4y78|i zX10mvx%v4vHFL&p4;a0vb-WqNdV^hz*`F-CExvvA&b{7_Ei=Ccj;0&)wd@+pa$Dxs zSial1H_x%ayhHOGxbJ2Ecr2dmL-`kZRKT~8VdPwd+D?`W=l(&L$<}+5*;aQldOwn# zlAQD4u9DM3_7KnvtT3>l$f-m|5Pk#8hv;|Pj9x^hKWtWS9EprtJ0=QG;Z#-vFm{~V zkCqwbNBph~>`!qz#GG?j*PCrHd~uvVvV7ZO`QoU*FH9dYFHU8x0V6<-6LJ;6`n?aF zAF2rVBt!V6eD#>C_aI{&oB6RG&*|FDcY58Id+)H5^O5zdb5DDJadY&t_a8@DODHpA z2QP~A$QZ-i4ycdL7|U$jta^oIHLgdG zSx(~^&30UT&TX_@n4>8I?6`P#Dn!Mp8yC+R#LWF07ti>@_@)u(sc>?3MnsgejFU6w zaE!%$-RCHr^M$Yi@QohGU!4D7tP(qoIqvTaCueNnWvhD_YY0^EP~OLKv3!JUX5^;C z${pH*amh71?6l<(=dN*b&JQ{YoNIR2xyvI?&iKGhaB_auGFT488(NW3^KZR}XnW)w zCucW?V@7<0B2LcEfAF2P!pRxCw?1cqodK~1ZD%}Rv=|(1|Aba zTl`K&zb7-aJ+p;ZiMDG+o}R%BUQFv|aML$Z-=(mH=cjN!QVD+euI2D{8T<|0D`S&Hy=&@9w;Ksx?w;zH>X4N@k zRnC!A0r<{lQG%i|^IXjFvoYglj>aENv8a0gRugFm&lq!RHPG7g_2!=J(RA+GvBau4 z(E#j#dirl<#Bj@nK6B23=T>$v#n^7nd>>6CbvR)Ke%_=$W1eYl&w%FwrbRzB-`%TP zs5u^fBnZW6a{`D;oul4I!tXqiimd3h`UrW?HS_jRG~jU3HkFpKZ=CXCYKQW#nN|w9gr1j`M4uspnMJ zDS86N9%r!mJX^~=qtM^j1}!biFC)cAk`tr1&CctVu?6v5IYlj_;OdaqPC81eW3XzWV;jr@X24MSjJ3u!H`nuwv)1p4niiaw@oadXy#C#m`jhJT zGvln)lYJy@6f^2tc>qknP6&Eh{GP-&sZ-!Gbb#?5@_s`Ftr!6v~ zig&_Ja8E{L&bMUzR7c?VlPCL1TKbNWF;d)0;im%5u_EhF))%)F_L-~;HS3!3O4u^P zm@~VJIT`D7GFr*`z>H7UpErw>@yGh}#{Xpu@@T3OdMVxx^pKK_4?2Tw! z?^At(ZT2p)+9J-JQ9^c~3(#hJ`@E<0_1QWP+A>!UAcj(33^i+e@{{=+)`EGSX5r_1 za?bx(`+?JB5jkrt60Jzi@5fl&mA=7}Au__55Bi)FX>Yx&^g#XFe9~{$0&q#N&X2_| z_s_^0uq##_Y~vGYJ>LUzuKv*!1=}qsBP(q0kv-F;Q)??70A7G7;EsGfm9O4QeNN8C zS6@lT)lN2y^O7_0k0!}}4kBzqb%tTiw}%dN=SJkbdVJbWtk?54ZT>w6DxWKB?_>D` zF6@37_e68XeC&~;EqQ0Lan7s1JNqD?5F2rgTt%PHfsLQf_4E0p*ZBEd zIgh&@=a|r%(-ZRPt=NNMPcR4jAh*MbZ0Nj`;&dlu4R2A9^NTy z+K8qh9~wDyiVu&oh8rA!=V5R4QOer5D}Dj?2iG#x9X+|oe?mX1UFgB213>Wh&b=-s zA={)~(X!W~1+V1k*i~WuFgK6o`)49iVSr4jNt}y3bMyD$k=G;lCHKjtHqXf@<>*u$^o@*J) zvs+=#wXAAxEBv`@owL4B|G_oYM*~l<=ap+`l+e#A*HD*H&uN8J$5F7o7&iiUE5Aam zYZ=RPn)8K6E8_jB<}{xd)VHqYG-nR??dv(sS;W1BZcZy4yB^POPPt~TnFX$ym4qCT zjQe+meaE+|=CeY-$2Qe0Rw($`s-C+F5g*%iGnUT-8fX2FvRCd;DCrCNYCeVg&p8u# zY~T5R6@EVUxT~ju2bz7y*mnNRJK~cm;%MGyg{4Oc`quD!;JX4p+>@vU6|=5CaSXW5 z`O5d!b6*ksfTN6f$Fg?Yx!-#fnUmepIvy1rZ+jqSP?pt;OsY63#y4U`gkCbH4v12(Wq02eGzGUER=JO zJE>esUKQhbX=L=RJo)+57k{g4bvM1k8daHj6+jAB4RRb_$c<5m1D}Z%Ihn>6tINk9 z*=-)@<O>^&$*vA5#}kUaH@(x{>8?hXJE14bT1c2>4mG7|zd^EC_ngknl#ka8U>|N|Q-ahNNw_#LAdgG%!@xjP&(vi6Pd8Am5u>WYaO+pCQSi+L(*5f%++ zOW7Dy%*rlJllGn%d(FNkjalVVpy-sQe8uiX-3xddm~da_!izK>y27UjeW7x>6m(p ztTnCyrm3+40Pm5t<{-?l@ovg1+LI~<#-C*QU-LB%M7+|FhcW`Ncvb^%KIgqjQ*dL+ zZ{#mpXN`!Mgl5nCX&dGTqGhEKXa0wEnQ98vm#VpZ5SrskCWrO(xoB%~Ix7v+DH8irQ$L zW&RpikID|2ukSX%Mhs7z`#RMg>n+EXQ}HaW&&nyj5&cAUN?mmV30cSB*YwYY8l(=K0U6p~z)c zMnCSF#?3-f)>2>F&d%4KM8$@9>o`UcHNsQZYF+NZvIbTRNxe#3`daO-m=oxS)&|`c zyK*eE_Cm7PP_F|U4jc1EzSFzGPh~z#SE`x-d=jS(17mZ29b*NIU$&&`SNI!^yIsYN z988#iR{3GB&^N?Oj(K9g$-DC07IHgSaV5wu(io-Jk%}up^?+sP!}E&O44Nl(SH>Mx zoIlFmr#Al8B=Uc$riRu$*r>#B>Fs>%enKVv`h`{grHfak~A1Ji8TZ||FUkm9>)>L zy24_GM`91E+5nsenRm=+zvlJ;m5$hVD?3otSZpeb^)&l_m4=R0Os=ms#ubC$V{H6` ze>&^h_=Fxys+j~>Frd8VVKU6x7NX zSM2YT_gJg|R4}}rdU8GW=dReTKV7W8ifzDCUx|P7QaqU$CsoYC!L*v;;ANw3u7;tVxcDHu^X*ze_PGZ7&xWAG=*Ut3~ZvaH!Jo5NCW9VSp zH1_k{bL_MEE(u@)kO*zcr|Epir-dzz%vF!|PknM2f8VveGi`h&8oDcM88w-|9&SC? z6$t%&B07E5qxkU@F>sII{1p2~Om1^xCu`&DyPbvi=PWVgu>pMnJE%Dgdt1Eq1Nl`r zDe9rD2JGk$CQJNkh&6P#oqM-7mx%f1t+mD6d+-(>$J$OlGCKarhq8)KWOT51#2X9e zo`bjO>)vA|qR*Xs4=yFvcaHv_Wh@~ARVnjGXfr9mVN}lCD|I=_SH^Q5kd=0S(i_iO znEM*u{)v3j{IvraPvi#JDG%ml*r)AleHw+GUNMiFcq==@B6G>!uFmu`eyjGvGso=m zklXk+*@*KPX_RbQ06fLACt>yK%txKy%uJ6m;Q?W8PR?->M?K)rnm=W-dfmNzR%frt zBi3nr?uooR@H|@y?Cy`vDocA^1_A?%36IgnqSxX0X;hkgCGnTrS!>^GbALWT=B<4; z`8_R}!S`Ypr;U$>{By^}8D7eqXj$Su1i4Umhc-6PcIx z_IfvoBHz)cF%*W~;(@V3mcKFrj-5l!-i04$$VcX=y%&yzn~yfP%bBf?t-;&9m=J|y zu_LhO+P=>l&73utSLXtZdq-xnqfBGWjAyGPs%~XwJIVp}yZ$YEEgkojsyBHKdhOLr zfj*Zd^VI%MW47*XnLUgvGGdhHvQg=G=6T+Nwdif3dAyg;>&>iod?Sp9&A4-7na7T8 zBD&??P>ok+X4@s%8uB=&&PL5Fw#zt_6$}j6qOrKgWd549!w#kMky&eRSD&o_CPA|z zOhT`LwFJk#a~ooGucb+jUTkW_u5$Z-P${2l^O1(KIpSE$L;MlyJ;=+-BHpS zE0Q^Hmw;SJWb}@ilOExZ=zC_kT@p}bwsy3d?pH-Gp(Hh+V0r^sx#_q;># zbIqN%v2mN{nD%eq>!Pw3sJi%Z@-EFM&kVLd-|~jw4IsAk^E)$#9a}ABpJWC*wnn`C zTxR)=cpzh5vTA*1v+LI8dDXZ87>+I$fxg?BnX#g_@}xc&Mr4f~_tJ6VOf9Lmg5ym( zKL4TXFY#_ZBfSL#`ii$f~~b^OWK3PrmG3d6_YfGO?!C-<6jc zbC-pE-8eyDEUIbwG(vAN)?C$heC~8`-d5>bMG_z?ay_~UuC)Gx;k&E+=ksQh*S5FQ8n&# znF;sy(FSQw)TwCup3K8Mn?2Xqxs)|kdb!fh+s9t`bHRt@Q?fE=UdxFVby;R_6Jy_a zZ7n=z+wU^pUiZ>=kJ^VDCHA&6_R%GR7Z|aNd=6vXE6t?9ejKv`ftmN*%NU1YPsOgf zR5h8;W%M3lEyXj5@%$cXjAM}B9Bq5lXKY)Yx026V^nR|r0S|rXck$&c4z%y}blkh= zK26@iA&p_%Yiq6`r`JsPA?hd+t$S^RvBGsh7xKxJ6+w{t^ z9o}UIO4YxQnJ3%IJgG+ieaSdM*1)d(fu8|y4Ovh}vSwavG3&%VZ^J$3xb=LGv6ZeT zFKJc7GAiF^pd5;)U7eCJVm`g!<2$UzbiJ3uk*Pisw3x)7G{zUbPh(^1ShDt!c`-GP zt?hb$B|oY5H|Czo)p`s-Sm7T4U)Nk#oWKdBTuU;s(s>H0m+}1ABSLg{W4)|*KceU0Vn76TPEQ__z zb?>!xeGX$jhsm{rOR@Lw^%QZ0Ry5{pHI~cj?Q(7$%VhO-ITtXW!4%)~zE~F2c;}my zVm2SkT1BQ%CqqYyWvg1-YMgrgvR2h7^_I|DRb#|7>YK&)o5x&ng!|Ux2>04#5^}#; zR;sniW5jY&tyP{6mWk^6$MY=v{nnn#+xNE1=9ahbHEOe5&3x;G&v@Lcjj5_LCs^L< zGHS!JR=xEyZo@KIF|T_6wXS5AqY5r7<|b;^tKa&}GE_%qElL?P9Q(bp%L-ySr(ITL zuVrta6`9XXa?P>I?L6weO|#4*Md>_~lIN3Ru7D@KkUyyPiWy1y+#~PdX1Q?rJS3O2 zjJWmj1xNW<4rzx(j#|!gM@JqN*mPAL#xh4)eHhCet=d_I7|R^3+F6ZQKJ&D{eeM>^9*yxJ%iUs`q?gUzVmYN_4in2A z-SpHAmOTplk+Zz=xkx_hYqGpp=IGddp5?{zMX?{RJtu_akgmzy$~QIm2xR?n<%k0XTrdP|-LYwh^ zzz49-fH^^b;HLo67~yfpb@pbLbfdF2l5_N9Y{q$vgsMP`zDdE%Gfj?lF41%#kpz)Z4{=j=6u=NqwWY zkNusu?={TZ$9~V-_gcmn;$Ekg7~)>HI;~dp-Snc@s|t&>v#}U2TD3FmlkuWeJHtL1 zFS_nrGdlx>v7HZ{-di0MqE4L&e%4Rd2bbfgrLpsV#<;aZ z#My~I{b(brc0Bi}*Ue4NyuxX*9saW^6WCip$KfoV)NByX#$ZhBWwJ>aM_b9m+`->F zmcPJPkW-fX*t53&hHH4no>zk%j65Sw%kAc;vR-`-5MydbN$bXEvVSFvBpvE&`V2RcC z<~wZMTk%!HPr>-PbGY?=KgK!unjZZbb}mpYQQ3=LUazk{()H>dtq$XTV=U0^oI3N2 z`;B{Lx27X*>tmb|TgDaloGN36Yu^ZK0=tplH_ka>*jdaYt z_~%sgWcfS{#tx4Xy6k4g3+G)+?EvF~p%opk+v}2BGqbTHugi35Z9XnLQRpK(d^A-u z+KEQXOm6QjMhhNyf@PU~1Qca{WQV)>Vf3{>vcvll{i((J$PRn{Bx8p;vpbJ(u9n$F z?XA|^!jA^0i}Pg=ZNNW6{EzzFZJyWx_VG+ke)#3Yhgg(T*OC2JyfobQ_rruW;Oupr zs&cDcWaRNJP>VK3T=zCiq{%h)yF^TxC z-mHT=3+>z`WD{r|owd4Lbu32UvMtwgqSnK!K7m7LaBVMaJm1}k8`__bOzifUSTKWF z6Y34??X=m3nEt^JJd-tvyF$8l_E}wnW&@!+PXsf;EmXMs@iHq$qeDk2A=9nR&$9;h z&SWEXmt|hMSIWiORc$xlS8Rlj1R>AknA`Vp-zLa;9~1UmR3HC2-e56P=e2eCX76El zaar#_dv9vok#PnZiCLs?x8b?O5d&kDskz^EZy1kyAU82;=G^)o_4?&;CnAg`zJT$q z%bC55ZS{UEvkliNgJAfujkQ}7TcbVZ5Rt$-D*&gdb$T3Ia~zS?r^ZN6^Q@~Xl+x8|$@X|G=V5*Sf&J*t zCuX;>T(-uAF|wQDv8*b##$y=|JL0J|9?N*wvHcv6y(uwUXDdcL7H2hfpWFnGW!!4i zV_v_(c-1u(7_9a+_F@SSW2|bF6Ib`L%zmejGS_2ltZp_+v>jo&0)ti4))I3y0=wfS z%BU+aI13vs=sJvzF|=5ym!va#pYJNG;L*fLjOa6Z;*6>#DoSm8g*E^sDj$36Mi zF*aUZYcjfe2Ubx#?i_Q^q~h~>reXcfXuR5XZ5;<^UNQUkWH-vUMQ5(nB29~qG@?ar z%M*z=;k#;-drjh3?9yj~ntdYsG$LR}lH3af3yXDvN-rR9s9OWVhLeTy6RdKMl;7PA z&bF4^WBss^w>cVcITUU#C2Gn)2(GC50FD_e8|!&Q8m}IayKIlPfzHkQ_7SPu7E(7K z`3`+EEifyHuRkSf2Wtgu`&90t(Xa0VYL|O$`$F%BdjypcxE^77djxOke7HV#=yJO2 zQ@?sFugCv-k88}p^gT_-nV~3a^BH=yuRC3=_x*WQM69e}_#T&H8rGx4jxWTT1#8#q zn750y3f8WVLcLwAQLuKsUTu~~{qFF(D(_h}t2x?W1#V zk>PV!fok^F(NOKBJZgsH<=p1S7q{3mtS-01ey`So;c}auEXDA;Q5$_vLCj|T=&j@? zTo}Xd*5mvP*BcRuuC|6DdJN}h7+%%RDy|rISGBW>tIJ?@5l6DjXjTUiN6dGw4vA;D z+=!>RWz9$m!{T}*o}q7RGov{Mce%`HhQn=2_(M&eoB#E7KVNIb{rJm>a%i9=oq zQuk8whSVxBWNt*_ISQwK;A`2%&LlGn|9&rfGP2TvJ>8WZ;!o#KWR(zWGNT#xhUYG4 zMl;-Pl+a~HX9Uh-&ZFssLF9<|KBObfDjT2`K1&)aS}PWN7^7>vcg&1tl?!Wfnpq7) zv^ShF;Z+PvH@z;^E4-Y}vqsefFiq&&iFhQhSC4!HW{t^DXQ&yjo)B9@zPKQAW+T@YC_)K4};+znPF#MPL<1zJ=94#GY60+(#>8 z%gnd1lkwJ`c*W1jTjE<-HN@y2Eb}ew+`RQCUa@oY+()T1hWM#@m~&W<%(CRu@~)O; zfqljqb-002PpyJSi~U%?BIkLV9Loc-n!58CTKOS!EY)b_e8Y%)?u#Zpk^KiAmY&x3 zXsRk7$MmP>Sn_+V?UAAD?=Ay6_w6IcvK@{kkNo??vB2Mh=Z9QVc>nMO%@>$gUc4Xt zOZ7&GCJyB7UJDm%-ffST$4Gh;MrIR4w#Uw0ieYllFVxG}{U<$s-t~O$X;^gBaZ=IC z>O9M??RpfeM(uVw_AIqd&^-wJ$L!qV@fY+r?3>@EiHd zvaX{PKS|Fvj>C$ifJtp6k*x6C4cZ}tU^RkT7GR`MTil{@3hz&Vr%ukdv_NdYu z>_Vm`j2pU))IW*rlk>I9SfowP&04oY;`sG%J@&7+;ql$qNjAOdEqs*e_NwozN@UE_ zl0^7XYAbZk>oR`5Esd$1Q@QqXPM$K-=v10rblc6KUm?_ha zJWh;zvR2h7_4;J3sxj*Qj&=E1oNEG}W~_vtE5KMLL<<%j05PeepRcFA+{U=KlWSys zEBg%cSuGafeAIH^aK|frseQ4SrxJ_ebV`@q$7pN%+Hpd?N4-WWP6Bu;o*&{d^AQ-M zwOLLR`t^Hk;rzWMWuI_KMxtFK|umG3c+Ca2fW`t(J{Ty?ogjGKa<#EdY;L8-;k3VL8i zcn|Y&8T*8lruWa`X~2EadahB7ZyLE2@ADr;-kyx8<0XuV!nrIjc78w2^{e9fy`HV9 zSYvFIp*!#pfl56-pMSY%obO%u~#(F+xoPUbGmEnAx^J5&;+vlV)ZmQ3NVXTy~ z`K}RT9erk|Jp17HvOY1QrvLMny(b9f9OvM6Eqfo(R|353oDpgg)jF_ynIiI5$L;J6 zCamPh-?F=wG+z!Y7D&N!X?ai99Q*=X)!JKj;}V`{Ck=S)%I;L!mCs{cKRefatlTkg z;qcrdTW_oveFU;5Kj;g3EhQTeOQPDy_5`B(&!vA_cXSami?)os#iq+WN_O=tz zgZYkeOPKUd+QEcs<3?T}cqcL+&qQ~CQv>lfPwJNN?wtfb`RrSnOVb^ub8G7~fX?^z zsE5)+_{YdN4q|YJl=&;8t{n4Uo^;c=@^ zZL9v|-1vUXNi#9hJb@Y>1$+%WGDL&+{W;7!JjnU^nwo?DZV0+AOnbtGDX4 z9INtyXfsx_-F@NhdcEE~&yckB;dgI%>t3hPS6GkdGOw^8^ZxeQ`)2CtD{0sJl$e2D zPu1#n@60%%gXzpfWy+yFr_)U8`EK^sjQ^SEdvjaL_#V_%XpE>@ynk-nFe=`YUJKz5 z!y3Z+WB1yXw*l96CQ|<(Kc9)E#(O@OpYO(Ey9uDyM)v53Yo&OqP+CP^!c$vnc*UC5_W;ZKe z9wXY@&-!i#lVj1JF~Pn^`}_48Tg%o6evRZ_mutxy!K{(oYx&$yQtbj_WpB*bo4WOv zGOurfMPxhV(OGR^~Ozn4H7G!hz#`EOz6m=(ptv_*nGXt<0OE zl%`MKuGi}^-k;a==&8t^2X`v-q)+@(`g}b7Wbrpz_PUz)uR1b?lwL2ZI3BAy;xIaf z@Td-@uP5g_;200ETBPW&_<9_1Fw|Z5ey(c?WNGAtlLpWmQ%b+>F288fu>l(lx3@kp+d>gUXDCaaV} zRh>mB$Oe5pSz8~;d$M1fE^$Ul?RUg?+#`g77JOH{fIE}6YX9}-8}EI; z611iA%kWLHmc3nXr_uM(pNl)kjUc19**<&Oj(Q(@FNF8OCG_?iJ~~jyJ2LyIPXIo$ zKbz+EyC{#y+_v z_IYD$6N@Pxwb&fvo1)h;-}$g719PYlFvc=%DwFlR*Wt>Bj3}8~6rYP;r+qFEBZ7nR zR=pmNPc$5*dUCJBc@1KxdOEEL=#uxN*If93%71%~hP7iH6)b_{O3GHbgb`oi{FNaK z8nwQW-kgXh`&;>n+fnUj?^AD6fi3lY=q;*SHQtA~mcJkf@PS0_h8x3@cz&b5MX#T+ zwe60TgkB@(xDUpKV?T`NGSA4@jeC<(1MviZzg}w(#ok!vlIxJS>~-~_*!gc|Z1Fzk z={R2r46e7YKF8|C#Ga2{BICqH4(Mp=NwjjcN5Pn~%bvK5x9v3=s1aBp8&%GfVJtj{ z2C)X#@4k5Z>POFUTE>}Sf8N{qtL)3Cq7VE81-wJA#WB-WbL&r~U%;;OYGAxsl;bUL z%NxeLU>~VobE71~p&v~?oMm9TlwOMuWn6&*9SMd6UI!YC{Suy>w%1#Ly4ZJpwK3%M z7@MwGdpnDnT|S)xGI|XiWdMCa-2<%V>uHXCB<3FNRaP$pp~33Ze}RC*>jI93 z{{g-U#%{aS%daOiV_hBKhh5pc*+^l9r;I=R-xE`5k(2Inz1Qlk9O(pR3#`C=jm}T7w%5=7ILy!3w%_5s zts^7$#C}hAlv?{X-?>dc;ZHu0chL8EB&Z#7Jx7#PCG=4e#sj>u@;37)_g>}02{Fp2 zTJ@2--^O%j(wkTE%vinN`-`ZC(q7grdmj#ySb!5x~P+uXRKEO_yg#=_XfDiN)G{%`s zZ&a&0U4^&Wt$Ow9!9AgF+baOzjdyKgT%(azbsrVaG>N_x@K3PhmK(w|OT48aQKyn0 zt9(@*fwFqynuDyt+N6WrWq%O9kVlM zfkb;nS+!a!d2F8_SyWhG^bLOLvx}I?#*}%8Urp};?g6{rp1f&(uU^9sWF+xf)1 zb6sY+5V5t6D$9h}>w0in#D=9!%iE7&qnSgr%N`S9B2d5x^n);(L_L-HQP>TN3t zc^ASxdR-Lh^=YULMOG5;ORs-ReW^#M*Gty3{EjT^VXdU9hb#*sYXdxGRA8wUsyqr- z(c7Q#z^ZzI(twBClV|hu8hG}Dq0JF9v3LYN8o-dvM{EMcK$F*prb$ zEz?)B^CE(ex;IMiEp9D+O^?~Cs77PCm;LJ4tUBxqf)#a=G&e$R>AIW>(^h!Sj_jI* z-rMZ&Nr+e(%b##$G21(qAz}WcVVKC`K*fw@Z?TLC=!t#$JJDst3}aj7g+7pH02g!( z#TtJqo(8ZDp!CpReSeF%Y$SW#^{Cx^p4%c1m8*!{ew4V$@Ozdkf!rKqgqvTAd@7t4 z_~YRBT5ozCg&e$<%ZYxoweKxHDA`z5m+x!&~=p zlUB1M%7E4Y>jQgbeg>Z0M^1SxHQMy&_S%|zJ#Wi2az0+#ww}S>f_8nV<#3%Gb^9yP zYg-i@CI-;F5ZMjP*k1 z<(qflBhu?+)!y4NeY8wdoja@~yph+2GDgSkt7@^;iTIP5=J}K18CzT6tEe+~8B7C5 z8OX-e`Y~(G7@m3Wz4g2gjOB?^uyT9^k-7c+0y#&OEz?PR6VssF2d0Pf*8cvz&Uw#G zABBk^#N1ENqNy{H7UK8RhdfeefFAF zwR8Wm*Qu(VWk#X$xYMdW56Ls4SX8T#*OB0vXXj@zRGEL9-=nhRv-UdY+|S(KHICcg zj77X_C>>muPUx?_>>;dI&<@~V|xbG`!a0W>I|;>=>k} zJfmazYhJipMzuXG9(Jt4@=Gd-Ca1Td*gN9c;VkCWQ-r}ct{D*)2al4fp69XX?deh$ zcaD91pGMC33wfViL8kU63y0ka$hn@(Vs`6m@tUH$PSZAu=l$g1*;mW!~|DZFL zuc@O17Ts3Y_wp8csv8(o@U(_qvm8fTC9p7>b5|o*EVr@CQD(V|sMN){Tkm6@56e%? z?XW6!u2_zuubL6#nrj=&P+U5*$9mE4<8NeMfV0`@1-=HY?!jdAT4yrm?_sNXE~)n( zPh>~IX-J6DAQk5-^gZe|bbgMpp$x$KFvr*r@CAvP$$rCzJ-OG|%bsDtb0cAW*Plwj@+Gm0<*K>%h??D))89aYtp^gJ0nU*1*f^9(gXKZVs{^{Im?oa_J*H_ z!LlWn>!Voqiy@$-;6R~K@j&KPVsZ<`OPMAcf%fzD2Lx$!!jzd z3fJCs5__KCndL){E%V*JEGu&DO%g08a{0^`mi0LL2XntEdkNs`x@cql=`rj~DECq7 zXoB5=!p@z^*@{=oWg>FBC4a!0qS6TaD>59hzahH#e5+@@j10kt%w*0-!XgZy5$kx& zQNmBnVqUH{@1DaP`}L8*+zx{|j{5faOXue2r~iB>z9;g>?uqAs-QR4FpM?S(?H5y> z8xWaa%1@iG$=l-7;e>}5JHM7ch!4)DC#t`%=fvR2dcKw+cW?hx^CnNW`dp1AV6hJ5 zy?^`(o{daxWf8VH-um8n_M0iDIo|S{1OIt8MH1W9vpe!!_{@4=iDqPjAyJQbn=^o@ z33~TTa4^)3z1ivv;OU6`xB14vr*N78=KjqTId1p)Ur+HnP668HTYo*RFW?85i#?eW^`dZg$;&P8_2|LbmPcOg`-4dXppDyH19++;m0-`| e=WO@so1E0R&7RG31h@I@(Ys&sWWzKN@BKd>F!6-| literal 0 HcmV?d00001 diff --git a/Code/client/ModCompat/BehaviorOrig.Skyrim b/Code/client/ModCompat/BehaviorOrig.Skyrim new file mode 100644 index 0000000000000000000000000000000000000000..eaeda4b95197d729a1498fefd83403fc8208dee1 GIT binary patch literal 226116 zcmeHw?{if-lBGXS#QqO_n(dC5-EOEKK=1ZO098~mMK!g+c183T2gZha0~p3OMb}Ks zzrMS9ZaSTkuFlbY#yrFDf&l;EDX*@SN@bptO8vk8`-h!B>|ELTX6J$Z`xpE7v3>p4 ze!gel{gZwF|cEM(0>1T`s5Y+{|DCM+nxWi^A9HN4`*Mm z*e8D3S?wH~9RK&p&Y^w(WM_ZpmHp<#{v6o%FL!>k-|pLQj_f!1{>jc8`*XDO+P-^g zGSHK~owxSC_}puga$w)Rn`HcA-<{ZJ@S8pR_jvl$>z!xz^U6MnXW-w})b4oazn}Fl z`s@8f`;|#QuxCbpPpr+Asjr9jf9UhSP0w+;N7kd`Q@Qahd_H>f$lm{<{rru!`PDx8 zU#F4SGx^7pl&2;g&nw^V-Sj`%GrTFr=!&&@Z9VW_9@^Wzw()sovf|DBx%k<8e`wFc z_Xj(Fx3PRZJri<%ch*0Q)-NXE*XbRO?EikXpN{OOCpMBV?SIi{Jo#k$?cvUI`~IKK z#_x)a>+9(m|1ymPp62h4nZ%P1?f0)v<-WA4Q;li%7qoR}oHThTAq z_1C5u(A?DWHzx0?$;IceGTb)9Zoqy;YqW4{5=I8tS{o{?s4nGkWsQzPd%jdwS1fq_8&exqAGve=nye zoJ=zWyW{Q96MTo!#hSra>_@L`)X@WsKUSmvkK3K+_Iu1C^y8tu9agEo5qkC0nGCe? z-OV-F*8^r9@(!l?!c*$eM33Gkdc zDfkTjq_p@AzP^}x{LEUyQlTHvZ=btA+yDRZbU!NFL_4=-&~xAWuk4`3RoY^;^T@{c z&_?H;%_^RA-`*WFfH|wBT%%GR*=WR`jpuzqKY7n);*rUHVwMZG6k`Lc>iztZw%fBE z!)^5&^SrQM;W=N?&*M1{O+MZPR;YZ+*R<7MM~}WaooCN zc+aalTvt-#ur5=}T`SzjaT#2T?%H$FlXhiX-QgO9xxwe5-7hMAxH{0I+tbsqOQxn? z-QilaGT+AcqI_PgL#{g*7oWcaX`NDL-5;)7rR3-b*QxT;%1YL==W?$JZF_7Qa%3Zj zcCc!&{Fvu!LfcYTqIHf@wC0)?ZN9N*!Kd>b+MmgFD_6rU)0C%Yz2utp*faw>^!&}V zeR?$QjIgueQ+eOGX1y}az^5PBx_M@C>61w(V- zT$@^1cI z2E2L1g@mFXc}Do%Qi#T6K@ji^Cog&uumDKX(2{6$ALw;f+1DHt<7%<6y*qIAE=O zZR55({RV3Zk#P8l@MFHR|Nq*2%|Dvg2yf%&^!YDres0+J@UX6)KCz4_9NWBe_B7yi zhz79Y%gh?>#*wiW=3lhPboF=A8meIoA+&OVP!GKwHE(s zV*$hisDa~4m!CB(X`qw;!1Zldr1Xyb+`7gpL={}cNP&uiJ* zaNT@t`z-7Zw9+vb*bjdjmj;~WJ9}?n4R`|P(Y;-GRR1>F6|{lHhR=Zi->)=0umpc% zUzVdlj#%Pfa1kX!2rWXd;Hms}`h3{E8q0}!iYMah=4Zw+z;X;-?|Z$&u7UU#(FJrf@_cIVX!1vDx-fam-r!txwV@=#w&!;~!?Sm)m&*i>( zdJz6e?rU=&!5N^K<@ox-*0sX3xNm}X=fS6XC|K)>WbevY-rt@3w&iE%aewMvZ_c@| zi}$=`Itx#%hlnYBYH#xTfuB7#jraDjVu2PaoGP^>up)ndg-pR~dNna(Cj}<!Kc8jJezDcsAFkx#rG&dxcr$8Yxkas{-p}sK-@-axTFuxh}c2 z4&0bwj|ziYhVLpwYR{t2`?eqN&amBUB63>UD!5~Fi8m;<;+lw?_RdhmXnB9KwxNmF zM7+PUKEg7e*b0I_fE83mFV_Z$=laMLbiap_UK1LGHa|@k93FmYCF(KaHmlZ%`5N$b zbIsxvw&M3W5B5 zVXN+j{T6?2m?i=_n0qvviw+-|?)CkYWuEWn5f!RYdjI%@OaIuS!1wQI`0bmE{&=6a zQQzf6eSAh()D~J3HW^4n#xZTPcn zS7yxgMZ|ddX2B0aZ%RLViKhgjh7EGDqU{y3&$|%{kngvv`VJU%g zuvdjI4+-bzU{%}*$xAp`6*)r2c{o@VS3>4;4pv2*kkr=!_@RpFRB>o2wbY8SOm0CT za~TJF%@{Mb!?+a0nd8223!D2}jWU6wV^3a+L2w&8Mp0DEIzrXvk!yHIFAN()jD2i+ z>~B7|;BNQ9QnL3))X$L5FNEDiJKw1T0V+`fmHmL03|;s_AR&7bx{GXym$o+I&A3is z-%Gxk;Zt7>5Ru#VG-q%8{T>+p82c%rd^WD$+sNj0_6K|D7s6upvno~A!QO;p9d?je zA0L%>kgKIe?p4kKv@JYPaI`>@%XwFs2f*sU`FrLJMx@k&=&$znTF;Q%r9IP5aQMhX z$6j&Y=FQIw#FMz@z~4fqv7_AZp^i+NbF#tShZJs&!c#=n5&DpRU$o`g!?3e2h4!qb z^#ODe%p!Ptf6iBiJuxj^84~GCT01wD&J`S-KY<$Ba>7da(g3A@v4_ity<<649G=cQ>q zM#kBlGLHI6>P|*oyHlJC?e9g2Ukhz2{fpXj<-7XsX%>l}6@i8PdWO~Jj#oZmnFrI8 z&v(Nm-b_y-XQ9d-FCPDSzpRw9>g1T{a%AJia1a9;{PXSm6Dbd#oyC zFNCedc^|B|I)+3B7PDp9*YnEeD+{vGGvB*P9{`zPsz-y>) zoU-#txOygmTWR#1_u<-^1idD>gfGq{@HMbE@n6p;Uj<$n^yT=J$Blg1>%wxouZg^; zgUV+pJ&)_ce%D-jpn8v{jG0$mD|cPQDx77yF0`}P3hYqm0N1_Ml(!5I0vd$1(s~l$ zotOr}V{;Fr94&BDti_&LWT0uti%MS){1MKM!X6<5Qn%)ruwcVj+tRzdZ)-pH${WHH zsOJ{e?{L+Vz!4e>*448B96T|u$_J)v22&`>lOjo&}^ojS&V_) z#N%mX`&r*Nh2?x;UIB93SWB+6X(xNR>Nka!ww`oKsxf=yOK}~=8z%z6-T*R|YN*>c zwR1t*c{Ft-Q|T;_Aj~jywcKUU7w);%y53*GIIWB0& z_7yli-r;Ne`AgGL{Mlq4NBAla%?9)s$j>=@V>~v9I@dc@F_L-NnHm?>zhK%wTzp~EL(^Xi|5U-R^I7F7O3Y8YC0E=q}sx6D2F@%kfyQ%i^>kL@dv zw*6@(1&XaQESAg5F;tlssNeywIMxN%m;RG|Tp!t}0__f#LuFLNEcZt?`oVQ;G&dn( ztY`fmv~#O85M$ixx5|}>(W)!LsLTk|146tB@5xVK&UMG%Smi?W=dRS~kil(J+xK2; zZl9Ji`&|F_>^v*ZTLKAlj5}+`sB8u>afdsoNQV^{HdyE0_dd_{X?_|Zdm7`)wW#i0 zyOLD40&96^dRM${@;EAUp`F=&dv4=^2;VX-JuzMFonsnjF2D+c$;WyMTcolU>Kr^D zW0kFd95~e6LoXvQ!=L5vo~tWl@m&ya8%S(?np-O%Epx2itEofXGdi+a5m^mfp?(Q`SamWfq;1$ zcWoa;EfG}X$i1rd0aay%(pvYkH-Ubz=a)!Mj6Jtq<)?Q|1Kb+`3y9q@eb|u1?HHGY z5&5lJ+d2y(wYKgNP*cwzDec5p0&spVAj3i?2pV}%eYbc@S2GcpLChRw0iMcpWpYjuCpjD9pL}@sNveUtwcreUyKm~ughSgOM(z2|4e#Z)`Ju;WT(`Db%2O}-)CE}kchb3wp^Pqo?yWrTT9QbKm~Fj=r@Jk$tR|t8Ljw!gW3wmQ?7w~z-?P# zwH&SOJ+t&}(VFW~ul0QWK!(<%h@xE=qH2V{J6da9s#`y_vG`Kt|M{u zfomBwvy{<`R2PR|haEoRi(Sj8$~qJI3~t|+ zKBKGz%bvn@cdltFMUe=F6=pcRV;l@zD>-8IxD(VYT5gg%U94??j5r* zhi97RS-`NR`)2*IZ@#j>kyC{k;HxcGYVK7n3XAr9rD3-N?)evc^1Cx^@bT0K>_GXx zYON_5DdA$*-J{9ZZjo2K?M1IW{v^KsVg!K)9oU{6qo5fU$B5i__*>D2uZ$86NzWxC zkFZnue7OOeD3{* z41cHI?yt|G;&f8r8K@$hW6br{bG6a$vV~%Bd>nCx_+U|`XfVTEkK0+nO!q5pw;HX^ zq(W+9do|jXya{Y4PVmFqi&F&Xt=4VC+Bik<(rl$y-(IdsiXVdSycO5s`Cc+dogsm1Z(5+-kNPsWjUHLFzC5kjK1X0Rez4iXD#dz7PCT%M zSgWy46w_4lJ!MZ@x#`EJRIdF@YVb>(K*(a{!`Ak%0W(>ej)4KWf z%*H6*YMDees@ZRD-{FsY6+a9?{%u@2=d><1FWYmn zJ*Ghf?e+BF9|P3|GYPh1vw7L`Y{bty7rQqe*sIsgzn;sv{G99a_h}P(*7M$NbE`L% zTRk89PbHt)&qyOf4Ic64GO70_?|A)c<=O78?ZSw1V;5%VdbX(Rn{c0N9>w`HxVHtb zA5r`K7Be0fx41O-iSU+rehhhIh*%J>l()OB6B+pXaE}M?gN!vix0hGP{T+B-;4$FE z3yE8>~``fuEKM>|B1fgaqlHwRV%&2;p=_1(DMw6fqa zjihm%g0yGWFGTfq?m^olu4AQ)GOweRz;&;bpz6PI?Sq8#=ev!n+aZ}7Ta6*6P@UbV`QF$a+&4@cp>Q#L9$pQw@)kE$dEICS{lY$(Rx!q%`-0xTIC12-cC_NVXFg%h zohZBuPlMl9`-}?VLJMHa&ey_<_&FzNXv-+fv8_DM=;@~s%mzRrx{VTs8x0}f3m;3kG9Hyj(8K1p^tjBQM;L{PWZK8wQiXPc_j1m^xoJL zq0#fFbI-}GN!TyuO{h#|ctG%w;y?RuNCnTXW6I*7bg`GNQ9hJh5%7bSd7k zpF^f9wauT)WN>ShGJq=NtpL6TRi1RVjJNJfXm`GgWIJ#REx7SNPW5M;?ZBSkcMKtG z7Cz}FxsKXX`h`Pdox?VQ3alYPscuu44 z*OtxL44YAp`lrNWcpfACjxCRI#n3_Kzj4eNe$c8=Pq%;9X;Lxxm#Fvn-y;wZ#_j0`EnpFg=o zhE%>ULxvRQukWo;dA&=KA%*-eLxwa9Fh+(n=Kr0=QoUP!74|>6*+g*w-&&luYjIof za%!L0wO!fuPH_Y)TU{ZghZ!lBpln-KMOO^LxQ6?jFStk)1E@J{GO#zCpZEN8pcpqS zYZJBD@&B7fG17v6?kGk%66ZrPQo_f8Vyxer&7c_BuPutPITRyD{nJ4)aBl^2R*;c_ zn!UgYf3-abxZ&ndjb(eD?{_>WZ|{uvsyY9N2w5~45mowz-hy)*?I+(SQss+(Mh46N>1jD+nL1zjz|eru5RP<=J$Qw6VE*E?oF~szAt{i#PM#^ZijWkeU+Vz8LY-%-bv~q)S}~TX zb$@A|sn+?Wd8Se>2vXISu%!FOtn zFL4b;JKtv`JH_o>JdtZ5S~84NVKm!&hQm6?SKKu1wNKd0DhL%G7La0g&$cu41lFbKiZAbgQh*j8S?>x2lYWN8AR+V%S;=W_)ymqsr}UrIoiX z_C^-jV@rEh%4#i+&h*TegQcm1c)PE~w|4J!n4UfGqh1|Av+Bmyzj`@2YNle2U6vfF1ZI%)!Nnf zK&q@#NISZ6#NwZv8zr{mWC%%$rbm0M}Kp=D5!CyMOPPHG5|x;I~=!tO)q4Wfrzv|5_rC zSL?MKHd0Gdwi2`3yQ%ZWAV=Q)!ZPyG^?UD5y8_NXChJ+=AgwC-*6-Z6=;ghjs=jYT z9LQ~Rl+0Jqyq@nxvY*Hr@@lQv+u@hO%L7x7`+A{`xO;Zf{HJ0VK5sr$kIZ@aQ6=&6 z`O=H%-6r@`)z2-Tx+y+Y&BCX`uf{I2WmtclJpS}7eLv*!Z2L)$lVIQ0bqsWD>TTU~ zh^pfmPkBGN?=?qhyao5I0`p=mxgT{hs1(6H{86qo_v?Ygz*F|OQq{dV(!XU`{T_L) zMc~8Asz9(Cqe?zp!#KOv@}peWN*N`W)=JyaTEnc3o_wq;nI@dBF&oGB3Y7#*%tHA2Md;HgY_XHtLx;OxEQ7-d}& zl>yIgBT_leSOc*N-1`A#FTP-)Wi3) z+7I{TdhLQwQ2c7IUGNEtOKtgtn$cA?aB7RoFnP_UMlM0zt=2}8%URU^nlCY6&7rdM zL(ADx=LLE;XE{@llvFdkietrIH|A)SZsu9Unxo~|-j-p-sSS@*aH5g> zs-FVG%2`pKeOFtYP4lT>|8bu5rj0$=RGgQ^&Wj!VhW(5G-Q;Ofj0WT6?6m>t}nTxFg@dVYa_vQNU_-twwo z?zk_%81&N8kXZF(6sHz zRovbhnPiScm3KdHPp;eU;Y(dpCNtG0YtQ#8G@|FEb`GaTJHzYZsX~>a1$7U1Z{@6RPdrmOE?9`*It) zjQ8bn=$OM@YBk+{$4S!OTGkwCYGu?9@Kf?yqC)>liD9X{XRib$~O@O3aAg9>ldLwXUuqs%||(uS;H_tzxHc zJsMXJRd*fX$+ss4r#;oCZaG3LuPXbSY0=Ty%yLco$#n3;+6$H{B|e!iZ@kcpl&QeJDk)#pl!L0!A(hi zLwu_p>SiKXYx~cY2lBS4L+sX50?-PtK{jxVTr!ZDnexKS!~O zD~o5ow}`Fnn>wY5dFj<-RJRqC_*e9bYfSlR+%lCOKyPnScNK9-IZ9=us(8g3{cm?M zb$8LK(tlX@d!}gz#)r?xo$qV>1}}AP6SH;4Gy}TrZyLK)%mcSW^R~G=dTYfw-m^9E zjjab{PxxBGjTG%0tD3p<=ZCy_I=5G7iyp+g=X2+EOVyo4kdwOd{bZTr>1tn#)fmsO zM_t`o#CsmkJ`3j*;qe4wd-GsTz#DDJv_y1aC#;1<#-miQRwGS({6)Zt=y4a z&q4y%FK4BpnXQ#pRde@t{%TK!E**5*@f~k|dtS=%zN*@}kL`&#!v_mg-d%x;W=px{ zv}0iPfRCl8r)uYNE9TZade8SmE&-PO#Qs2UZteWt{tand%eXY${EU4UH{ZXrSvorN zWHob{dRN=~?+thR{;Wq_7kQ6Le@JneBMH6>y|Y>K@loeSxvXnD-`U8dJtlo^b-ZIeJ+v`yZ)=HnU-4P$+teVr+Ve7uvDsAF0Z4lD&^KyrslPAFSbf1 zGDx7iU>(pa+{J>Z9oz$$O2n3%J=K-_RExNM-fV*!mpK-Lz3_=4N54!y1L|iXMt@`4 zi+!=)=h|_;e5QfF>(ah$f@k2p+_DUtVj1`xd^#KhG82xbJ3kK1KLbX!Z#(`b?;OnC zwTE$V{4d+J2r7$8vPGPL_C1{M;B3$4kx%$O@C)N+JAVrI30p*kM>DlY!Eibrzc6-$ zV=s80GQw@+Rqh48n>@!ilV6-~Sm(R&2)WFToL6*LjDkMz#G_=iD{DXAvNuPh4JO2+ zmA2+0*PB)rGlCCtvvEYWXnjjt+as=HrHqHR=2zAq#Ne$2u6v~fRY#I*A0&8e z3_tv?S((=s3xOMi&3S3R@rYs1`iIri_Kj;PB*SV!;*nwJZ_M)m8*pge{>r2spL*+x zt$>X4oOeRL46`_pxlSEPZtWncuLJPE^w}h>^C7j=im^-(ccroM|S&ZXTeON>kLD=Wj1z?U)RT{A4f_W`d#{Qi8h zfq@OFs+eCI~nDo&-(ZlanEvq5-@BcQ!Zg%O(qZw=AVYQn5CFIAoC!cOCUCbTKW zLGQirkb2ez)p^*P;W^M%?78V5#`CxidH;}?0{^9~;;Oile8QXs`^u0e)l2w*_1PT7 zm!N+@2(f#enD2~H2gd;Ygnx;Chd-h?l$;0TTEQ|QBLLPN-cn?_EB3@k7`|R0)9TC? zKD~GP6!-#|)3-%WwO{9cGVi6X_NO|K8lE%9iYXxt?X)_C2|FWt;i?aoglp*RhZ?`Ym^K&0=6&)agFWW3bbG zbC%+w5qaePV|TzURnQ;!4}Y}3INgHX1{Q0xm^?$MK5s;xkIH%QcqVNr;vMJFel?xP zs<~ocVIhH#I_m%Do!?D+A@)W5&SQ)*Q}Dh$+XNQR`nW~nH-*Hr8TeFicp%s>ZDnA^ zAX;&6$bV`XvQMq1+8E8?-uI(3Kg)eG?h7ThU&n#oj^j)WC*cuUKZfHT&&qPObY?yG zczA9r_jpEV0{42BXKQlLy2U^cftEL|E94$+@%diFdR4?|I!0FK0C={vIs?$YW9b!M z6|wv}InwGJK1g|Ls&ScRpJGJ}vk!lL+b&ek=dU;N2=qZ+bS z*waTfh_0DW&DuiOZrk24=M&Wlf>qJR(WAt26ylw>x{P{U!lA9pz=IU>?LD63VhZst zqor>xBCpXFg?0nAVATy3*6r8`_@cKHqH@c|S+RWz`)*}n2O3G^dmf}cvwn@(K81vr zGD=>jX4DiCUP|C>pF+bSfwO&@>r-esy;dI4Lx~oZVd; z&5W~pae~6*M{KY{;xUuzM4!UteLn?*0KUUVx@JAN*9TmkWt*#W3B7i~C@Mt0*DkWn z^%(?)cq$a0-OQ(P_a!;m%kQQtH45ybp9U(c_bmZ z{Wc1zzi0c*iDBb^wf9GkbM3dz(fYtiaR(-zg4SU}6D9DGQ1#GY3m=-du{%2lHa|^p zkqiO6U{nc$PXK=&Ud;9BXG9f$ocMvw-o#R_zY%iwIWq?9jT8K^^^p2?HHp4uuGbf)87XefRUj3fg0C*LM5w_<7V(-T75sWp^o?aivTM}!!N5DA- z%vPQ>1b_5=vfzkWkS!Fx6^rFqbjn!Ic9pS zFF#gQ@4K{jn}|+TKezGdrs7dG3!h2^`rU-2!smTx-UxW`Pdx`N_hI*8IQ!2cOU`>P z^O1REn%P9Px8^F<66##D&KCD^~SwP z6_H}}#!NAtoC?Ho4FNqTJ{xAVS(s_eQF zQHoD5!Fds~k9qr!}9q{@&R%ZVyAE=y(3)xO?*L_z}BJoF~_L(d?4 zJiX_kz1vHB(>RqEvUJR$Z**3fbQ~L0Idt5DMt@b*0X+x~CbOJSf0A)xU{ef4{kxi~UXty4+$+f7JwFKGZ8U|?*$17xWgxiLU62q$FMs-%X>;*?Q zM+oivAe&rQ(YK7`c(v0Ja(g~xlWQ^hwGOhWwL0dn)`1c7H$rnmYN-`tnOgUkBAZ(0 zmsUIF7B=^{np;!I>@xOHp|azQOpV4eyX!Vv;j(*E9`3REDE{ViNg;#ltm8xdniC3- zbv&Wu-%4~zp|NOLX3o~_xTbk-)X!$^Uz&Z4H{&{0BStJISe3KciKkLqOd>Wn36XE@qw`%_wj zHs3(usB<5Dj;kv~)z|l&zfh-<_jdkbGsi5g!c%+fL9i7HOYOA_wnCw%y>`J?D8%%g z>FZ0=`lwF{PXXHNbE(cFb6i`UNUm2Z5MrDmo^xNz&m@CYcur(+pR4Xi>@)qI@VKIu z0!D3bvUYc-QS3`wYQ<_>)R)Eg!?tJ2t}Q*mylX1~b_^A3`~BgTt?myp++ZvFQuv-( zOF?Vc*`5@2j=7fN?}YJTk~mgUOM=(&%KjjS&u@czX1{qmVGX{X)G6m$R*p3G0Gzf4 zOB_uKjl4GD~PN{Mmjnu*;7KGMFmEqA!m-@Rd+4}W_4TK7$B!sde^Vr^=l zm(A4;!Kv?AjgYL|i#&peF8qyA2bVp))>pUWxD6C1se3CDHFlTDDp#bIxYU-0z0uOR zW@0r&TaR3ypRPqPd;G1APj#x+0#@ zQZ4iHS<;K?-zGRx-P0{Yx+#WK&%>v}kA82y0XUQ=r}rnq+l2=Lzxnb`th7EF-_hJd zV;Cm)ve1rsbQ5*}sfjTkL!$bpvRcAta?IIpm>|(E7V6d7~#Ec$N zocY5sidhZufnmUI0rk0#xkul-Igz6V(A)7TKE)_(^%p{t{0kJ1W(dyqdlZYhLfTu zd2P!SuZaERwzW7uL&y}1h);)i5^uq^WX~#F;zl1-MsN2i%^S8=Y*J12IfTi~jIk%RhbBv>`srb;dvY!`Uaf zzwDp9fA&eP5&p@CXP@M{;GcY4j2O2GY_9wr71QTWxn=9(>1m%7!v|05SG&0zD|@aP z@icB1_KbH2CjDZHy5^ds?)i%hiID_8_sHrxe;%8vMGVR3$w5=KiCrdc#6GawB*79n za{&%F?i?#`#8gZlWIZz(n6;BLTfSaC8g9~K5m#USI+vWfAn49iX&|0 z!Pg$k<2DZRj%;?odd5Dv-qnp|q`6Ek4m0MrcH_R5l zi}t!W3+GaoorqMd;_^3#&)?C{vPr}VlK`Mq4Jt*xL^1*(w zTr2blc~bjR{Tg`pVSC)xD+cqn?cb%XhR3^aTJdbMWVjs;PlZLQbD0&Vxl|_Z-fg8S z4>W>82=3=*527vC`1Fq3R*LOJ zyo6})vFVy;557G0bmn|#TE;nsIFGV$!z`PfytxD@ke^8DN#I&}*ILDGdnv6QYgDl3 zeZYGCW!l?H{k3~&3lv(e^W@p#p=wqn!4>`JOa?8$5-3HmP^1#XkRN$F<+>X0FoSS#L<-+TTjZr*eIF zpCg}|ZMYR}pEF;h=qHc-ewy~ga*ZKkgBOHa8pv>u>@i9G%S+1jbf4E+bJb-@RxZaNB&HKjn8t?hku!+Bz-n=`* zVISLXffmNRD+Z_R&G**s#H1YV{ENjKu%4)<7rtq|HWa%vlId%F{+?s~Zu`LX8LKID z($`VVse#SqHgw*)y-f-2xemuElN`O63&s7wLw2vNUiqVQV`ZBjzKp(deZ;$#65^Z! zGJcPWeN$EUTIvU7lwaL7NGdBIFajo^X&foOga*g%2U~_sc6}#mve<1C+ef4(tNjvVXdb@|D z9rppe9sI@q8@76Nkr~_Ar;v>UoCAInc5~nj*nfby0G;}3qt&h2yfAqCusFRu#m_l= zd%bZ2n!es0dF#l(?5yq&(bo^3;k{0;x7prL&G!I*;^(oEUlTJFh%UauQaFS0)PDNV zS`Sa!pXik~=OP;`?~MS;U5qPPH+-+jb|98Gm86IoO#x z#%d*SpD>=8D2@Ap+y{)YU@dtJ6Plc3Q=il1p5V4R7T2HPKRlwE`{pd7Lc48sEUt4H zpJ!%UVE4Awv9M>kWl$I=#%x<1>tM?14u@{gkR>eQ*0%c=J8dnsb%3InN zs673;Pp&t-s+5j;Q~#pMOaHBShstTdN50-L_nE#uL+U?o&U4B5oQL%p%PqC*A9sF# ziUjSOJ|XsmzwPW#Xy!%V?^Al`OgEPHF_^PAwn~6BVfFl};?wGN^9TvuzuF#;6Fi@kI&j;HK(*# z+xS{?c7Y@P=VdZEZo^oqj61fBX4u;YTgEw>0BOPV)n~I?E|p^mr3~O`@Q{(I-b&y&LMcJ9jhtPF zg!9)hP*t)Z8IkSLgdy|0cvQVC$SBVdV{gF;sJoNYS5rLUUQs<}>U;-euEREJt?ugp ze3%!LuZHu#Jx)*Sd`K;|Vk}eZ{wo{Fah-$FEkR4!My~aoZRC2slx^gCKF(!V)w;O# z433uP6feJvhofRZ>cI@aheM8e&HZr=MLS2``)niELbNP-iTa6L)7-0zrva0EZfgOV z|8H&G2AeYCId4yE2e#0kTh=fbbDe=f=Gk*qxvPJ-j;ho(Vh{D1ieL}_I$6ixY<^x& z9E59TZP0^b8!@ld0xutZk2&XvYq_(->w9&U6Fsj;sF=}~ZNU4d?yBlzZOgP6boj(yz_d_G5xN1#e%?%d@a z9ja0nyiPe@ewb=G26`0z=K6Jhb`n-#&e+U($&2Jka7GMT?4NS0W-*m_RfN6fbFhrmBZC5%=A_Z8!rK+C=AT=-hd=ZUDDwdAqKiTScewtwf?)Ly&t z53%z{U2K0lXBNG;+%JU34ByZ{rx*~90Y0!kM|JahJKu?d4JmQ75d*@x7p`gBlU}8FjPJK6y|}j2m|E@6V}EWdjVbnH z&osR}E3)~sUg33eu88l$3=LHL#>$Ym{y8!30glg!@tqS-D{Vr{O({NO?uqw!1imZc z*?k^?YnMhH)v2x?9v=9+I@i@}7x=q6%hhWa`1^-pDG+buy;e;76h~2duS>n3-P5cY zPh5U8onj&Vn-~9Of~qL;I4KJRgQP&I;$mIJ(Hll zwD2F7&x^0+qci#3e>=~tw9CGKmr&z6c=VL=BfPkPb(x2_GIuXYCF?AXY{r=USgnW>vrnx6}dZdm==iEzp zJTFY+ca7t&>uk2IwdS_1;S>CQx5Hv~&v%Sk@7 z-yd$9YdLX(tuKXZc`XI4VO{!CxK7tn)al(DqPlJ^r95%d?+>@LJxSmgfTPxDch$Wn zkTO2ItL`{ilJlePIMHW!ZwhTq#JHF1qwX|WnlYm8I2oU8RkxcsPOzG?BTEmzL<_)z z^Oc%ef%nbMhR>^RF7cCzdKbQ z#NIWM$Gw4-?fKEVKJSWmQ#Q1hKY=#fiyfbNMf;_8vTxzaQ?HQ5?PWcmo|TKrH@@$q zZL60TnF|6|1HD7khgcl9w<0eW`wh;}!kVEEo6H8OaT3ORe$E*oOGjw^tdM1rm*!oB z=X}wbAs5@r;Qc>bcF3~+ZZkwSlOeKfHa?{+5ya2%vVAB1#XOW>Ew)8oBXm2@yMD;i zv*{oD&c*!^hQ@JkV~(!+Gn79Oo_6Gf^0U0$yU2I?*~avx;qU%j?ptJw(gWbW#Iq@a z@Em&2Z}BH^e*t%`Bkln12BaW7h1N?5+xx;W6}0%#P=>h4o5%jiUM9*9B=yKN%zMUT zq<-7i79n{{_z}#*&bGBb6fL=K#LVQ#*BLGPKC<>6t2t_~@;*W@%bCM%DeNr~hupP! zL%uQcDzIjcZJlOr3)hsqr7FgR>qveUT93QCqYc-RoPjbz!mTp6-yXLlJ5CppmgrDl zQk~na&ZcIc>Zhx`42-ek!oN-Z_Wr6Yj3+i1&~a4!%=h*926|uLkfo~ZW`AS#Ts@uX z=mobmIB9S)t6UK6v`+oS`hDkgj<1QxCHq&;fx7c6b*Z;9Rn6OM`C!6aaZcG|@OUe( zLs%cl-(bh?opD5b!qytz6&UXe!=9kSvBuO*UfBlN^fT*&_f*~9m2Do{+dVfMo2~f% zl&x@TJD$R|g4BYIt_Jb;{@%gYbU5vpSgGRuq}0i7S4R)X@1MW z{0!EzD!1+X;`}PCZOn~22U=P$AVtW~d~N{Z}Fu&3s%)*gX68=44h?Cn01dFo4_3=MnV z?(FI`C^Q~@4IH^#Un)PsbCJT&&6C)pGoQH{zc;-NYo$(n#tw)bpv+KK84;!RZ*P=S z)o-)iEz{bkr<$Tpb7qV3j#k$&l?CyCrWKa0qXoB3h+K|MzkG$vTk`!Z^zxS3-G4cI zC%${FrqzNSsBf+H2~A%Eem>mK#E$HN%7h4=1`-$AqVgK*&(A$-Rf*Q0fgLXLQPla& zoB^~z^(RDWeQyI8C-W83Qj|KUPG@4x26OG}HTPH7BXvr1-n#ZTR2A8HDps*u>3AO3 zrakj3;XB}rWV@fL+XE&PG2ot2e+)bus=k3`Ib-f4dD~VCGM5nlWc&{l zlH-tQ^V)XSwt}R;2ikHZ@|#otBXztT2ejvyz{>jS9*ma2wGS(NnG7Dg_2vUB&#{!! z+Tm@uy<>75>vlVqqpJ4Fe0py@xwnpt`HZR_SXGC7p4P{4jt<_P`&+QK-|qaY&F0E_ z@W%el>Mp2C&Gip0ankKTwB{P<8S~JBN0W>v1@fzK@Tb#$ay0pqC#FH=$%OfsD@5Ga z+~1~Egi5T);=~(seFIwYZYNsYGW;U^4YcF>1&gyk`M`npwxg_cDpy!JPZ>jd?Qj+^ ztg6{Xt9#b#1M7Qlw3M!8KYA^-hQ+?Uvz`N7iA}-AlPd^X4@XJXz1{=n$|>} zK-`-w2~hEV%|N^n-*>Zhy9%=3T-&fy`i>J8ZEg!xMMijTZV3aYi*pX>wbD3f%=b3a z-&+sh^}Ie?@2WN<))8hMh%#&h>aSvLKAt=+)CP+BR(L+wJSOLnt$56PS|5eoGbtrn zh5d)`xp@B{Z4VkF$B?7!V9r~3;UyY?*4*y({3Y*M=#awfd#!yh&emE3oiRZ+r+d%2 zMpFW}dA;YSgnFk+d0aPp@-nkMC2(t4OUSmRPndGJmg0tEWYh$U0%ZS@=?e5Ss$ZoX zZZpvy_5}=$>&cv3hQGu0lvl@y=PTsj_k3V*VX?Cn*UC8anFwjN;`VTKD>UAdYvak} zjdK3RtCX?b1@rFKG*A-QWOy|#2L?G@1D9mlLju=8_~G!T`O~@9&07Kcb1Xk+fNPs- zKSxil+Bk5%o6G7;;Fb~l45YA%mv}zc!N=3;(^Xv*r?6)`6ZVrA_OI{MF@lO)!0Flp z)5Mc$<-a^#v&jRZ&)gn{#Veyu#V4c(5p~yZ*=(=OR?InNJeh0VyVG}tCy49^=uO>g zu629%Y3%EcLin0TwMt;evD@d^aqWvt{<-EvYsESsR{};DfxV^Wj!wfeL@tM9=E!i4%R&JC6E5{ z$z0#~iCv5{w`jE|=iX_#zS|yf`__|`8GlNq(!ROZKbHhgKE_CK9re08Y|bVlSCZ>v z-4;0)_1R>!<`%DP{jJ$b#L&IxbIaG0(C-D;PGI0irq8(BgJJONGa(@{XMk%d{CebF z1Zt!*i7=vEZ~cUOnZr@)MfQd3>+LDZK-3UcI$Lp#bWb1N=a1(3cnhF`+`~hp*ke7= zCfjq(gH6HBTkuekXMo#dAd%HlMsK(#h9%DI4!_f=L~|g4YvP{aU_I^!t+?*NuKB5F z>;u@#fJ^23^Zi%9zk9y5?}?sp9YhryU|Fa+{%-Qfo>~l=J>fdnvvBQL{BN5pFt9I7 z`Y+QgrDU#)eaSDaJtVmeE>9&y)C|8p?Z_#p5nAeZ(KFM z5>oiQBaUU`ftnYwV@0F<^Rd`0ev*es`ZEf3OcP-~8WpJ&W%kb=k=O(F?m$JA%W_Equ zkJ4}H>4?(QvTa7q(HnJgBKh0Q*@X^pjr6gowE&25o=57#>1gZ-ULZzk7KO5r-lq|~FBlDH=B*$PJQU+ml*Ac#_*dd!?ew@1UIX!qx&tu&tqT38c4p{@3P?56_E11>z`{5bh{tlpf$I8w#M&q)M*SQZN6F+U-K86mlM+#KR4<7T&yj{)I^Jn z{=!;iYo(u&Ih`7UthH>*brYUkp1Nb`Ep}I~q0lYoU!2l4=LPU2Je&{PJQwO zt+`(IFfJc|_}@7a+&;oLg^h4qJs*FrjcB<}O?SKrx09_j`}z%B-Rd}JQ(8{1D{8xPGoBDX1hW5x79 z3iu(Mk36*f2(p&lfU6iFNL{B6yJCmRvGTY$A_91L`W9Tp6_s+!d0Zk@uYgxJqDyYV z{d%DL9+`~$qxhuOcZ)s2BSD}SVG;Cs7TD#(CflWM&9xmXB(ijR_ln{iHP>^*o?ww( z&#}_xNFpR~s~q+;{G?&&fMZ{xOHwh&XiT3h=3HX zr|hjzYas9FgA8t;okNQ_I=!kG3&l9G=ZCbE!J{bbbg);jzaz|5u~NF0H1Y?zc0#vZ zuWBDhoub*Z5%x1ok#E;lcu))!j~&sE#7lAnxkkFI^z7jO{hh@2ilzF|JiT4>>izs! zMAE65*%z&m?mNNvf)++@E~4>c+uz`mV6Ib|(#`ZBouh55J}4&2E!LrFm7g{8ya3=l z@odFKVO@AmA`o?W9B7F%WrwG=AaITrIR*GlO5_$4Hn4xvz8$NS#&tHcjI$SIrUjSD zZ7kN}H}gpd2Y+kCIu(#@7cfL5c2ulo?@=CyJ3g^*CV zOiS$d@JYZczz)HF!V@d8V0C`S<=nLu6uCOyZ(vTXH+!-550O^^TZ2qlSV&~7!Y2oI zVa>mI6+fu9IWIM?)dHipRk|HW39M@~ofi8nU7ut+%P>(P0C ztUrc2hx~n)_HHxv4S7Gebq#UG*f|p9(SiSqIf=8e_=*v9&3$S=UA!*CJM(Awy?t|= z7QMk<9a*@n4q|-vKc;sHn~e8*YHx^Dh3NY{Z}HYVho{rJ-P>UO!t_XcQBAuC#oOcd zqwr*F4_5i?(W3Ro7-9|20CUo2FmwL~`zgG?lAZS*mHRKPugd)u*P>wRVMBY>xwzND zP(ALU;C*hHPGW^1=6-0S;W?fDR@_6;QIYbV6Pt#I6Kga5Rh4}Zt0%{_j!abs!Z>@L zd&!Bu#uz_3?Rog^IFrNl?B3+VF>TXX2FyG6`B51L+2@EE?oWCPuQEOUki)eqFphY0 ztmCp;k;)es#RKtlu4mxpbPkoOblB>59Z7TRGtYgktGel&fQVAz`@`P^4~+=G-&SP- zWQIbp6~O>STdrj_?t!=&KH8pnW3}alcb55U+-{Zf;_2LWxn;!u6gL+|8?IUXGm=1t z_)1cBNz{2v^bgjpSC>Sc$xKT#&ns5UeYWf2aEig_EQ^n*;_ngV9httt&+yfrK6|w0 z8pNMm=5r`MKX%?kNaCqnb2LV#PFmiwH+4=3+#K#-_Vqn~I@hRr&t*1RowvlkQs(O9 z&T!9GUc5iw5m%;}X`%BL48_%#ZF;!3K2Q1Gq#xjQYOAKsQDXhzN&D8e^cYHuI_KxZ ze+|FRN89m?GS0eUBM3<+h8BEj77H0qU{P=nP}ogWe8J5io`-~bfqqs96(c+&4ruD! z`~JhuA55BKWOzQZmf`WiCYSNT`})+MH-b<`7r%S&_@va0f86=~=_-Qm!Nhm0W zb@4YLl<%{&H=#`*^2UR*Ut0uVQwTsg>MU}P*$*UOCf!94HTAK=#L+rOV#yAOF^ zLB{R1*XjEp_qem&Hr_{+3tQ)7#{Fj&k#TPayLh>KFOT=ZIgBa*b00^e1uEi41R1Oc z!wWbjgpq__nBI7c7pRyYJ_G7L!-saS&JjMJ7Zvem?45Je$C_01e{X;rD4%+S8*r`4 zzNc3TysM8Ja9tbY20ZFtiW_i^8{-D*q(Hk)N-tN({t>VD>kF&cADQRA#u#p(BDcs+ zWViv3^T7c3>o|g^W081?4(uAsiuemzueH^$u?DSkjs%9)8=(NbicF*U-`8;9tM#06 zO@b~kZEltR={SMge#v&-LqDi-kQ`y{?YcLx*?IGMp7QuqqIYJ{rOGu54T0 z0jjd~$EPIbdHNTLM1W<${gF6d4-^950gu2bSe#r&ZUug~Ni3rD_CIGNq8^9!F`csg z(zrh&zKcd7&eNBOLO&b^QTA$!Kx_tqD98L$!5`qg>`h*w`?HANz&j#y5tZLIf0yDq zk7>_YhR`==3a zO5na*JQL$lGQ-?+i?LuWx#xB=i0HY$Hsb%epN27jw-+<4bc6fBk&ml#6vke-s*Er~ zS-AdyYe5D^?_8EbD9~=5Q&}osp_K(~(r2fQ0v{=D>9ol9!$G;;{r|AfJByGhW>4LFPIqytG!w{M9-Dzfhm= z;`S2#3#p}6jAe2Q3Yo~SU3RuhY1{IXT}%o?;uX5G46jpp7Gs=OVJ&0igX{3pb8IT_ zLSsZ+L(z_-QYzB|ElVW7M6*;?Yp=tD)0i(!i+x8^ITkg_!EzE+U2F8zGcsU10~JCA z(0DqxpHVf)kqWerHhj14XB8H}$C2ku%<#wt3 z^sZ@Y?a}xAUscxtH-{jjro+7qTe=BiFXyRuu3PTwf$PfbsJjytuaDJdY!4DPa0=r%`!BOUx9vPPGi2k$+BPaBEe|2)o?tiK;(POQ}~`Ul!jF zm8^Efs`}EkoIFq4?+@Q2YdKy?@Tfb^sv1Ep1$}_;+wY6g*o>=ptu6y@Pib%ValKJ> z2kO4~$iObL{w&pE?9Q+34^S3Anf1(mgDSSM*Qy&Zd%Z%u0~7+MyO5n1@22(Hck8lU zj+#qQbp@7Gh*uQ_9@zWt+syX)c6B>u;w?SqO;-{?RhoJ1A8*T}iKo+?VeX%pKXznN zUY*tIQnjgj?IKh1x~SpOYZuk9FQPVpt_*;z1k{s4wLj=nj(Cg|*DUN!qYPAC7oeYK zt7=i#-Y?TBT>;>(y)#ziJ*$gV)_e3f))fG9-Rw>otf-2G%B84ZKi{iVWq{u5cAKLm zF13YWm$fvG2(G5t^>_0a_W7x`QPly^%5|!YfAme8n2#gNXE`{_y2dEKHY*o1!ga77 z#r`f*dLZ*k02j$aLU&Lt0F{n_3nGs5+8o#kQ3ncDYBtG2wh;ou{6A-ga`_mo&t5K- zec8Az) zDf`K_K6kD99FodMU&?-RJs-25nmc87*Y`BdoC4K2Ha+$?pGyiETxWsI@CqW*^$9(_ZHVOj#*7$OZa+EusWd5XX?tL7 zTReqh8e{g8Tfkf`E&Iu}Wo080CyV;o;#^~vv7g*}mH3U1jN(eid?nYMb@)oIJ>d%n zZrXafiZNwqrQ$~!*Qxo@@TD2o$@QmQ$8)Ze>rp%vo|0!B_P9>2OTIFDTqoBbed0v1 zq&?g{?&MGv+k5Q-=T|IguU+8$>UP}`o69ZFdHjuCt7-|(Be|tf)%Nv#kGXusqT&rk zen?Lu*U|HhiLZjV_fm1JrTk^y*zUAbBg5D2pSt09*?6?Q<-4!T!yX^G9N^tC_s{{H z@`XqK$o_p}yDk{9x{~dvF1*j(d1Z4ejDBaV;5C0^^!VCB&V*ijCE8@x|#|C_dKjYkY2V4qJ;G01??bD;+lpC{`ABdc^xF zZkFGVsw%tpTIIcsikV%VGE$1=&>e=g zf8PA$cy!LgOpc^pJ|}rmJ=_EvIqK_{hujnoIhu)2hk-0}vzcYwvXJcDOz!BuA9EBT znZ&>_90kp+X&ysmTku`m)0#C0dBqUV?P*P>p@`+y<10D7*~(hNSMsO_(gNA3xvKNA zjU^V+O3?9k^g{8K981T0oS&~$6{#ROF$i@hpGKq3$5(O`75xIj@W###BY(y7dK0;+ zM;|$gN;_lpYaMuBZZV{mS}~TXb$^5t`W}E=Bh~vZa3=c)t&-VEaaF&<@&S^hsrf<#G$HloDA7h=QkOLs?KeW z&x`VXv$ZYG$LycgO;@aB#2?TO&Y^Pqlrc{a#Z>&H+nFBw%577N++sh^m#s1YY`03W=r!MvBR<31r zPoQaKU8$aBTle%O&N=qwaBZx673ZJ&Qn+T;QqUS+eqRdL&RU8(m#VnFTFU5Ls^a`= zN$^ATxm3mf)w1#&F>FtLE>*LDk<(tbYjGFF2rfI9%C&fOE|q(AyHUa*!`u3jyX>s>7|ES#36>?P)=f5KDQ#~vSk!?;7X*N^$|`Ke6iL-*}*eZsTF zTP~721zv(|t!u`S;#4cRQuwQ=A?LT=;1ioY;aNr%j3xNI`O{@1bRG_MiR8=YQ7^KW zo8VHH^mogrZi-J`G8>-`r|Lc`@WLmS>9{%eG<`3R7P-e2_(` ze%#mUd8XkBb1$pcD*RyXulHJo7tDR8Iilj@ul%BjOrmWYm2mHfAsO5|Dt$WdnYw+a z{4@~7TAOLWKD5t9 z{(9n@>Q0?JpVZS;#YSe!$hUMIg(uD;k9$)tJ6n_LHl0>qS`1h5h*+abPwRi!Q;gY@ zdbC@6rq41W4;ERi_4!M6h7qe}$tgX)qvhV$!?9K6SJtxTz13MpCSiV>N!5d$YhBv| zzSH$NI8_xE`udIK@FSbxmhq^tR;cUcYeZFp)jJ9hkhpOzWbxfkWAdnt#8xWDSK*Z#r?E0DyXArt}$rIBX=JAjVrh)yrA!aE2IGZ%t{|`)VkKQ-v0^BigoAS+3Hz+JWUL^k8N0*F%jIYA{D*{%Yg1vZsbs&{zS# zGnng-<0FV4{%Y@s+>NL@k13# zwF`v(3yU<_oH!N?jhK%u-^*Bb@;u_dNCw~QGQ&!sMl%pukC~CJi2uXCsB5uV4nKUG z)+hbE<7hrA=ZUD9w9AjJ-?wL*h_YE9xAFF-;%znqpGxHY*gOocD%4uJ&9U$qGe_)- zxYA=x-_3cv9WB~um-{NrE8=ld8$o|o)jhdOy zxIQa*st9`>d~a#A?Qg20>N+-0Yum%iRGh8xuTgw`XR`8dr)as^RURXmD()_G z1Q1ukX2iI03ze;KXVj4)!(dUP9k);`Tlw?KVCtOje5L#S&N%IoJ>|B^+s{|Lin1S@ z9Yd|VcGprdwm%0v^3$^zm+x8gw*t1~IRm%O+Vh=EwZDDVp4+C9@6IRt{OOxl{mI!T zd#kjiZIylGx{^Bf*bt8+8=YhO8hzw@S+*;!cC_P~!tJKFoyXXjO*qCZ6u;iX5CXGM z%zCd~U>0*eJ$u`07np@U$;)sgb)vW4P3D>#qpS31oPW^j(M97Q$PvH}fcd~#;XfK0 z0(=LjI2`@hZ1zCzRc&POIpZH{RMy8oxU|d0Ki^iZ<`kY-s513rw|>rw(l}fk+J{H@sW&4eHXk)Tx1#A!F|m1@#a20_bl7kzKmx$ zPLe)boiWROg1{VFAHDSh((B2HDcZI;7WXOJw`w^X?p2~CLx4sYiTAHpr$-?qwZFxq zcOIRLz1b07;<^Lo*XO^iH?Gbqq#o26>mLRwLESH~iXKtcxyA|~LA&*8&~eRbWkH`u zcV=;IgS4m=R@Wb^-%cSYrHr!LSSx|ss!{^4L8tH(NO+$bblj>z^0FFq+{Qu1`D)N{ z3kaF()S%;*5t8~k01x=ZgfrlVq&T>(>lMb z2A#ru`q@hg@yY$9Mhn|rMdw(|@2U!m8A!U$wYX#Bci6eJ&}UTTS+Fyc3jc{Vxq~7D zFEe~phDC|BM(^})?T9%t8DV>l%;vtfoIl`X^@xWwt!c3)P~BqRGD|}1)ftQQ&uWC% zpQsQa?EAN^*TAewA4uUq;`(wK3rV_FXCPrWnk3t8Nz)jr(( z?OcMY`i8g4ea`(a#DlOF$F_!AE=pB{8|Q`Ux^N6N{K^nCo*%_5W4t@pLY5_^?x-r) zp0BQ-ZH!*pei_f>J8s!luiIAUGW&O@%6*Uia7}dE13TGz;Hd$))2Ga-o8MV=kq9d4 ztKr5BWJjXf6XFNdfx-TY-(r1k_Wq1@k%iA0Rb79q;Lm|WODpr;WP9G&ZWs{`a%bO| z7J@(Ao$?gcL3%D5fn9e@miG6<7a840=6`<-$ZbY35o!3| z%JJH00UK7H-r`sY^W8Z5mNAF-M)^o{JNu1|uAgI1Ka=}d@D$=KTSjr*PsisOn#uhm ze+tI9hh=gfC`ZC$>i>-SZ26A!h(~3!VNA>XhBC%f=DzA-K?@%YmelpvBVwgncLGit6 zRoMr(px{n@21dwc?1)T{p^4aO^44R8bNUXDElO*p@J*~J*WvPc^LOFeq))LadxcmX zZ+FMO!uI58xEMjcb z^y{~sznx)JO206xc;X}bi!-%>l_-o8m2IEcQ(m6kFzfxyyiJWwEnd51mLN7-ktNh=#AR5E^N?_BD=!ZR_lf7$uTbT9hHH3sr= zHvZRX?mXf?v{8zd94DHepM@Npv5&S~W9Dri+VjgwXbPR=)z>r*$?B&m{4q2o^BLxz zmO>)u?R|9AofOEJNXt>qy22n~Wzt7xk%PLC;+D<9t1~vpp9@bZc0kl&X3>DR%^jw0 z$F=D8q}$%Q%*_t`wtjoAQA|$u$j4pXQ{lY`>_5*Nt6M7CHhD%u-C7Sn8e?5%Qb+%I z#O7`4k?Enk>OKmWk)zUY&+QRxOX#%EO}*;Xy%Y1c?W+G;Xjty%KU(#U-Loq7F>YMP zaElHy!N6!dv6kT#L`$w!=&@%){5G}r7U~8Guy(lbKD`yT64mVy@be+(mq}8|k*a$l zdadTxYJNw=MPl`c!Qd(5o@+b_-{EJ+?oq=XmDH|p^t5-4jYTZgVn|zz{*BoroRr`r zG)IiqL*|*}rTBK_Uk-+Ly zX7oMVRkmlx6~@kS+Zv_kQDhy%a+IF?`V6J#KK{pWcD!eEBbyAE$`eE7z!-Y`p>m&V z#4wS>Xvw2XkIqmrWP6tUA8e%SKQ9c&bMM$|eP`zX_AEKPg&dVc%5IgD>SF!XnmXYj^G01QRssn@qSs=VNpRSI%_tLD}mxi1${IzC} z`F>I&Q{Eqiv|~>wThwSQ&s#~Xu58_U?+SNU%$vg7=gdOOyeZ^8XS&`;W287PI%3`w z?!IRl;?+BP{Juink*mx(J9Qs47ephevQnJ>6oro55~J^YH1QwvN`KR^Wez z+7{X;;+|)mF-=d-eK($=*nW~DB{RwNPE{su6nQ2-E-G&t?bfRp!M)5@7PM(pF@kFtq&+*eII3dAs2)bh zcxa=!vi{&SK|4NN=gMC2iV>=QC?vd3#R$$rL2{m?#aZAu$9vn}6c}&VCvMXq<9rn( zxYdKqbt*=1s|ZOkf3*(4ztj~YxVS~WnUvQ^TIqwRWMusui1t8#HH})$n@DbJcbnDkC zT)M?>U2A$+phB$o%$Iy&eMK%ecAWd>!y%J9&TMG3`i|`e@JOFbOb*&VvX;Ol!R%lZ z;;p$Jg}<43?tz;}TkieM*)?yY&}qjbk=u!UFCdK3hVP{-V@TfG+Z@hjINI_(v$Y0o z_JG2rmQ{8XR$aG7^z?2zGt#pD3bC$bz{7k_ zWN?qGmI3}_&(_JolsnztnHeL=eXUknX_<igYs?>KAOW7dPozb<&>Ub|rOk-NXn^Mc6-FT~olJ5BBuHP?{=Cxu^=)yvpW{qRE$bqAR$z#TF2JiI*AM6P(R+OLlQf&>Sv9-xdGoBJu{jUV zs%2h2&w4Ta+XT<5d%ERWfu;fJ@JRoq?S3&U;fdkvvDs31mbf4JitV!Np0ElmjPaA3 z<5~0USbMVN!Q@pwpE8_)7ll>(_i99bXZVVrKKuQ-MgkrRa3wHDsKs%2`U&I9#^z5u zf0}Tdlc{Gu6V9ojhn{Z}b9K?Z!@dapcr`l*w8>tD7xFQT&~1wx9~$R@*amZfC~1>p z;Yb}Ythe_3O+OjyACckVhMyewAog+_HaQ028-5I$=s3^E(GwuYZzqo&OywcN?apbw9x8Ccn9d>p+g`Jj)ZN6smrvKw}$&FTyGVlX9_Y2lI61FYob nrS_t()ib`cZ_l?#0*kq4J+3TC_i$>a(^d(SqAW;7w9 void GenerateFromEnum(uint64_t key) +{ + using namespace magic_enum; + constexpr size_t count = enum_count(); + constexpr auto variables_values = enum_values(); + constexpr auto variables_names = enum_names(); + BehaviorVars sig; + + sig.m_key = key; + for (size_t index = 0; index < count; index++) + { + std::string name = static_cast(variables_names[index]); + uint32_t value = enum_integer(variables_values[index]); + + // Remove the leading 'k' + name = name.substr(1, name.size() - 1); + + sig.m_namemap[name] = value; + sig.m_valuemap[value] = name; + } + + BehaviorVarsMap::getInstance().Register(sig); +}; + +#ifdef TP_SKYRIM +#include "BehaviorOrig.Skyrim" +#else +#include "BehaviorOrig.Fallout4" +#endif + +} // using namespace BehaviorOrig diff --git a/Code/client/ModCompat/BehaviorOrigGenerate.ps1 b/Code/client/ModCompat/BehaviorOrigGenerate.ps1 new file mode 100644 index 000000000..2c0b0f533 --- /dev/null +++ b/Code/client/ModCompat/BehaviorOrigGenerate.ps1 @@ -0,0 +1,94 @@ +param ( + [string]$path = "..\..\encoding\Structs\Skyrim" +) +$files = Get-ChildItem $path -Filter *_*.cpp +Set-PSDebug -Trace 0 +"// DO NOT EDIT, MACHINE-GENERATED CODE +// +// This is an admittedly dirty approach, but done with the best of intentions. +// +// The idea is to minimize intrusion into the STR Devs's base code, but we +// need some information that isn't exposed (the behavior variables' strings, +// not just their enum values). This is needed so we can translate the numeric +// original behavior vars back to their string names, so we can then look up the +// NEW numeric value when behaviors are modified. +// +// That would require a simple code change, but one needed so ubiquitously +// it is intrusive. If the STR team gives permission for the change, this +// can all be cleaned up. Unless and until they do, we make some edited copies +// of the relevant behavior structs in their own namespace to provide the needed info. +// +// Would be so much easier if Nemesis simply added new vars to the end of the +// list, rather than randomly rearranging it. Rumor is Pandora does it correctly. +// +" + + +$creatures = "`r`nvoid BehaviorOrigInit()`r`n{`r`n" + +foreach ($f in $files) +{ + $path = $f.FullName + $pathparts = Get-Item $path + $file = $pathparts.Name + $creature = $pathparts.BaseName + $creatures = $creatures + " (void) $creature::getInstance();`r`n" + + $extract = "`r`nclass $creature`r`n{`r`n private:" + $extract + + # For the enum declaration, match non-greedy to stop at first close brace. + # Master_Behavior special case since they include more stuff. + # Also even more special for Fallout 3rd-person, since they inject namespaces + # we need a look-behind to get rid of it. + $pattern = "namespace TP" + $extract = [Regex]::Match((Get-Content $path -Raw), $pattern).Value + if ([string]::IsNullOrEmpty($extract)) { + $pattern = "(?s) *enum Variables(.*?)};" + } else { + $pattern = "(?s)(?<=namespace TP`r`n{`r`n) *enum Variables(.*?)};" + } + + $extract = [Regex]::Match((Get-Content $path -Raw), $pattern).Value + $extract + + $pattern = "key =.*;" + $extract = [Regex]::Match((Get-Content $path -Raw), $pattern).Value + + # If no key was found in the .cpp file it is because for some creatures it is in .h file + if ([string]::IsNullOrEmpty($extract)) + { + $hpath = Get-Item $path + $hpath = Join-Path $hpath.DirectoryName ($hpath.BaseName + ".h") + $extract = [Regex]::Match((Get-Content $hpath -Raw), $pattern).Value + } + + $extract = ' static const uint64_t m_' + $extract + "`r`n" + $extract + + # Constructor + $extract = " // Constructor + $creature() + { + BehaviorOrig::GenerateFromEnum(m_key); + } + + // Singleton + $creature($creature const&) = delete; + void operator=($creature const&) = delete; + + public: + static $creature& getInstance() + { + // The only instance. Guaranteed lazy initiated + // Guaranteed that it will be destroyed correctly + static $creature instance; + + return instance; + }`r`n};" + + $extract +} + +$creatures = $creatures + "};`r`n" +$creatures diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 0c38cb3ea..b53a51ac3 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -1,9 +1,31 @@ +// +// Core support for modified behavior (as in Nemesis or Pandora behavior modification or extension). +// +// One of the greatest features ensuring the longevity of Bethesda games is their support +// for community modification, and many of the most popular mods also change the behavior +// of creatures. STR and FTR don't support mods as a matter of policy. And supporting +// behavior mods is particularly difficult. +// +// The game determines a set of behavior variables that must be synced and locks thatdown. +// Changing the list is difficult, because behavior mods won't just add to the list, they +// will change the order of the list also changing the shorthand numeric codes for behavior +// vars to sync. +// +// So, supporting behavior mods means: +// 1) We must be able the translate the built-in behavior var codes back to their string values. +// 2) We must then retranslate the string values back to their (new) numeric values. +// 3) We must add in the additional behavior variables requested by modders +// 4) Finally, that will push us over some hard-coded limits, in particular +// a limit of 64 boolean vars that can be synced. Remove the limit. +// #ifdef MODDED_BEHAVIOR_COMPATIBILITY +#include #include #include -#include +#include "BehaviorVar.h" +#include "BehaviorVarsMap.h" #if TP_SKYRIM64 #include @@ -34,6 +56,61 @@ const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apMana return BehaviorVar::Get()->Patch(apManager, apActor); } +// +// Translate modded behavior numeric values. +// When a behavior is modified (at least by Nemesis) it can rearrange the order of BehaviorVars. +// Since their corresponding numeric value is based on the order, we have to translate the +// BehaviorVars chosen (numerically) by the STR devs to their new numeric values. +// We do this with a hack to translate old numeric value back to a string, then we +// can forward-translate the string to its new numeric value. +// +// The machine-generated table hack to do this can be removed with STR-devs +// permission to also embed the string invformation in the Code\encoding\structs files. +// +void BehaviorVar::seedAnimationVariables( + uint64_t hash, + const AnimationGraphDescriptor* pDescriptor, + std::map& reversemap, + std::set& boolVars, + std::set& floatVars, + std::set& intVars) +{ + auto& origVars = BehaviorVarsMap::getInstance(); + + // Defensive code to detect if for some reason we have a number + // without a string, or a string without a number. + for (auto& item : pDescriptor->BooleanLookUpTable) + { + auto strValue = origVars.find(hash, item); + if (strValue.empty()) + spdlog::warn("BehaviorVar::seedAnimationVariables unable to find string for original BooleanVar {}", item); + else if (reversemap.find(strValue) == reversemap.end()) + spdlog::warn("BehaviorVar::seedAnimationVariables unable to find BooleanVar {}", strValue); + else + boolVars.insert(reversemap[strValue]); + } + for (auto& item : pDescriptor->FloatLookupTable) + { + auto strValue = origVars.find(hash, item); + if (strValue.empty()) + spdlog::warn("BehaviorVar::seedAnimationVariables unable to find string for original FloatVar {}", item); + else if (reversemap.find(strValue) == reversemap.end()) + spdlog::warn("BehaviorVar::seedAnimationVariables unable to find FloatVar {}", strValue); + else + floatVars.insert(reversemap[strValue]); + } + for (auto& item : pDescriptor->IntegerLookupTable) + { + auto strValue = origVars.find(hash, item); + if (strValue.empty()) + spdlog::warn("BehaviorVar::seedAnimationVariables unable to find string for original IntegerVar {}", item); + else if (reversemap.find(strValue) == reversemap.end()) + spdlog::warn("BehaviorVar::seedAnimationVariables unable to find IntegerVar {}", strValue); + else + intVars.insert(reversemap[strValue]); + } +} + const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apManager, Actor* apActor) { // Serialize, Actors are multi-threaded. Might not be strictly necessary, I think we're on @@ -83,15 +160,15 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa if (invocations++ == 100) spdlog::warn("BehaviorVar::Patch: warning, more than 100 invocations, investigate why"); - spdlog::info("BehaviorVar::Patch: actor with formID {:x} with hash of {} has modded behavior", hexFormID, hash); + spdlog::info("BehaviorVar::Patch: actor with formID {:x} with hash of {} has modded (or not synced) behavior", hexFormID, hash); - // Get all animation variables for this actor, then create a reversemap to go from strings to aniamation enum. + // Get all animation variables for this actor, then create a reversemap to go from strings to animation enum. auto pDumpVar = apManager->DumpAnimationVariables(false); std::map reversemap; - spdlog::debug("Known behavior variables for formID {:x}:", hexFormID); + spdlog::info("Known behavior variables for formID {:x}:", hexFormID); for (auto& item : pDumpVar) { - spdlog::debug(" {}:{}", item.first, item.second); + spdlog::info(" {}:{}", item.first, item.second); reversemap.insert({static_cast(item.second), item.first}); } @@ -102,11 +179,11 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa break; if (iter >= behaviorPool.end()) { - spdlog::warn("No replacer found for behavior hash {:x} (found on formID {:x}), adding to fail list", hash, hexFormID); + spdlog::warn("No original behavior found for behavior hash {:x} (found on formID {:x}), adding to fail list", hash, hexFormID); failList(hash); return nullptr; } - spdlog::info("Found match, behavior replacer signature {}", iter->signatureVar); + spdlog::info("Found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", hash, hexFormID, iter->creatureName, iter->signatureVar); // Build the set of BehaviorVar strings as sets (not vectors) to eliminate dups // Also, we want the set sorted, to make sure we get the same hash if mods @@ -124,9 +201,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa const AnimationGraphDescriptor* pTmpGraph = nullptr; if (iter->orgHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(iter->orgHash))) { - boolVar.insert(pTmpGraph->BooleanLookUpTable.begin(), pTmpGraph->BooleanLookUpTable.end()); - floatVar.insert(pTmpGraph->FloatLookupTable.begin(), pTmpGraph->FloatLookupTable.end()); - intVar.insert(pTmpGraph->IntegerLookupTable.begin(), pTmpGraph->IntegerLookupTable.end()); + seedAnimationVariables(iter->orgHash, pTmpGraph, reversemap, boolVar, floatVar, intVar); spdlog::info("Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", iter->orgHash, boolVar.size(), floatVar.size(), intVar.size()); } @@ -179,6 +254,8 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa if (foundCount) spdlog::info("Now have {} intVar descriptors after searching {} BehavivorVar strings", intVar.size(), iter->syncIntegerVar.size()); +#if 0 // There are no limits, flex arrays now. Will come back and delete if it works. + // Ensure we aren't over the limits. If we are, we won't update // the animation. Performance will be terrible unless we kill some of the logging // or keep track of failed signatures. @@ -198,7 +275,8 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa failList(hash); return nullptr; } - + #endif + // Reshape the (sorted, unique) sets to vectors TiltedPhoques::Vector boolVector(boolVar.begin(), boolVar.end()); TiltedPhoques::Vector floatVector(floatVar.begin(), floatVar.end()); @@ -231,21 +309,17 @@ void BehaviorVar::failList(uint64_t hash) failedBehaviors.insert_or_assign(hash, std::chrono::steady_clock::now() + FAILLIST_DURATION); } -bool dirExists(std::string aPath) +// Find all the subdirectories of behavior variables +std::vector BehaviorVar::loadDirs(const std::filesystem::path& acPATH) { - return std::filesystem::is_directory(aPath); -} - -std::vector loadDirs(const std::string& acPATH) -{ - std::vector result; + std::vector result; for (auto& p : std::filesystem::directory_iterator(acPATH)) if (p.is_directory()) result.push_back(p.path().string()); return result; } -BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) +BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aDir) { // Enumerate all files in the directory and push bools, ints and floats // to their respective vectors @@ -314,6 +388,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) // Prepare reading files std::string sigVar; + std::string creatureName = aDir.filename().string(); std::vector floatVar; std::vector intVar; std::vector boolVar; @@ -325,7 +400,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) erase_if(sigVar, isspace); // removes any inadvertant whitespace if (sigVar.size() == 0) return nullptr; - spdlog::info("BehaviorVar::loadReplacerFromDir found signature variable {}", sigVar); + spdlog::info("BehaviorVar::loadReplacerFromDir found {} with signature variable {}", creatureName, sigVar); // Check to see if there is a hash file. // This is recommended, and shouild contain the ORIGINAL hash, @@ -347,13 +422,13 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) file.close(); erase_if(tempString, isspace); // removes any inadvertant whitespace orgHash = std::strtoull(tempString.c_str(), nullptr, 10); - spdlog::info("Replacer specifies original hash {} for {}", orgHash, sigVar); + spdlog::info("Replacer specifies original hash {} for {}", orgHash, creatureName); } // Build lists of variables to sync // Read float behavior variables spdlog::debug("reading float var"); - for (auto item : floatVarsFile) + for (auto& item : floatVarsFile) { std::ifstream file(item); while (std::getline(file, tempString)) @@ -367,7 +442,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) // Read integer behavior variables spdlog::debug("reading int vars"); - for (auto item : intVarsFile) + for (auto& item : intVarsFile) { std::ifstream file(item); while (std::getline(file, tempString)) @@ -381,7 +456,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) // Read boolean behavior variables spdlog::debug("reading bool vars"); - for (auto item : boolVarsFile) + for (auto& item : boolVarsFile) { std::ifstream file(item); while (std::getline(file, tempString)) @@ -398,6 +473,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) result->orgHash = orgHash; result->signatureVar = sigVar; + result->creatureName = creatureName; result->syncBooleanVar = boolVar; result->syncFloatVar = floatVar; result->syncIntegerVar = intVar; @@ -407,15 +483,19 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::string aDir) void BehaviorVar::Init() { + // Initialize original (base STR) behaviors so we can search them. + BehaviorOrig::BehaviorOrigInit(); + // Check if the behaviors folder exists - const std::string behaviorPath = TiltedPhoques::GetPath().string() + "/behaviors"; + std::filesystem::path pBehaviorsPath; + pBehaviorsPath = launcher::GetLaunchContext()->gamePath / L"Data" / L"SkyrimTogetherRebornBehaviors"; - if (!dirExists(behaviorPath)) + if (!std::filesystem::is_directory(pBehaviorsPath)) return; - std::vector behaviorDirs = loadDirs(behaviorPath); + auto behaviorDirs = loadDirs(pBehaviorsPath); - for (auto dir : behaviorDirs) + for (auto& dir : behaviorDirs) { Replacer* sig = loadReplacerFromDir(dir); if (sig) diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index 573f83b4f..246c2a80a 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -10,6 +10,7 @@ struct BehaviorVar uint64_t orgHash; uint64_t newHash; std::string signatureVar; + std::string creatureName; std::vector syncBooleanVar; std::vector syncFloatVar; std::vector syncIntegerVar; @@ -27,7 +28,16 @@ struct BehaviorVar static BehaviorVar* single; uint64_t invocations = 0; - Replacer* loadReplacerFromDir(std::string aDir); + void seedAnimationVariables( + uint64_t hash, + const AnimationGraphDescriptor* pDescriptor, + std::map& reversemap, + std::set& boolVars, + std::set& floatVars, + std::set& intVars); + + std::vector loadDirs(const std::filesystem::path& acPATH); + Replacer* loadReplacerFromDir(std::filesystem::path aDir); std::vector behaviorPool; // Pool for loaded behaviours std::map failedBehaviors; diff --git a/Code/client/ModCompat/BehaviorVarsMap.cpp b/Code/client/ModCompat/BehaviorVarsMap.cpp new file mode 100644 index 000000000..a05b5f452 --- /dev/null +++ b/Code/client/ModCompat/BehaviorVarsMap.cpp @@ -0,0 +1,49 @@ +#include "BehaviorVarsMap.h" + + +uint32_t BehaviorVarsMap::find(const uint64_t key, const std::string name) +{ + auto map = m_map.find(key); + + if (map != m_map.end()) + { + auto map2 = map->second.m_namemap.find(name); + + if (map2 != map->second.m_namemap.end()) + return map2->second; + } + + return -1; +} + +std::string BehaviorVarsMap::find(const uint64_t key, const uint32_t value) +{ + constexpr std::string empty; + + auto map = m_map.find(key); + if (map != m_map.end()) + { + auto map2 = map->second.m_valuemap.find(value); + + if (map2 != map->second.m_valuemap.end()) + return map2->second; + } + + return empty; +} + +void BehaviorVarsMap::Register(const BehaviorVars map) +{ + m_map.insert_or_assign(map.m_key, map); +} + + +BehaviorVarsMap& BehaviorVarsMap::getInstance() +{ + // The only instance. Guaranteed lazy initiated + // Guaranteed that it will be destroyed correctly + static BehaviorVarsMap instance; + + return instance; +} + diff --git a/Code/client/ModCompat/BehaviorVarsMap.h b/Code/client/ModCompat/BehaviorVarsMap.h new file mode 100644 index 000000000..f95aaa686 --- /dev/null +++ b/Code/client/ModCompat/BehaviorVarsMap.h @@ -0,0 +1,36 @@ +#pragma once + + +struct BehaviorVars +{ + uint64_t m_key; + std::map m_namemap; + std::map m_valuemap; +}; + + + +class BehaviorVarsMap +{ + private: + std::map< uint64_t, BehaviorVars> m_map; + + // Singleton + BehaviorVarsMap(){}; + BehaviorVarsMap(BehaviorVarsMap const&) = delete; + void operator=(BehaviorVarsMap const&) = delete; + + public: + uint32_t find(const uint64_t key, const std::string name); + + std::string find(const uint64_t key, const uint32_t value); + + void Register(const BehaviorVars map); + + static BehaviorVarsMap& getInstance(); +}; + +namespace BehaviorOrig +{ + extern void BehaviorOrigInit(); +}; diff --git a/Code/client/ModCompat/magic_enum.hpp b/Code/client/ModCompat/magic_enum.hpp new file mode 100644 index 000000000..a4ea49ae9 --- /dev/null +++ b/Code/client/ModCompat/magic_enum.hpp @@ -0,0 +1,1472 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.5 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_HPP +#define NEARGYE_MAGIC_ENUM_HPP + +#define MAGIC_ENUM_VERSION_MAJOR 0 +#define MAGIC_ENUM_VERSION_MINOR 9 +#define MAGIC_ENUM_VERSION_PATCH 5 + +#include +#include +#include +#include +#include +#include +#include + +#if defined(MAGIC_ENUM_CONFIG_FILE) +# include MAGIC_ENUM_CONFIG_FILE +#endif + +#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +# include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING) +# include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +# include +#endif + +#if defined(MAGIC_ENUM_NO_ASSERT) +# define MAGIC_ENUM_ASSERT(...) static_cast(0) +#else +# include +# define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__)) +#endif + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-warning-option" +# pragma clang diagnostic ignored "-Wenum-constexpr-conversion" +# pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast('\0')' for char_type = char (common on Linux). +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. +# pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast('\0')' for char_type = char (common on Linux). +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 26495) // Variable 'static_str::chars_' is uninitialized. +# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. +# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call. +# pragma warning(disable : 4514) // Unreferenced inline function has been removed. +#endif + +// Checks magic_enum compiler compatibility. +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__) +# undef MAGIC_ENUM_SUPPORTED +# define MAGIC_ENUM_SUPPORTED 1 +#endif + +// Checks magic_enum compiler aliases compatibility. +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920 +# undef MAGIC_ENUM_SUPPORTED_ALIASES +# define MAGIC_ENUM_SUPPORTED_ALIASES 1 +#endif + +// Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128. +// If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN. +#if !defined(MAGIC_ENUM_RANGE_MIN) +# define MAGIC_ENUM_RANGE_MIN -128 +#endif + +// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128. +// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX. +#if !defined(MAGIC_ENUM_RANGE_MAX) +# define MAGIC_ENUM_RANGE_MAX 127 +#endif + +// Improve ReSharper C++ intellisense performance with builtins, avoiding unnecessary template instantiations. +#if defined(__RESHARPER__) +# undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN +# undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN +# if __RESHARPER__ >= 20230100 +# define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V) +# define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name() +# else +# define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr +# define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr +# endif +#endif + +namespace magic_enum { + +// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL. +#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +MAGIC_ENUM_USING_ALIAS_OPTIONAL +#else +using std::optional; +#endif + +// If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +MAGIC_ENUM_USING_ALIAS_STRING_VIEW +#else +using std::string_view; +#endif + +// If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING) +MAGIC_ENUM_USING_ALIAS_STRING +#else +using std::string; +#endif + +using char_type = string_view::value_type; +static_assert(std::is_same_v, "magic_enum::customize requires same string_view::value_type and string::value_type"); +static_assert([] { + if constexpr (std::is_same_v) { + constexpr const char c[] = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; + constexpr const wchar_t wc[] = L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; + static_assert(std::size(c) == std::size(wc), "magic_enum::customize identifier characters are multichars in wchar_t."); + + for (std::size_t i = 0; i < std::size(c); ++i) { + if (c[i] != wc[i]) { + return false; + } + } + } + return true; +} (), "magic_enum::customize wchar_t is not compatible with ASCII."); + +namespace customize { + +// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. +// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. +// If need another range for specific enum type, add specialization enum_range for necessary enum type. +template +struct enum_range { + static_assert(std::is_enum_v, "magic_enum::customize::enum_range requires enum type."); + static constexpr int min = MAGIC_ENUM_RANGE_MIN; + static constexpr int max = MAGIC_ENUM_RANGE_MAX; + static_assert(max > min, "magic_enum::customize::enum_range requires max > min."); +}; + +static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); +static_assert((MAGIC_ENUM_RANGE_MAX - MAGIC_ENUM_RANGE_MIN) < (std::numeric_limits::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX."); + +namespace detail { + +enum class customize_tag { + default_tag, + invalid_tag, + custom_tag +}; + +} // namespace magic_enum::customize::detail + +class customize_t : public std::pair { + public: + constexpr customize_t(string_view srt) : std::pair{detail::customize_tag::custom_tag, srt} {} + constexpr customize_t(const char_type* srt) : customize_t{string_view{srt}} {} + constexpr customize_t(detail::customize_tag tag) : std::pair{tag, string_view{}} { + MAGIC_ENUM_ASSERT(tag != detail::customize_tag::custom_tag); + } +}; + +// Default customize. +inline constexpr auto default_tag = customize_t{detail::customize_tag::default_tag}; +// Invalid customize. +inline constexpr auto invalid_tag = customize_t{detail::customize_tag::invalid_tag}; + +// If need custom names for enum, add specialization enum_name for necessary enum type. +template +constexpr customize_t enum_name(E) noexcept { + return default_tag; +} + +// If need custom type name for enum, add specialization enum_type_name for necessary enum type. +template +constexpr customize_t enum_type_name() noexcept { + return default_tag; +} + +} // namespace magic_enum::customize + +namespace detail { + +template +struct supported +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT) + : std::true_type {}; +#else + : std::false_type {}; +#endif + +template , std::enable_if_t, int> = 0> +using enum_constant = std::integral_constant; + +template +inline constexpr bool always_false_v = false; + +template +struct has_is_flags : std::false_type {}; + +template +struct has_is_flags::is_flags)>> : std::bool_constant::is_flags)>>> {}; + +template +struct range_min : std::integral_constant {}; + +template +struct range_min::min)>> : std::integral_constant::min), customize::enum_range::min> {}; + +template +struct range_max : std::integral_constant {}; + +template +struct range_max::max)>> : std::integral_constant::max), customize::enum_range::max> {}; + +struct str_view { + const char* str_ = nullptr; + std::size_t size_ = 0; +}; + +template +class static_str { + public: + constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence{}} { + MAGIC_ENUM_ASSERT(str.size_ == N); + } + + constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence{}} { + MAGIC_ENUM_ASSERT(str.size() == N); + } + + constexpr const char_type* data() const noexcept { return chars_; } + + constexpr std::uint16_t size() const noexcept { return N; } + + constexpr operator string_view() const noexcept { return {data(), size()}; } + + private: + template + constexpr static_str(const char* str, std::integer_sequence) noexcept : chars_{static_cast(str[I])..., static_cast('\0')} {} + + template + constexpr static_str(string_view str, std::integer_sequence) noexcept : chars_{str[I]..., static_cast('\0')} {} + + char_type chars_[static_cast(N) + 1]; +}; + +template <> +class static_str<0> { + public: + constexpr explicit static_str() = default; + + constexpr explicit static_str(str_view) noexcept {} + + constexpr explicit static_str(string_view) noexcept {} + + constexpr const char_type* data() const noexcept { return nullptr; } + + constexpr std::uint16_t size() const noexcept { return 0; } + + constexpr operator string_view() const noexcept { return {}; } +}; + +template > +class case_insensitive { + static constexpr char_type to_lower(char_type c) noexcept { + return (c >= static_cast('A') && c <= static_cast('Z')) ? static_cast(c + (static_cast('a') - static_cast('A'))) : c; + } + + public: + template + constexpr auto operator()(L lhs, R rhs) const noexcept -> std::enable_if_t, char_type> && std::is_same_v, char_type>, bool> { + return Op{}(to_lower(lhs), to_lower(rhs)); + } +}; + +constexpr std::size_t find(string_view str, char_type c) noexcept { +#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) +// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc +// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + constexpr bool workaround = true; +#else + constexpr bool workaround = false; +#endif + + if constexpr (workaround) { + for (std::size_t i = 0; i < str.size(); ++i) { + if (str[i] == c) { + return i; + } + } + + return string_view::npos; + } else { + return str.find(c); + } +} + +template +constexpr bool is_default_predicate() noexcept { + return std::is_same_v, std::equal_to> || + std::is_same_v, std::equal_to<>>; +} + +template +constexpr bool is_nothrow_invocable() { + return is_default_predicate() || + std::is_nothrow_invocable_r_v; +} + +template +constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(is_nothrow_invocable()) { +#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) + // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html + constexpr bool workaround = true; +#else + constexpr bool workaround = false; +#endif + + if constexpr (!is_default_predicate() || workaround) { + if (lhs.size() != rhs.size()) { + return false; + } + + const auto size = lhs.size(); + for (std::size_t i = 0; i < size; ++i) { + if (!p(lhs[i], rhs[i])) { + return false; + } + } + + return true; + } else { + return lhs == rhs; + } +} + +template +constexpr bool cmp_less(L lhs, R rhs) noexcept { + static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::cmp_less requires integral type."); + + if constexpr (std::is_signed_v == std::is_signed_v) { + // If same signedness (both signed or both unsigned). + return lhs < rhs; + } else if constexpr (std::is_same_v) { // bool special case + return static_cast(lhs) < rhs; + } else if constexpr (std::is_same_v) { // bool special case + return lhs < static_cast(rhs); + } else if constexpr (std::is_signed_v) { + // If 'right' is negative, then result is 'false', otherwise cast & compare. + return rhs > 0 && lhs < static_cast>(rhs); + } else { + // If 'left' is negative, then result is 'true', otherwise cast & compare. + return lhs < 0 || static_cast>(lhs) < rhs; + } +} + +template +constexpr I log2(I value) noexcept { + static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type."); + + if constexpr (std::is_same_v) { // bool special case + return MAGIC_ENUM_ASSERT(false), value; + } else { + auto ret = I{0}; + for (; value > I{1}; value >>= I{1}, ++ret) {} + + return ret; + } +} + +#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L +# define MAGIC_ENUM_ARRAY_CONSTEXPR 1 +#else +template +constexpr std::array, N> to_array(T (&a)[N], std::index_sequence) noexcept { + return {{a[I]...}}; +} +#endif + +template +inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + + if constexpr (supported::value) { +#if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E); + constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +#elif defined(__clang__) + str_view name; + if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { + static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); + return str_view{}; + } else { + name.size_ = sizeof(__PRETTY_FUNCTION__) - 36; + name.str_ = __PRETTY_FUNCTION__ + 34; + } +#elif defined(__GNUC__) + auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1}; + if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { + static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); + return str_view{}; + } else if (name.str_[name.size_ - 1] == ']') { + name.size_ -= 50; + name.str_ += 49; + } else { + name.size_ -= 40; + name.str_ += 37; + } +#elif defined(_MSC_VER) + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + str_view name; + name.str_ = __FUNCSIG__; + name.str_ += 40; + name.size_ += sizeof(__FUNCSIG__) - 57; +#else + auto name = str_view{}; +#endif + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + return name; + } else { + return str_view{}; // Unsupported compiler or Invalid customize. + } +} + +template +constexpr auto type_name() noexcept { + [[maybe_unused]] constexpr auto custom = customize::enum_type_name(); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return static_str{name}; + } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) { + return static_str<0>{}; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { + constexpr auto name = n(); + return static_str{name}; + } else { + static_assert(always_false_v, "magic_enum::customize invalid."); + } +} + +template +inline constexpr auto type_name_v = type_name(); + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + + if constexpr (supported::value) { +#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); + auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +#elif defined(__clang__) + str_view name; + if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { + static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); + return str_view{}; + } else { + name.size_ = sizeof(__PRETTY_FUNCTION__) - 36; + name.str_ = __PRETTY_FUNCTION__ + 34; + } + if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') { + name.size_ -= 23; + name.str_ += 23; + } + if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) { + name = str_view{}; + } +#elif defined(__GNUC__) + auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1}; + if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { + static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); + return str_view{}; + } else if (name.str_[name.size_ - 1] == ']') { + name.size_ -= 55; + name.str_ += 54; + } else { + name.size_ -= 40; + name.str_ += 37; + } + if (name.str_[0] == '(') { + name = str_view{}; + } +#elif defined(_MSC_VER) + str_view name; + if ((__FUNCSIG__[5] == '_' && __FUNCSIG__[35] != '(') || (__FUNCSIG__[5] == 'c' && __FUNCSIG__[41] != '(')) { + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + name.str_ = __FUNCSIG__; + name.str_ += 35; + name.size_ = sizeof(__FUNCSIG__) - 52; + } +#else + auto name = str_view{}; +#endif + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + return name; + } else { + return str_view{}; // Unsupported compiler or Invalid customize. + } +} + +#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920 +# define MAGIC_ENUM_VS_2017_WORKAROUND 1 +#endif + +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + +# if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); + auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +# else + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + str_view name; + name.str_ = __FUNCSIG__; + name.size_ = sizeof(__FUNCSIG__) - 17; + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ',' || name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) { + name = str_view{}; + } + return name; +# endif +} +#endif + +template +constexpr auto enum_name() noexcept { + [[maybe_unused]] constexpr auto custom = customize::enum_name(V); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return static_str{name}; + } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) { + return static_str<0>{}; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) + constexpr auto name = n(); +#else + constexpr auto name = n(); +#endif + return static_str{name}; + } else { + static_assert(always_false_v, "magic_enum::customize invalid."); + } +} + +template +inline constexpr auto enum_name_v = enum_name(); + +template +constexpr bool is_valid() noexcept { +#if defined(__clang__) && __clang_major__ >= 16 + // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307 + constexpr E v = __builtin_bit_cast(E, V); +#else + constexpr E v = static_cast(V); +#endif + [[maybe_unused]] constexpr auto custom = customize::enum_name(v); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return name.size() != 0; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) + return n().size_ != 0; +#else + return n().size_ != 0; +#endif + } else { + return false; + } +} + +enum class enum_subtype { + common, + flags +}; + +template > +constexpr U ualue(std::size_t i) noexcept { + if constexpr (std::is_same_v) { // bool special case + static_assert(O == 0, "magic_enum::detail::ualue requires valid offset."); + + return static_cast(i); + } else if constexpr (S == enum_subtype::flags) { + return static_cast(U{1} << static_cast(static_cast(i) + O)); + } else { + return static_cast(static_cast(i) + O); + } +} + +template > +constexpr E value(std::size_t i) noexcept { + return static_cast(ualue(i)); +} + +template > +constexpr int reflected_min() noexcept { + if constexpr (S == enum_subtype::flags) { + return 0; + } else { + constexpr auto lhs = range_min::value; + constexpr auto rhs = (std::numeric_limits::min)(); + + if constexpr (cmp_less(rhs, lhs)) { + return lhs; + } else { + return rhs; + } + } +} + +template > +constexpr int reflected_max() noexcept { + if constexpr (S == enum_subtype::flags) { + return std::numeric_limits::digits - 1; + } else { + constexpr auto lhs = range_max::value; + constexpr auto rhs = (std::numeric_limits::max)(); + + if constexpr (cmp_less(lhs, rhs)) { + return lhs; + } else { + return rhs; + } + } +} + +#define MAGIC_ENUM_FOR_EACH_256(T) \ + T( 0)T( 1)T( 2)T( 3)T( 4)T( 5)T( 6)T( 7)T( 8)T( 9)T( 10)T( 11)T( 12)T( 13)T( 14)T( 15)T( 16)T( 17)T( 18)T( 19)T( 20)T( 21)T( 22)T( 23)T( 24)T( 25)T( 26)T( 27)T( 28)T( 29)T( 30)T( 31) \ + T( 32)T( 33)T( 34)T( 35)T( 36)T( 37)T( 38)T( 39)T( 40)T( 41)T( 42)T( 43)T( 44)T( 45)T( 46)T( 47)T( 48)T( 49)T( 50)T( 51)T( 52)T( 53)T( 54)T( 55)T( 56)T( 57)T( 58)T( 59)T( 60)T( 61)T( 62)T( 63) \ + T( 64)T( 65)T( 66)T( 67)T( 68)T( 69)T( 70)T( 71)T( 72)T( 73)T( 74)T( 75)T( 76)T( 77)T( 78)T( 79)T( 80)T( 81)T( 82)T( 83)T( 84)T( 85)T( 86)T( 87)T( 88)T( 89)T( 90)T( 91)T( 92)T( 93)T( 94)T( 95) \ + T( 96)T( 97)T( 98)T( 99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \ + T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \ + T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \ + T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \ + T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255) + +template +constexpr void valid_count(bool* valid, std::size_t& count) noexcept { +#define MAGIC_ENUM_V(O) \ + if constexpr ((I + O) < Size) { \ + if constexpr (is_valid(I + O)>()) { \ + valid[I + O] = true; \ + ++count; \ + } \ + } + + MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V) + + if constexpr ((I + 256) < Size) { + valid_count(valid, count); + } +#undef MAGIC_ENUM_V +} + +template +struct valid_count_t { + std::size_t count = 0; + bool valid[N] = {}; +}; + +template +constexpr auto valid_count() noexcept { + valid_count_t vc; + valid_count(vc.valid, vc.count); + return vc; +} + +template +constexpr auto values() noexcept { + constexpr auto vc = valid_count(); + + if constexpr (vc.count > 0) { +#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) + std::array values = {}; +#else + E values[vc.count] = {}; +#endif + for (std::size_t i = 0, v = 0; v < vc.count; ++i) { + if (vc.valid[i]) { + values[v++] = value(i); + } + } +#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) + return values; +#else + return to_array(values, std::make_index_sequence{}); +#endif + } else { + return std::array{}; + } +} + +template > +constexpr auto values() noexcept { + constexpr auto min = reflected_min(); + constexpr auto max = reflected_max(); + constexpr auto range_size = max - min + 1; + static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); + static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); + + return values(); +} + +template > +constexpr enum_subtype subtype(std::true_type) noexcept { + if constexpr (std::is_same_v) { // bool special case + return enum_subtype::common; + } else if constexpr (has_is_flags::value) { + return customize::enum_range::is_flags ? enum_subtype::flags : enum_subtype::common; + } else { +#if defined(MAGIC_ENUM_AUTO_IS_FLAGS) + constexpr auto flags_values = values(); + constexpr auto default_values = values(); + if (flags_values.size() == 0 || default_values.size() > flags_values.size()) { + return enum_subtype::common; + } + for (std::size_t i = 0; i < default_values.size(); ++i) { + const auto v = static_cast(default_values[i]); + if (v != 0 && (v & (v - 1)) != 0) { + return enum_subtype::common; + } + } + return enum_subtype::flags; +#else + return enum_subtype::common; +#endif + } +} + +template +constexpr enum_subtype subtype(std::false_type) noexcept { + // For non-enum type return default common subtype. + return enum_subtype::common; +} + +template > +inline constexpr auto subtype_v = subtype(std::is_enum{}); + +template +inline constexpr auto values_v = values(); + +template > +using values_t = decltype((values_v)); + +template +inline constexpr auto count_v = values_v.size(); + +template > +inline constexpr auto min_v = (count_v > 0) ? static_cast(values_v.front()) : U{0}; + +template > +inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v.back()) : U{0}; + +template +constexpr auto names(std::index_sequence) noexcept { + constexpr auto names = std::array{{enum_name_v[I]>...}}; + return names; +} + +template +inline constexpr auto names_v = names(std::make_index_sequence>{}); + +template > +using names_t = decltype((names_v)); + +template +constexpr auto entries(std::index_sequence) noexcept { + constexpr auto entries = std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; + return entries; +} + +template +inline constexpr auto entries_v = entries(std::make_index_sequence>{}); + +template > +using entries_t = decltype((entries_v)); + +template > +constexpr bool is_sparse() noexcept { + if constexpr (count_v == 0) { + return false; + } else if constexpr (std::is_same_v) { // bool special case + return false; + } else { + constexpr auto max = (S == enum_subtype::flags) ? log2(max_v) : max_v; + constexpr auto min = (S == enum_subtype::flags) ? log2(min_v) : min_v; + constexpr auto range_size = max - min + 1; + + return range_size != count_v; + } +} + +template > +inline constexpr bool is_sparse_v = is_sparse(); + +template > +constexpr U values_ors() noexcept { + static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype."); + + auto ors = U{0}; + for (std::size_t i = 0; i < count_v; ++i) { + ors |= static_cast(values_v[i]); + } + + return ors; +} + +template +struct enable_if_enum {}; + +template +struct enable_if_enum { + using type = R; + static_assert(supported::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); +}; + +template , typename D = std::decay_t> +using enable_if_t = typename enable_if_enum && std::is_invocable_r_v, R>::type; + +template >, int> = 0> +using enum_concept = T; + +template > +struct is_scoped_enum : std::false_type {}; + +template +struct is_scoped_enum : std::bool_constant>> {}; + +template > +struct is_unscoped_enum : std::false_type {}; + +template +struct is_unscoped_enum : std::bool_constant>> {}; + +template >> +struct underlying_type {}; + +template +struct underlying_type : std::underlying_type> {}; + +#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) + +template +struct constexpr_hash_t; + +template +struct constexpr_hash_t>> { + constexpr auto operator()(Value value) const noexcept { + using U = typename underlying_type::type; + if constexpr (std::is_same_v) { // bool special case + return static_cast(value); + } else { + return static_cast(value); + } + } + using secondary_hash = constexpr_hash_t; +}; + +template +struct constexpr_hash_t>> { + static constexpr std::uint32_t crc_table[256] { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL + }; + constexpr std::uint32_t operator()(string_view value) const noexcept { + auto crc = static_cast(0xffffffffL); + for (const auto c : value) { + crc = (crc >> 8) ^ crc_table[(crc ^ static_cast(c)) & 0xff]; + } + return crc ^ 0xffffffffL; + } + + struct secondary_hash { + constexpr std::uint32_t operator()(string_view value) const noexcept { + auto acc = static_cast(2166136261ULL); + for (const auto c : value) { + acc = ((acc ^ static_cast(c)) * static_cast(16777619ULL)) & (std::numeric_limits::max)(); + } + return static_cast(acc); + } + }; +}; + +template +inline constexpr Hash hash_v{}; + +template +constexpr auto calculate_cases(std::size_t Page) noexcept { + constexpr std::array values = *GlobValues; + constexpr std::size_t size = values.size(); + + using switch_t = std::invoke_result_t; + static_assert(std::is_integral_v && !std::is_same_v); + const std::size_t values_to = (std::min)(static_cast(256), size - Page); + + std::array result{}; + auto fill = result.begin(); + { + auto first = values.begin() + static_cast(Page); + auto last = values.begin() + static_cast(Page + values_to); + while (first != last) { + *fill++ = hash_v(*first++); + } + } + + // dead cases, try to avoid case collisions + for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits::max)(); *fill++ = ++last_value) { + } + + { + auto it = result.begin(); + auto last_value = (std::numeric_limits::min)(); + for (; fill != result.end(); *fill++ = last_value++) { + while (last_value == *it) { + ++last_value, ++it; + } + } + } + + return result; +} + +template +constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v) { + if constexpr (std::is_void_v) { + std::forward(f)(std::forward(args)...); + } else { + return static_cast(std::forward(f)(std::forward(args)...)); + } +} + +enum class case_call_t { + index, + value +}; + +template +inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v) { return T{}; }; + +template <> +inline constexpr auto default_result_type_lambda = []() noexcept {}; + +template +constexpr bool has_duplicate() noexcept { + using value_t = std::decay_t; + using hash_value_t = std::invoke_result_t; + std::arraysize()> hashes{}; + std::size_t size = 0; + for (auto elem : *Arr) { + hashes[size] = hash_v(elem); + for (auto i = size++; i > 0; --i) { + if (hashes[i] < hashes[i - 1]) { + auto tmp = hashes[i]; + hashes[i] = hashes[i - 1]; + hashes[i - 1] = tmp; + } else if (hashes[i] == hashes[i - 1]) { + return false; + } else { + break; + } + } + } + return true; +} + +#define MAGIC_ENUM_CASE(val) \ + case cases[val]: \ + if constexpr ((val) + Page < size) { \ + if (!pred(values[val + Page], searched)) { \ + break; \ + } \ + if constexpr (CallValue == case_call_t::index) { \ + if constexpr (std::is_invocable_r_v>) { \ + return detail::invoke_r(std::forward(lambda), std::integral_constant{}); \ + } else if constexpr (std::is_invocable_v>) { \ + MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ + } \ + } else if constexpr (CallValue == case_call_t::value) { \ + if constexpr (std::is_invocable_r_v>) { \ + return detail::invoke_r(std::forward(lambda), enum_constant{}); \ + } else if constexpr (std::is_invocable_r_v>) { \ + MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ + } \ + } \ + break; \ + } else [[fallthrough]]; + +template ::value_type>, + typename BinaryPredicate = std::equal_to<>, + typename Lambda, + typename ResultGetterType> +constexpr decltype(auto) constexpr_switch( + Lambda&& lambda, + typename std::decay_t::value_type searched, + ResultGetterType&& def, + BinaryPredicate&& pred = {}) { + using result_t = std::invoke_result_t; + using hash_t = std::conditional_t(), Hash, typename Hash::secondary_hash>; + static_assert(has_duplicate(), "magic_enum::detail::constexpr_switch duplicated hash found, please report it: https://github.com/Neargye/magic_enum/issues."); + constexpr std::array values = *GlobValues; + constexpr std::size_t size = values.size(); + constexpr std::array cases = calculate_cases(Page); + + switch (hash_v(searched)) { + MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE) + default: + if constexpr (size > 256 + Page) { + return constexpr_switch(std::forward(lambda), searched, std::forward(def)); + } + break; + } + return def(); +} + +#undef MAGIC_ENUM_CASE + +#endif + +} // namespace magic_enum::detail + +// Checks is magic_enum supported compiler. +inline constexpr bool is_magic_enum_supported = detail::supported::value; + +template +using Enum = detail::enum_concept; + +// Checks whether T is an Unscoped enumeration type. +// Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false. +template +struct is_unscoped_enum : detail::is_unscoped_enum {}; + +template +inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; + +// Checks whether T is an Scoped enumeration type. +// Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false. +template +struct is_scoped_enum : detail::is_scoped_enum {}; + +template +inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; + +// If T is a complete enumeration type, provides a member typedef type that names the underlying type of T. +// Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed. +template +struct underlying_type : detail::underlying_type {}; + +template +using underlying_type_t = typename underlying_type::type; + +template +using enum_constant = detail::enum_constant; + +// Returns type name of enum. +template +[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_t { + constexpr string_view name = detail::type_name_v>; + static_assert(!name.empty(), "magic_enum::enum_type_name enum type does not have a name."); + + return name; +} + +// Returns number of enum values. +template > +[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t { + return detail::count_v, S>; +} + +// Returns enum value at specified index. +// No bounds checking is performed: the behavior is undefined if index >= number of enum values. +template > +[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + + if constexpr (detail::is_sparse_v) { + return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::values_v[index]; + } else { + constexpr auto min = (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v) : detail::min_v; + + return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::value(index); + } +} + +// Returns enum value at specified index. +template > +[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t> { + using D = std::decay_t; + static_assert(I < detail::count_v, "magic_enum::enum_value out of range."); + + return enum_value(I); +} + +// Returns std::array with enum values, sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t> { + return detail::values_v, S>; +} + +// Returns integer value from enum value. +template +[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t> { + return static_cast>(value); +} + +// Returns underlying value from enum value. +template +[[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t> { + return static_cast>(value); +} + +// Obtains index in enum values from enum value. +// Returns optional with index. +template > +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + using U = underlying_type_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. + } else if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { +#if defined(MAGIC_ENUM_ENABLE_HASH) + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::index>( + [](std::size_t i) { return optional{i}; }, + value, + detail::default_result_type_lambda>); +#else + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (enum_value(i) == value) { + return i; + } + } + return {}; // Invalid value or out of range. +#endif + } else { + const auto v = static_cast(value); + if (v >= detail::min_v && v <= detail::max_v) { + return static_cast(v - detail::min_v); + } + return {}; // Invalid value or out of range. + } +} + +// Obtains index in enum values from enum value. +// Returns optional with index. +template +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + + return enum_index(value); +} + +// Obtains index in enum values from static storage enum variable. +template >> +[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t { + constexpr auto index = enum_index, S>(V); + static_assert(index, "magic_enum::enum_index enum value does not have a index."); + + return *index; +} + +// Returns name from static storage enum variable. +// This version is much lighter on the compile times and is not restricted to the enum_range limitation. +template +[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t { + constexpr string_view name = detail::enum_name_v, V>; + static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name."); + + return name; +} + +// Returns name from enum value. +// If enum value does not have name or value out of range, returns empty string. +template > +[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + + if (const auto i = enum_index(value)) { + return detail::names_v[*i]; + } + return {}; +} + +// Returns name from enum value. +// If enum value does not have name or value out of range, returns empty string. +template +[[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t { + using D = std::decay_t; + + return enum_name(value); +} + +// Returns std::array with names, sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t> { + return detail::names_v, S>; +} + +// Returns std::array with pairs (value, name), sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t> { + return detail::entries_v, S>; +} + +// Allows you to write magic_enum::enum_cast("bar", magic_enum::case_insensitive); +inline constexpr auto case_insensitive = detail::case_insensitive<>{}; + +// Obtains enum value from integer value. +// Returns optional with enum value. +template > +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { + using D = std::decay_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. + } else { + if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { +#if defined(MAGIC_ENUM_ENABLE_HASH) + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( + [](D v) { return optional{v}; }, + static_cast(value), + detail::default_result_type_lambda>); +#else + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (value == static_cast>(enum_value(i))) { + return static_cast(value); + } + } + return {}; // Invalid value or out of range. +#endif + } else { + if (value >= detail::min_v && value <= detail::max_v) { + return static_cast(value); + } + return {}; // Invalid value or out of range. + } + } +} + +// Obtains enum value from name. +// Returns optional with enum value. +template , typename BinaryPredicate = std::equal_to<>> +[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { + using D = std::decay_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. +#if defined(MAGIC_ENUM_ENABLE_HASH) + } else if constexpr (detail::is_default_predicate()) { + return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( + [](std::size_t i) { return optional{detail::values_v[i]}; }, + value, + detail::default_result_type_lambda>, + [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); }); +#endif + } else { + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (detail::cmp_equal(value, detail::names_v[i], p)) { + return enum_value(i); + } + } + return {}; // Invalid value or out of range. + } +} + +// Checks whether enum contains value with such value. +template > +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + using U = underlying_type_t; + + return static_cast(enum_cast(static_cast(value))); +} + +// Checks whether enum contains value with such value. +template +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + using U = underlying_type_t; + + return static_cast(enum_cast(static_cast(value))); +} + +// Checks whether enum contains value with such integer value. +template > +[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + + return static_cast(enum_cast(value)); +} + +// Checks whether enum contains enumerator with such name. +template , typename BinaryPredicate = std::equal_to<>> +[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { + using D = std::decay_t; + + return static_cast(enum_cast(value, std::move(p))); +} + +template +inline constexpr auto as_flags = AsFlags ? detail::enum_subtype::flags : detail::enum_subtype::common; + +template +inline constexpr auto as_common = AsFlags ? detail::enum_subtype::common : detail::enum_subtype::flags; + +namespace bitwise_operators { + +template = 0> +constexpr E operator~(E rhs) noexcept { + return static_cast(~static_cast>(rhs)); +} + +template = 0> +constexpr E operator|(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) | static_cast>(rhs)); +} + +template = 0> +constexpr E operator&(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) & static_cast>(rhs)); +} + +template = 0> +constexpr E operator^(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); +} + +template = 0> +constexpr E& operator|=(E& lhs, E rhs) noexcept { + return lhs = (lhs | rhs); +} + +template = 0> +constexpr E& operator&=(E& lhs, E rhs) noexcept { + return lhs = (lhs & rhs); +} + +template = 0> +constexpr E& operator^=(E& lhs, E rhs) noexcept { + return lhs = (lhs ^ rhs); +} + +} // namespace magic_enum::bitwise_operators + +} // namespace magic_enum + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif + +#undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN +#undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN +#undef MAGIC_ENUM_VS_2017_WORKAROUND +#undef MAGIC_ENUM_ARRAY_CONSTEXPR +#undef MAGIC_ENUM_FOR_EACH_256 + +#endif // NEARGYE_MAGIC_ENUM_HPP diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__hash.txt new file mode 100644 index 000000000..0b51217fb --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__hash.txt @@ -0,0 +1 @@ +14566708169643289121 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__sig.txt new file mode 100644 index 000000000..81d764c9d --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Frost/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_AtronachFrostBlocking \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__hash.txt new file mode 100644 index 000000000..4b704ea36 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__hash.txt @@ -0,0 +1 @@ +9011796343880008240 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__sig.txt new file mode 100644 index 000000000..5941a8483 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Atronach_Storm/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_AtronachStormDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__hash.txt new file mode 100644 index 000000000..d8409d1be --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__hash.txt @@ -0,0 +1 @@ +12283352931604624777 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__sig.txt new file mode 100644 index 000000000..fc129f850 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_BearDefault = 60 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__hash.txt new file mode 100644 index 000000000..9664f7f0b --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__hash.txt @@ -0,0 +1 @@ +6432093022549018934 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__sig.txt new file mode 100644 index 000000000..b62b2b468 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chaurus/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_DefaultChaurus_MT \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__hash.txt new file mode 100644 index 000000000..6f1e64f1f --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__hash.txt @@ -0,0 +1 @@ +5224687413749858422 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__sig.txt new file mode 100644 index 000000000..0ecaaf233 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Chicken/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_Chicken_Default_MT \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__hash.txt new file mode 100644 index 000000000..eb3f15e3f --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__hash.txt @@ -0,0 +1 @@ +17103635255379484992 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__sig.txt new file mode 100644 index 000000000..d909ca498 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_CowDefault = 46 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__hash.txt new file mode 100644 index 000000000..19a28f55e --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__hash.txt @@ -0,0 +1 @@ +1832497254465648632 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__sig.txt new file mode 100644 index 000000000..78ab1a433 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_DeerDefault = 46 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__hash.txt new file mode 100644 index 000000000..d8409d1be --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__hash.txt @@ -0,0 +1 @@ +12283352931604624777 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__sig.txt new file mode 100644 index 000000000..fb39650af --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_DogRun \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__bool.txt new file mode 100644 index 000000000..b2eac1a4d --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__bool.txt @@ -0,0 +1,7 @@ +IsStaggering +IsUDAnimation +IsDying +bTailTurnOneMore +bNoStagger +IsRight +IsEnraging \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__float.txt new file mode 100644 index 000000000..bf20b471a --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__float.txt @@ -0,0 +1 @@ +playbackSpeed \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/ULTIDRAGON__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__bool.txt new file mode 100644 index 000000000..ce85a02af --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__bool.txt @@ -0,0 +1,25 @@ +bAnimationDriven +bVoiceReady +bWantCastVoice +IsAttackReady +IsShouting +isMoving +bSpeedSynced +IsOnGround +bLookAtTarget +bCanLookAtTarget +bEquipOk +IsBusy +bIsSynced +IsFlapping +IsGliding +HasTweenSpeed +IsTurningLeft +IsTurningRight +IsMovingForward +BSLookAtModifier_CanLookOutsideLimit +MoveDirZ +bFullyMotionDriven +bNoFootIK +bFootIK +LookAtOutOfRange \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__float.txt new file mode 100644 index 000000000..54e9990bf --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__float.txt @@ -0,0 +1,27 @@ +Pitch +TurnDelta +Direction +Speed +TargetSpeed +TurnDeltaDamped +PitchDeltaDamped +TargetSpeedDamped +MaxSpeedDamped +LookAtHeadingMaxAngle +m_errorOut +FlightPitchBlend +TweenEntryDirection +LipBigAah +LipDST +LipEee +LipFV +PitchDelta +DistToGoal +PathAngle +BSLookAtModifier_m_onGain +BSLookAtModifier_m_offGain +TimeStep +DirectionDamped +TurnDeltaTarget +PitchDeltaTarget +FlightPitchBlendTarget \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__hash.txt new file mode 100644 index 000000000..c3f149fbc --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__hash.txt @@ -0,0 +1 @@ +18331100224015734760 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__int.txt new file mode 100644 index 000000000..e68d0a8d6 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__int.txt @@ -0,0 +1,3 @@ +iSyncIdleLocomotion +iSyncTurnState +iState \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__sig.txt new file mode 100644 index 000000000..f412788a5 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_DragonDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__hash.txt new file mode 100644 index 000000000..1a5b256b4 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__hash.txt @@ -0,0 +1 @@ +1556693752012287718 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__sig.txt new file mode 100644 index 000000000..e0b0a4d52 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Draugr/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_DraugrDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__hash.txt new file mode 100644 index 000000000..18ab3265e --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__hash.txt @@ -0,0 +1 @@ +15924684633707834553 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__sig.txt new file mode 100644 index 000000000..7d82bc451 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_DefaultSpider_MT = 41 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__hash.txt new file mode 100644 index 000000000..392e60e2a --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__hash.txt @@ -0,0 +1 @@ +3009402738794250552 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__sig.txt new file mode 100644 index 000000000..22e68c23d --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Falmer_Master/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_FalmerDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__hash.txt new file mode 100644 index 000000000..310fe1d80 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__hash.txt @@ -0,0 +1 @@ +1928879069472700161 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__sig.txt new file mode 100644 index 000000000..be6d1948f --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_DefaultSpider_MT = 25 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__hash.txt new file mode 100644 index 000000000..6ca4b1bcd --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__hash.txt @@ -0,0 +1 @@ +14787123347890181413 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__sig.txt new file mode 100644 index 000000000..fd5ee5e16 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Giant/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_GiantDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__hash.txt new file mode 100644 index 000000000..6e2e5b000 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__hash.txt @@ -0,0 +1 @@ +5260053452598805463 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__sig.txt new file mode 100644 index 000000000..86cddfba1 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_GoatDefault = 46 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__hash.txt new file mode 100644 index 000000000..133ce7a8a --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__hash.txt @@ -0,0 +1 @@ +3017922126943190855 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__sig.txt new file mode 100644 index 000000000..dc6adb834 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Hargraven_Master/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_HagravenDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__hash.txt new file mode 100644 index 000000000..fadcebf60 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__hash.txt @@ -0,0 +1 @@ +6046020211772183226 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__sig.txt new file mode 100644 index 000000000..940120b26 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_HorkerDefault = 46 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__hash.txt new file mode 100644 index 000000000..cb4574d68 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__hash.txt @@ -0,0 +1 @@ +3064138997224155673 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__sig.txt new file mode 100644 index 000000000..986235c8b --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_HorseDefault = 47 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__hash.txt new file mode 100644 index 000000000..75cb72413 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__hash.txt @@ -0,0 +1 @@ +13065750443784029010 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__sig.txt new file mode 100644 index 000000000..d2dabb170 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_MammothDefault = 46 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__hash.txt new file mode 100644 index 000000000..b1903ba33 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__hash.txt @@ -0,0 +1 @@ +9498225481650921683 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__sig.txt new file mode 100644 index 000000000..d819dd84b --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mudcrab/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_MCrab_Default_MT \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__hash.txt new file mode 100644 index 000000000..eaf466d85 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__hash.txt @@ -0,0 +1 @@ +11071881714804970071 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__sig.txt new file mode 100644 index 000000000..99a73b2d9 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Rabbit/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_Hare_Default_MT \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__hash.txt new file mode 100644 index 000000000..e156a7f1c --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__hash.txt @@ -0,0 +1 @@ +8391591236278645567 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__sig.txt new file mode 100644 index 000000000..4bae72f16 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_SabreCatDefault = 46 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__hash.txt new file mode 100644 index 000000000..ee697cef0 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__hash.txt @@ -0,0 +1 @@ +5600819660802946846 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__sig.txt new file mode 100644 index 000000000..ae7b6614c --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Scrib/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_ScribDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__hash.txt new file mode 100644 index 000000000..95f1ed0e9 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__hash.txt @@ -0,0 +1 @@ +2357248884501192123 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__sig.txt new file mode 100644 index 000000000..e8e0eb0c7 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_SkeeverDefault = 46 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__hash.txt new file mode 100644 index 000000000..6845ee992 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__hash.txt @@ -0,0 +1 @@ +10099378323021197839 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__sig.txt new file mode 100644 index 000000000..a609a60e2 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Spriggan/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_SprigganDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__hash.txt new file mode 100644 index 000000000..565908a05 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__hash.txt @@ -0,0 +1 @@ +12323911819758128165 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__sig.txt new file mode 100644 index 000000000..245bb6137 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Steam/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_SteamDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__hash.txt new file mode 100644 index 000000000..018f14bd9 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__hash.txt @@ -0,0 +1 @@ +12972242470338891659 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__sig.txt new file mode 100644 index 000000000..63359a0a8 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Troll/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_TrollDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__hash.txt new file mode 100644 index 000000000..8c62d9867 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__hash.txt @@ -0,0 +1 @@ +6408297713843182476 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__sig.txt new file mode 100644 index 000000000..ca3764748 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireBrute/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_GargoyleDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__hash.txt new file mode 100644 index 000000000..bfe0cbcd9 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__hash.txt @@ -0,0 +1 @@ +16269673692629748097 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__sig.txt new file mode 100644 index 000000000..aa1e867b9 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/VampireLord/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_VampireLordDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__hash.txt new file mode 100644 index 000000000..393159226 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__hash.txt @@ -0,0 +1 @@ +9732983738769370819 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__sig.txt new file mode 100644 index 000000000..a0e5594f5 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Werewolf/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_WerewolfBeastDefault \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__bool.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__float.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__hash.txt new file mode 100644 index 000000000..acaffc0fb --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__hash.txt @@ -0,0 +1 @@ +1344932221912162919 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__int.txt new file mode 100644 index 000000000..e69de29bb diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__sig.txt new file mode 100644 index 000000000..04acdd8f9 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__sig.txt @@ -0,0 +1 @@ +iState_WolfDefault = 46 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__bool.txt new file mode 100644 index 000000000..3613707e5 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__bool.txt @@ -0,0 +1,7 @@ +tdmHeadtrackingBoth +tdmHeadtrackingBehavior +tdmHeadtrackingSKSE +TDM_Dodge +TDM_TargetLock +tdmHeadtrackingBehavior +360HorseGen \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__float.txt new file mode 100644 index 000000000..1e3558d19 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__float.txt @@ -0,0 +1,19 @@ +TDM_Roll +TDM_Pitch +TDM_SpineRot +TDM_VelocityX +TDM_VelocityY +AimRemap +TDM_HorseAimTurn_Angle +TDM_Remap +Fwd_Remap +Lft_Remap +Rgt_Remap +Bwd_Remap +TDM_HorseAimTurn_Angle_Absolute +TDM_HorseAimTurn_PlayerPitch +TDM_Roll +TDM_Pitch +TDM_SpineRot +TDM_VelocityX +TDM_VelocityY \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__int.txt new file mode 100644 index 000000000..422027866 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TDM__int.txt @@ -0,0 +1 @@ +360AimingDir \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__bool.txt new file mode 100644 index 000000000..32d405dd7 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__bool.txt @@ -0,0 +1,6 @@ +rightRace +registered +NPCDodgeAI +NPCInvincibleFrame +changedone +CrouchSlideMod_Installed \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__float.txt new file mode 100644 index 000000000..090afdb67 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__float.txt @@ -0,0 +1,12 @@ +MaxSpeedPenalty +DodgeSpeed +IFrameR +IFrameS +distance +dagger +unarmed +shield +onehanded +twohanded +InvincibleFrameR +InvincibleFrameS diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__int.txt new file mode 100644 index 000000000..3f8a595ee --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDMSPID__int.txt @@ -0,0 +1,18 @@ +Stamina +StaminaCostR +StaminaCostS +SneakKey +DDodgeStyle +chance6 +chance16 +frequency2 +frequency3 +staminacost +pseudorandom16 +pseudorandom6 +NPCIFrame +GPFlag +DAFlag +DodgeID +playerSex +warningcount \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__bool.txt new file mode 100644 index 000000000..4403fc049 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__bool.txt @@ -0,0 +1,6 @@ +rightRace +StepdodgeStaminaFixEnabled +registered +Counted +changedone +CrouchSlideMod_Installed \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__float.txt new file mode 100644 index 000000000..e3d4c48a1 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__float.txt @@ -0,0 +1,11 @@ +MaxSpeedPenalty +SpeedPenalty +DodgeSpeed +IFrameR +IFrameS +distance +dagger +unarmed +shield +onehanded +twohanded diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__int.txt new file mode 100644 index 000000000..6c98691e0 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/TUDM__int.txt @@ -0,0 +1,23 @@ +Stamina +StaminaCostR +StaminaCostS +SneakKey +DodgeSpeedMethod +DDodgeStyle +chance6 +chance16 +frequency1 +frequency2 +frequency3 +staminacost +pseudorandom16 +pseudorandom6 +StaminaCostR +StaminaCostS +NPCIFrame +playerSex +CombatTimerID +DodgeID +warningcount +SneakKey +DodgeToggleKey \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__bool.txt new file mode 100644 index 000000000..d61840fe2 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__bool.txt @@ -0,0 +1,60 @@ +bEquipOk +bMotionDriven +IsBeastRace +IsSneaking +IsBleedingOut +IsCastingDual +Is1HM +IsCastingRight +IsCastingLeft +IsBlockHit +IsPlayer +IsNPC +bIsSynced +bVoiceReady +bWantCastLeft +bWantCastRight +bWantCastVoice +b1HM_MLh_attack +b1HMCombat +bAnimationDriven +bCastReady +IsAttacking +bAllowRotation +bMagicDraw +bMLh_Ready +bMRh_Ready +bInMoveState +bSprintOK +bIdlePlaying +bIsDialogueExpressive +bAnimObjectLoaded +bEquipUnequip +bAttached +bIsH2HSolo +bHeadTracking +bIsRiding +bTalkable +bRitualSpellActive +bInJumpState +bHeadTrackSpine +bLeftHandAttack +bIsInMT +bHumanoidFootIKEnable +bHumanoidFootIKDisable +bStaggerPlayerOverride +bNoStagger +bIsStaffLeftCasting +bPerkShieldCharge +bPerkQuickShot +IsBlocking +IsBashing +IsStaggering +IsRecoiling +IsEquipping +IsUnequipping +isInFurniture +bNeutralState +bBowDrawn +PitchOverride +NotCasting \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__float.txt new file mode 100644 index 000000000..d5575a0a8 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__float.txt @@ -0,0 +1,13 @@ +TurnDelta +Direction +SpeedSampled +weapAdj +Speed +CastBlend +PitchOffset +SpeedDamped +Pitch +VelocityZ +1stPRot +1stPRotDamped +CastBlendDamped \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__hash.txt new file mode 100644 index 000000000..bfd1e8cdc --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__hash.txt @@ -0,0 +1 @@ +17585368238253125375 \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__int.txt new file mode 100644 index 000000000..28da60975 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__int.txt @@ -0,0 +1,14 @@ +iRightHandEquipped +iLeftHandEquipped +i1HMState +iState +iLeftHandType +iRightHandType +iSyncIdleLocomotion +iSyncForwardState +iSyncTurnState +iIsInSneak +iWantBlock +iRegularAttack +testint +currentDefaultState \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__name.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__name.txt new file mode 100644 index 000000000..8b25206ff --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__name.txt @@ -0,0 +1 @@ +master \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__sig.txt new file mode 100644 index 000000000..7dcbac2f5 --- /dev/null +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__sig.txt @@ -0,0 +1,2 @@ +bHumanoidFootIKEnable + From 23f7692e122317c1aa7221391cac07ff0f179542 Mon Sep 17 00:00:00 2001 From: rfortier Date: Tue, 5 Mar 2024 22:36:14 -0500 Subject: [PATCH 35/86] There's a typo in the Speed behavior var in some formIDs of the base game (lower case "speed"). If we get a miss on Speed try again with "speed". If this is the only one, this is a safer fix than going to case-insensitive search, which could have its own issues. Raised the log level to Error for these sorts of things. --- Code/client/ModCompat/BehaviorVar.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index b53a51ac3..d7ee348ea 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -83,9 +83,9 @@ void BehaviorVar::seedAnimationVariables( { auto strValue = origVars.find(hash, item); if (strValue.empty()) - spdlog::warn("BehaviorVar::seedAnimationVariables unable to find string for original BooleanVar {}", item); + spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original BooleanVar {}", item); else if (reversemap.find(strValue) == reversemap.end()) - spdlog::warn("BehaviorVar::seedAnimationVariables unable to find BooleanVar {}", strValue); + spdlog::error("BehaviorVar::seedAnimationVariables unable to find BooleanVar {}", strValue); else boolVars.insert(reversemap[strValue]); } @@ -93,9 +93,13 @@ void BehaviorVar::seedAnimationVariables( { auto strValue = origVars.find(hash, item); if (strValue.empty()) - spdlog::warn("BehaviorVar::seedAnimationVariables unable to find string for original FloatVar {}", item); + spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original FloatVar {}", item); else if (reversemap.find(strValue) == reversemap.end()) - spdlog::warn("BehaviorVar::seedAnimationVariables unable to find FloatVar {}", strValue); + if (strValue == "Speed" && reversemap.find("speed") != reversemap.end()) // Fix typo in base game. + strValue = "speed", spdlog::error("BehaviorVar::seedAnimationVariables successfully compensated for incorrect capitalization of Floatvar 'speed'"); + + if (reversemap.find(strValue) == reversemap.end()) + spdlog::error("BehaviorVar::seedAnimationVariables unable to find FloatVar {}", strValue); else floatVars.insert(reversemap[strValue]); } @@ -103,9 +107,9 @@ void BehaviorVar::seedAnimationVariables( { auto strValue = origVars.find(hash, item); if (strValue.empty()) - spdlog::warn("BehaviorVar::seedAnimationVariables unable to find string for original IntegerVar {}", item); + spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original IntegerVar {}", item); else if (reversemap.find(strValue) == reversemap.end()) - spdlog::warn("BehaviorVar::seedAnimationVariables unable to find IntegerVar {}", strValue); + spdlog::error("BehaviorVar::seedAnimationVariables unable to find IntegerVar {}", strValue); else intVars.insert(reversemap[strValue]); } From ecfc0024487c4c58467ad22b76b270274ed85a25 Mon Sep 17 00:00:00 2001 From: rfortier Date: Fri, 8 Mar 2024 16:39:33 -0500 Subject: [PATCH 36/86] Beast mode support. Support remembering the modded humanoid/Master hash so exiting a beast modes can return to that (vs. a force-plug of the original unmodded behavior). --- Code/client/Games/ActorExtension.h | 5 +- Code/client/Games/Skyrim/PlayerCharacter.cpp | 4 + Code/client/ModCompat/BehaviorVar.cpp | 244 ++++++++++--------- Code/client/ModCompat/BehaviorVar.h | 23 +- 4 files changed, 155 insertions(+), 121 deletions(-) diff --git a/Code/client/Games/ActorExtension.h b/Code/client/Games/ActorExtension.h index e2d7d4f07..19273ec3d 100644 --- a/Code/client/Games/ActorExtension.h +++ b/Code/client/Games/ActorExtension.h @@ -20,7 +20,10 @@ struct ActorExtension ActionEvent LatestAnimation{}; size_t GraphDescriptorHash = 0; +#ifdef MODDED_BEHAVIOR_COMPATIBILITY + size_t OrigGraphDescriptorHash = 0; // To aid popping back from beast forms. +#endif MODDED_BEHAVIOR_COMPATIBILITY -private: + private: uint32_t onlineFlags{0}; }; diff --git a/Code/client/Games/Skyrim/PlayerCharacter.cpp b/Code/client/Games/Skyrim/PlayerCharacter.cpp index 9800851ef..951f6bd78 100644 --- a/Code/client/Games/Skyrim/PlayerCharacter.cpp +++ b/Code/client/Games/Skyrim/PlayerCharacter.cpp @@ -163,6 +163,10 @@ void TP_MAKE_THISCALL(HookSetBeastForm, void, void* apUnk1, void* apUnk2, bool a if (!aEntering) { PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = AnimationGraphDescriptor_Master_Behavior::m_key; +#ifdef MODDED_BEHAVIOR_COMPATIBILITY + PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = PlayerCharacter::Get()->GetExtension()->OrigGraphDescriptorHash; +#endif MODDED_BEHAVIOR_COMPATIBILITY + World::Get().GetRunner().Trigger(BeastFormChangeEvent()); } diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index d7ee348ea..8f4a8d74b 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -2,6 +2,11 @@ // // Core support for modified behavior (as in Nemesis or Pandora behavior modification or extension). // +// Credit to Edho08 for the original implementation. This version advances to include support +// for unlimited behavior variables, for seeding modded behaviors with the original BehaviorVars +// (decoupling STR devs decisions from what modders need to know) and support for beast forms +// among many more changes. +// // One of the greatest features ensuring the longevity of Bethesda games is their support // for community modification, and many of the most popular mods also change the behavior // of creatures. STR and FTR don't support mods as a matter of policy. And supporting @@ -39,7 +44,7 @@ std::mutex mutex_lock; // How long we failList a behavior hash that can't be translated. // See explanation in BehaviorVar::Patch using namespace std::literals; -const std::chrono::steady_clock::duration FAILLIST_DURATION(5min); +const std::chrono::steady_clock::duration FAILLIST_DURATION(10min); BehaviorVar* BehaviorVar::single = nullptr; BehaviorVar* BehaviorVar::Get() @@ -81,7 +86,7 @@ void BehaviorVar::seedAnimationVariables( // without a string, or a string without a number. for (auto& item : pDescriptor->BooleanLookUpTable) { - auto strValue = origVars.find(hash, item); + const auto strValue = origVars.find(hash, item); if (strValue.empty()) spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original BooleanVar {}", item); else if (reversemap.find(strValue) == reversemap.end()) @@ -105,7 +110,7 @@ void BehaviorVar::seedAnimationVariables( } for (auto& item : pDescriptor->IntegerLookupTable) { - auto strValue = origVars.find(hash, item); + const auto strValue = origVars.find(hash, item); if (strValue.empty()) spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original IntegerVar {}", item); else if (reversemap.find(strValue) == reversemap.end()) @@ -115,6 +120,121 @@ void BehaviorVar::seedAnimationVariables( } } +const std::vector BehaviorVar::tokenizeBehaviorSig(const std::string signature) const +{ + // Syntax is [!]sig1[,!sig2]... Must be at least one. Each signature var possibly negated + // (meaning it MUST NOT be in the BehaviorVars of the actor). Separated by commas. + // Requires that whitespace has already been deleted (was, when file was read). + // Tokenize on ',' + // + std::vector retVal; + size_t commaPos; + size_t offset = 0; + + do + { + commaPos = signature.find(',', offset); + retVal.push_back(signature.substr(offset, commaPos)); + offset = commaPos + 1; + + } while (commaPos != std::string::npos); + + return retVal; +} + +const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uint64_t acNewHash, const Replacer& acOldBehavior, std::map& acReverseMap) +{ + // Build the set of BehaviorVar strings as sets (not vectors) to eliminate dups + // Also, we want the set sorted, so these have to be std::sets. TiltedPhoques::Set + // uses a hash map instead of a sorted tree, and I don't want to have to figure + // out how to override that. + std::set boolVar; + std::set floatVar; + std::set intVar; + + // If we can find the original behavior that is being modded, + // get the descriptor and seed the behavior vars with it. + // That way mod developers only need to know what vars their + // mod adds, they don't have to know what the STR devs picked + const AnimationGraphDescriptor* pTmpGraph = nullptr; + if (acOldBehavior.origHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(acOldBehavior.origHash))) + { + seedAnimationVariables(acOldBehavior.origHash, pTmpGraph, acReverseMap, boolVar, floatVar, intVar); + spdlog::info("Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", + acOldBehavior.origHash, boolVar.size(), floatVar.size(), intVar.size()); + } + + // Check requested behavior vars for those that ARE legit + // behavior vars for this Actor AND are not yet synced + int foundCount = 0; + for (auto& item : acOldBehavior.syncBooleanVar) + { + bool found = acReverseMap.find(item) != acReverseMap.end(); + if (found && boolVar.find(acReverseMap[item]) == boolVar.end()) + { + if (foundCount++ == 0) + spdlog::info("Boolean variables added to sync:"); + boolVar.insert(acReverseMap[item]); + spdlog::info(" {}", item); + } + } + if (foundCount) + spdlog::info("Now have {} boolVar descriptors after searching {} BehavivorVar strings", boolVar.size(), + acOldBehavior.syncBooleanVar.size()); + + foundCount = 0; + for (auto& item : acOldBehavior.syncFloatVar) + { + bool found = acReverseMap.find(item) != acReverseMap.end(); + if (found && floatVar.find(acReverseMap[item]) == floatVar.end()) + { + if (foundCount++ == 0) + spdlog::info("Float variables added to sync:"); + floatVar.insert(acReverseMap[item]); + spdlog::info(" {}", item); + } + } + if (foundCount) + spdlog::info("Now have {} floatVar descriptors after searching {} BehavivorVar strings", floatVar.size(), + acOldBehavior.syncFloatVar.size()); + + foundCount = 0; + for (auto& item : acOldBehavior.syncIntegerVar) + { + bool found = acReverseMap.find(item) != acReverseMap.end(); + if (found && intVar.find(acReverseMap[item]) == intVar.end()) + { + if (foundCount++ == 0) + spdlog::info("Int variables added to sync:"); + intVar.insert(acReverseMap[item]); + spdlog::info(" {}", item); + } + } + if (foundCount) + spdlog::info("Now have {} intVar descriptors after searching {} BehavivorVar strings", intVar.size(), + acOldBehavior.syncIntegerVar.size()); + + // Reshape the (sorted, unique) sets to vectors + TiltedPhoques::Vector boolVector(boolVar.begin(), boolVar.end()); + TiltedPhoques::Vector floatVector(floatVar.begin(), floatVar.end()); + TiltedPhoques::Vector intVector(intVar.begin(), intVar.end()); + + // Construct a new descriptor + auto panimGraphDescriptor = new AnimationGraphDescriptor(); + + // This is a bit grubby, but it IS a struct with public members. + // Maybe the devs will help us out by agreeing to an additional constructor. + panimGraphDescriptor->BooleanLookUpTable = boolVector; + panimGraphDescriptor->FloatLookupTable = floatVector; + panimGraphDescriptor->IntegerLookupTable = intVector; + + // Add the new graph to the known behavior graphs + new AnimationGraphDescriptorManager::Builder(AnimationGraphDescriptorManager::Get(), acNewHash, *panimGraphDescriptor); + return AnimationGraphDescriptorManager::Get().GetDescriptor(acNewHash); +} + + + const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apManager, Actor* apActor) { // Serialize, Actors are multi-threaded. Might not be strictly necessary, I think we're on @@ -129,7 +249,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa #if TP_SKYRIM64 // If it is the player-character AND they are in 1st person, we don't have the data to mod them; - // Used the base game animation graphs until a Master Behavior actor enters the room. Could be an NPC, + // Use the base game animation graphs until a Master Behavior actor enters the room. Could be an NPC, // but will always happen no later than when the 2nd person joins the server and room. // Remote players are ALWAYS in 3rd person by definition if (hexFormID == 0x14 && PlayerCamera::Get()->IsFirstPerson()) @@ -189,115 +309,13 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa } spdlog::info("Found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", hash, hexFormID, iter->creatureName, iter->signatureVar); - // Build the set of BehaviorVar strings as sets (not vectors) to eliminate dups - // Also, we want the set sorted, to make sure we get the same hash if mods - // end up rearranging order, so these have to be std::set s. TiltedPhoques::Set - // uses a hash map instead of a sorted tree, and I don't want to have to figure - // out how to override that. - std::set boolVar; - std::set floatVar; - std::set intVar; - - // If we can find the original behavior that is being modded, - // get the descriptor and seed the behavior vars with it. - // That way mod developers only need to know what vars their - // mod adds, they don't have to know what the STR devs picked - const AnimationGraphDescriptor* pTmpGraph = nullptr; - if (iter->orgHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(iter->orgHash))) - { - seedAnimationVariables(iter->orgHash, pTmpGraph, reversemap, boolVar, floatVar, intVar); - spdlog::info("Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", - iter->orgHash, boolVar.size(), floatVar.size(), intVar.size()); - } - - // Check requested behavior vars for those that ARE legit - // behavior vars for this Actor AND are not yet synced - int foundCount = 0; - for (auto& item : iter->syncBooleanVar) - { - bool found = reversemap.find(item) != reversemap.end(); - if (found && boolVar.find(reversemap[item]) == boolVar.end()) - { - if (foundCount++ == 0) - spdlog::info("Boolean variables added to sync:"); - boolVar.insert(reversemap[item]); - spdlog::info(" {}", item); - } - - } - if (foundCount) - spdlog::info("Now have {} boolVar descriptors after searching {} BehavivorVar strings", boolVar.size(), iter->syncBooleanVar.size()); - - foundCount = 0; - for (auto& item : iter->syncFloatVar) - { - bool found = reversemap.find(item) != reversemap.end(); - if (found && floatVar.find(reversemap[item]) == floatVar.end()) - { - if (foundCount++ == 0) - spdlog::info("Float variables added to sync:"); - floatVar.insert(reversemap[item]); - spdlog::info(" {}", item); - } - } - if (foundCount) - spdlog::info("Now have {} floatVar descriptors after searching {} BehavivorVar strings", floatVar.size(), iter->syncFloatVar.size()); - - foundCount = 0; - for (auto& item : iter->syncIntegerVar) - { - bool found = reversemap.find(item) != reversemap.end(); - if (found && intVar.find(reversemap[item]) == intVar.end()) - { - if (foundCount++ == 0) - spdlog::info("Int variables added to sync:"); - intVar.insert(reversemap[item]); - spdlog::info(" {}", item); - } - } - if (foundCount) - spdlog::info("Now have {} intVar descriptors after searching {} BehavivorVar strings", intVar.size(), iter->syncIntegerVar.size()); - -#if 0 // There are no limits, flex arrays now. Will come back and delete if it works. - - // Ensure we aren't over the limits. If we are, we won't update - // the animation. Performance will be terrible unless we kill some of the logging - // or keep track of failed signatures. - std::string msgString; - if (boolVar.size() > 64) - msgString = "boolean"; - - else if ((floatVar.size() + intVar.size()) > 64) - msgString = "float+integer"; - - if (msgString.size() > 0) - { - spdlog::error("Too many {} behavior vars to sync for actor, max is 64.", msgString); - spdlog::error("Actor with formID {:x}, signature {}, original hash {} cannot be synced", - hexFormID, iter->orgHash, iter->signatureVar); - spdlog::error("Fail listing behavior hash {:x} found on formID {:x}", hash, hexFormID); - failList(hash); - return nullptr; - } - #endif - - // Reshape the (sorted, unique) sets to vectors - TiltedPhoques::Vector boolVector(boolVar.begin(), boolVar.end()); - TiltedPhoques::Vector floatVector(floatVar.begin(), floatVar.end()); - TiltedPhoques::Vector intVector(intVar.begin(), intVar.end()); + // Save the new hash for the actor, and save it as the original actor hash. + // The latter is to assist with humanoid actors popping back from a beast form. + pExtendedActor->GraphDescriptorHash = hash; + pExtendedActor->OrigGraphDescriptorHash = hash; - // Construct a new descriptor - auto panimGraphDescriptor = new AnimationGraphDescriptor(); + return constructModdedDescriptor(hash, *biter, reversemap); - // This is a bit grubby, but it IS a struct with public members. - // Maybe the devs will help us out by agreeing to an additional constructor. - panimGraphDescriptor->BooleanLookUpTable = boolVector; - panimGraphDescriptor->FloatLookupTable = floatVector; - panimGraphDescriptor->IntegerLookupTable = intVector; - - // Add the new graph to the known behavior graphs - new AnimationGraphDescriptorManager::Builder(AnimationGraphDescriptorManager::Get(), hash, *panimGraphDescriptor); - return AnimationGraphDescriptorManager::Get().GetDescriptor(hash); } // Check if the behavior hash is on the failed liist @@ -475,7 +493,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aD // Create the replacer Replacer* result = new Replacer(); - result->orgHash = orgHash; + result->origHash = orgHash; result->signatureVar = sigVar; result->creatureName = creatureName; result->syncBooleanVar = boolVar; @@ -524,7 +542,7 @@ void BehaviorVar::Debug() spdlog::info("Dumping behavior sigs:"); for (const auto& sig : behaviorPool) { - spdlog::info("orgHash: {} => newHash: {}", sig.orgHash, sig.newHash); + spdlog::info("origHash: {} => newHash: {}", sig.origHash, sig.newHash); // bools spdlog::info("bools:"); diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index 246c2a80a..cde65b8e9 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -7,13 +7,17 @@ struct BehaviorVar { struct Replacer { - uint64_t orgHash; + uint64_t origHash; uint64_t newHash; std::string signatureVar; std::string creatureName; std::vector syncBooleanVar; std::vector syncFloatVar; std::vector syncIntegerVar; + bool operator==(const uint64_t& acRHS) const + { + return origHash == acRHS; + } }; static BehaviorVar* Get(); @@ -29,12 +33,17 @@ struct BehaviorVar uint64_t invocations = 0; void seedAnimationVariables( - uint64_t hash, - const AnimationGraphDescriptor* pDescriptor, - std::map& reversemap, - std::set& boolVars, - std::set& floatVars, - std::set& intVars); + uint64_t hash, + const AnimationGraphDescriptor* pDescriptor, + std::map& reversemap, + std::set& boolVars, + std::set& floatVars, + std::set& intVars); + + const std::vector tokenizeBehaviorSig(const std::string signature) const; + const AnimationGraphDescriptor* constructModdedDescriptor( + const uint64_t acNewHash, const Replacer& acOldBehavior, + std::map& acReverseMap); std::vector loadDirs(const std::filesystem::path& acPATH); Replacer* loadReplacerFromDir(std::filesystem::path aDir); From 3b3e7b095f06b73bdac3e6570d5c49c630747819 Mon Sep 17 00:00:00 2001 From: rfortier Date: Mon, 11 Mar 2024 20:53:33 -0400 Subject: [PATCH 37/86] Several changes to improve unique signatures. Greatest changes are vastly improved error messages to warn when signatures are not unique (match multiple creatures). Those messages made possible improving many signatures. They also showed that 8 creatures simply are not unique; the only OrigVars they define are shared. Sometimes rearranged, but they all have the same 92 variables. A mod to one of these creatures will have to define a new unique signature, even if it means introducing a variable. --- Code/client/ModCompat/BehaviorVar.cpp | 169 +++++++++++++++--- Code/client/ModCompat/BehaviorVar.h | 1 + Code/client/ModCompat/BehaviorVarsMap.cpp | 2 +- Code/client/ModCompat/BehaviorVarsMap.h | 8 +- .../Bear/Vanilla__sig.txt | 2 +- .../Cow/Vanilla__sig.txt | 2 +- .../Deer/Vanilla__sig.txt | 2 +- .../Dog/Vanilla__hash.txt | 2 +- .../Dog/Vanilla__sig.txt | 2 +- .../DwarvenSpider/Vanilla__sig.txt | 2 +- .../FrostbiteSpider/Vanilla__sig.txt | 2 +- .../Goat/Vanilla__sig.txt | 2 +- .../Horker/Vanilla__sig.txt | 2 +- .../Horse/Vanilla__sig.txt | 2 +- .../Mammoth/Vanilla__sig.txt | 2 +- .../SabreCat/Vanilla__sig.txt | 2 +- .../Skeever/Vanilla__sig.txt | 2 +- .../Wolf/Vanilla__sig.txt | 2 +- .../humanoid_Master/Vanilla__sig.txt | 2 +- 19 files changed, 166 insertions(+), 44 deletions(-) diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 8f4a8d74b..90022c1ca 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -120,19 +120,27 @@ void BehaviorVar::seedAnimationVariables( } } +// Syntax for a signature is [!]sig1[,[!]sig2]... Must be at least one. Each signature var possibly negated +// signature var possibly negated (meaning it MUST NOT be in the BehaviorVars of the actor). Separated by commas. +// Requires that whitespace has already been deleted (which it was, when directories were loaded). +// Tokenize on ',' +// const std::vector BehaviorVar::tokenizeBehaviorSig(const std::string signature) const { - // Syntax is [!]sig1[,!sig2]... Must be at least one. Each signature var possibly negated - // (meaning it MUST NOT be in the BehaviorVars of the actor). Separated by commas. - // Requires that whitespace has already been deleted (was, when file was read). - // Tokenize on ',' - // + + const static std::string notVal{"!"}; std::vector retVal; size_t commaPos; size_t offset = 0; do { + if (signature[offset] == '!') + { + offset++; + retVal.push_back(notVal); + } + commaPos = signature.find(',', offset); retVal.push_back(signature.substr(offset, commaPos)); offset = commaPos + 1; @@ -142,7 +150,7 @@ const std::vector BehaviorVar::tokenizeBehaviorSig(const std::strin return retVal; } -const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uint64_t acNewHash, const Replacer& acOldBehavior, std::map& acReverseMap) +const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uint64_t acNewHash, const Replacer& acReplacer, std::map& acReverseMap) { // Build the set of BehaviorVar strings as sets (not vectors) to eliminate dups // Also, we want the set sorted, so these have to be std::sets. TiltedPhoques::Set @@ -157,17 +165,17 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin // That way mod developers only need to know what vars their // mod adds, they don't have to know what the STR devs picked const AnimationGraphDescriptor* pTmpGraph = nullptr; - if (acOldBehavior.origHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(acOldBehavior.origHash))) + if (acReplacer.origHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(acReplacer.origHash))) { - seedAnimationVariables(acOldBehavior.origHash, pTmpGraph, acReverseMap, boolVar, floatVar, intVar); + seedAnimationVariables(acReplacer.origHash, pTmpGraph, acReverseMap, boolVar, floatVar, intVar); spdlog::info("Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", - acOldBehavior.origHash, boolVar.size(), floatVar.size(), intVar.size()); + acReplacer.origHash, boolVar.size(), floatVar.size(), intVar.size()); } // Check requested behavior vars for those that ARE legit // behavior vars for this Actor AND are not yet synced int foundCount = 0; - for (auto& item : acOldBehavior.syncBooleanVar) + for (auto& item : acReplacer.syncBooleanVar) { bool found = acReverseMap.find(item) != acReverseMap.end(); if (found && boolVar.find(acReverseMap[item]) == boolVar.end()) @@ -180,10 +188,10 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin } if (foundCount) spdlog::info("Now have {} boolVar descriptors after searching {} BehavivorVar strings", boolVar.size(), - acOldBehavior.syncBooleanVar.size()); + acReplacer.syncBooleanVar.size()); foundCount = 0; - for (auto& item : acOldBehavior.syncFloatVar) + for (auto& item : acReplacer.syncFloatVar) { bool found = acReverseMap.find(item) != acReverseMap.end(); if (found && floatVar.find(acReverseMap[item]) == floatVar.end()) @@ -196,10 +204,10 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin } if (foundCount) spdlog::info("Now have {} floatVar descriptors after searching {} BehavivorVar strings", floatVar.size(), - acOldBehavior.syncFloatVar.size()); + acReplacer.syncFloatVar.size()); foundCount = 0; - for (auto& item : acOldBehavior.syncIntegerVar) + for (auto& item : acReplacer.syncIntegerVar) { bool found = acReverseMap.find(item) != acReverseMap.end(); if (found && intVar.find(acReverseMap[item]) == intVar.end()) @@ -212,7 +220,7 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin } if (foundCount) spdlog::info("Now have {} intVar descriptors after searching {} BehavivorVar strings", intVar.size(), - acOldBehavior.syncIntegerVar.size()); + acReplacer.syncIntegerVar.size()); // Reshape the (sorted, unique) sets to vectors TiltedPhoques::Vector boolVector(boolVar.begin(), boolVar.end()); @@ -229,6 +237,10 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin panimGraphDescriptor->IntegerLookupTable = intVector; // Add the new graph to the known behavior graphs + // TODO: doesn't handle case of the acNewHash already existing. + // That has to be addressed before we can support just adding + // more pre-existing vars to sync. For now, only get here + // when mods have changed the hash. new AnimationGraphDescriptorManager::Builder(AnimationGraphDescriptorManager::Get(), acNewHash, *panimGraphDescriptor); return AnimationGraphDescriptorManager::Get().GetDescriptor(acNewHash); } @@ -296,26 +308,65 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa reversemap.insert({static_cast(item.second), item.first}); } - // See if these animation variables include a signature variable for one of the replacers. - auto iter = behaviorPool.begin(); - for (; iter < behaviorPool.end(); iter++) - if (reversemap.find(iter->signatureVar) != reversemap.end()) - break; - if (iter >= behaviorPool.end()) + // See if these animation variables include a signature for one of the replacers. + // Since some of the original behaviors don't have a single variable name that is completely + // unique, we allow a syntax of "!?signaturevar\(,!?signaturevar\)*". That is, an initial + // (possibly negated) signaturevar, followed by zero or more comma separated additional + // signaturevars (possibly negated). + // + // That's enough info to create a unique signature in the base game descriptors. At least, + // it was at the time of writing. + // + // O(N) loop, but this typically only gets executed a few times (once for each modded + // creature TYPE, not each modded creature). + // + std::vector matchedReplacers; + + for (size_t i = 0; i < behaviorPool.size(); i++) { - spdlog::warn("No original behavior found for behavior hash {:x} (found on formID {:x}), adding to fail list", hash, hexFormID); - failList(hash); - return nullptr; + auto tokens = tokenizeBehaviorSig(behaviorPool[i].signatureVar); + auto found = tokens.size() > 0; + + for (auto titer = tokens.begin(); found && titer < tokens.end(); titer++) + { + if (*titer == "!") + found = reversemap.find(*++titer) == reversemap.end(); + else + found = reversemap.find(*titer) != reversemap.end(); + } + if (found) + matchedReplacers.push_back(i); } - spdlog::info("Found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", hash, hexFormID, iter->creatureName, iter->signatureVar); + switch (matchedReplacers.size()) + { + case 0: + spdlog::warn("No original behavior found for behavior hash {:x} (found on formID {:x}), adding to fail list", hash, hexFormID); + failList(hash); + return nullptr; + + case 1: + break; + + default: + spdlog::critical("BehaviorVar::Patch: multiple behavior replacers have the same signature, this must be corrected:"); + for (auto& item : matchedReplacers) + spdlog::critical(" {}", behaviorPool[item].creatureName); + failList(hash); + return nullptr; + + } + + auto& foundRep = behaviorPool[matchedReplacers[0]]; + spdlog::info("Found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", hash, + hexFormID, foundRep.creatureName, foundRep.signatureVar); + // Save the new hash for the actor, and save it as the original actor hash. // The latter is to assist with humanoid actors popping back from a beast form. pExtendedActor->GraphDescriptorHash = hash; pExtendedActor->OrigGraphDescriptorHash = hash; - return constructModdedDescriptor(hash, *biter, reversemap); - + return constructModdedDescriptor(hash, foundRep, reversemap); } // Check if the behavior hash is on the failed liist @@ -503,6 +554,36 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aD return result; } +// Find any behaviors which match the signature. +// There should be exactly one. +// +std::vector BehaviorVar::signatureMatches(const uint64_t acHash, const std::string acSignature) const +{ + auto& bvMap = BehaviorVarsMap::getInstance(); + std::vector hashes; + + bvMap.hashes(hashes); + auto tokens = tokenizeBehaviorSig(acSignature); + for (size_t i = 0; i < hashes.size(); i++) + { + if (hashes[i] == acHash) + continue; + + auto found = true; + for (auto titer = tokens.begin(); found && titer < tokens.end(); titer++) + { + if (*titer == "!") + found = bvMap.find(hashes[i], *++titer) == UINT32_MAX; + else + found = bvMap.find(hashes[i], *titer) != UINT32_MAX; + } + if (!found) + hashes.erase(hashes.begin() + i--); + } + + return hashes; +} + void BehaviorVar::Init() { // Initialize original (base STR) behaviors so we can search them. @@ -525,6 +606,40 @@ void BehaviorVar::Init() behaviorPool.push_back(*sig); } } + + // Ambiguousness check. + for (auto& signature : behaviorPool) + { + static size_t firsttime = 0; + + auto matches = signatureMatches(signature.origHash, signature.signatureVar); + switch (matches.size()) + { + case 0: + spdlog::critical("BehaviorVar::Init: failure to find self in behaviorPool, {}", signature.creatureName); + case 1: + break; + + default: + if (firsttime++ == 0) + spdlog::warn("BehaviorVar::Init: some creatures have ambiguous signatures. This is expected for now, " + "but a modder must create a unique signature in their mod."); + + spdlog::warn("BehaviorVar::Init: {} signature {} matches:", signature.creatureName, signature.signatureVar); + for (auto hash : matches) + { + auto iter = std::find(behaviorPool.begin(), behaviorPool.end(), hash); + if (iter < behaviorPool.end()) + spdlog::warn(" {}", std::find(behaviorPool.begin(), behaviorPool.end(), hash)->creatureName); + else + spdlog::warn( + " {}: unable to find creature name for this hash, likely typo in SkyrimTogetherReborn tree", + hash); + } + break; + } + } + } void BehaviorVar::Debug() diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index cde65b8e9..27a813093 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -47,6 +47,7 @@ struct BehaviorVar std::vector loadDirs(const std::filesystem::path& acPATH); Replacer* loadReplacerFromDir(std::filesystem::path aDir); + std::vector signatureMatches(const uint64_t acHash, const std::string acSignature) const; std::vector behaviorPool; // Pool for loaded behaviours std::map failedBehaviors; diff --git a/Code/client/ModCompat/BehaviorVarsMap.cpp b/Code/client/ModCompat/BehaviorVarsMap.cpp index a05b5f452..baf01717b 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.cpp +++ b/Code/client/ModCompat/BehaviorVarsMap.cpp @@ -13,7 +13,7 @@ uint32_t BehaviorVarsMap::find(const uint64_t key, const std::string name) return map2->second; } - return -1; + return UINT32_MAX; } std::string BehaviorVarsMap::find(const uint64_t key, const uint32_t value) diff --git a/Code/client/ModCompat/BehaviorVarsMap.h b/Code/client/ModCompat/BehaviorVarsMap.h index f95aaa686..837dc373f 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.h +++ b/Code/client/ModCompat/BehaviorVarsMap.h @@ -13,7 +13,7 @@ struct BehaviorVars class BehaviorVarsMap { private: - std::map< uint64_t, BehaviorVars> m_map; + std::map m_map; // Singleton BehaviorVarsMap(){}; @@ -24,6 +24,12 @@ class BehaviorVarsMap uint32_t find(const uint64_t key, const std::string name); std::string find(const uint64_t key, const uint32_t value); + void hashes(std::vector& aHashes) const + { + aHashes.clear(); + for (auto& item : m_map) + aHashes.push_back(item.first); + }; void Register(const BehaviorVars map); diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__sig.txt index fc129f850..632223acf 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Bear/Vanilla__sig.txt @@ -1 +1 @@ -iState_BearDefault = 60 \ No newline at end of file +iState_BearDefault,iState_BearSwimDefault,km_hitSomething_3 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__sig.txt index d909ca498..ae1bfe587 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Cow/Vanilla__sig.txt @@ -1 +1 @@ -iState_CowDefault = 46 \ No newline at end of file +iState_CowDefault,!iState_DogRun diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__sig.txt index 78ab1a433..1f34227ed 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Deer/Vanilla__sig.txt @@ -1 +1 @@ -iState_DeerDefault = 46 \ No newline at end of file +iState_DeerDefault diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__hash.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__hash.txt index d8409d1be..6cfae0584 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__hash.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__hash.txt @@ -1 +1 @@ -12283352931604624777 \ No newline at end of file +16093192286272613165 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__sig.txt index fb39650af..f91397415 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dog/Vanilla__sig.txt @@ -1 +1 @@ -iState_DogRun \ No newline at end of file +iState_DogRun diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__sig.txt index 7d82bc451..e0fe584d7 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/DwarvenSpider/Vanilla__sig.txt @@ -1 +1 @@ -iState_DefaultSpider_MT = 41 \ No newline at end of file +iState_DefaultSpider_MT,FootIKEnable diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__sig.txt index be6d1948f..347683713 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/FrostbiteSpider/Vanilla__sig.txt @@ -1 +1 @@ -iState_DefaultSpider_MT = 25 \ No newline at end of file +iState_DefaultSpider_MT,!FootIKEnable diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__sig.txt index 86cddfba1..9e1514618 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Goat/Vanilla__sig.txt @@ -1 +1 @@ -iState_GoatDefault = 46 \ No newline at end of file +iState_GoatDefault diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__sig.txt index 940120b26..a7f697e11 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horker/Vanilla__sig.txt @@ -1 +1 @@ -iState_HorkerDefault = 46 \ No newline at end of file +iState_HorkerDefault diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__sig.txt index 986235c8b..0089a33a8 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Horse/Vanilla__sig.txt @@ -1 +1 @@ -iState_HorseDefault = 47 \ No newline at end of file +iState_HorseDefault,!FemaleOffset diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__sig.txt index d2dabb170..7fe4b214c 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Mammoth/Vanilla__sig.txt @@ -1 +1 @@ -iState_MammothDefault = 46 \ No newline at end of file +iState_MammothDefault,km_hitSomething_0,!km_hitSomething_3 diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__sig.txt index 4bae72f16..0a32b8c69 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/SabreCat/Vanilla__sig.txt @@ -1 +1 @@ -iState_SabreCatDefault = 46 \ No newline at end of file +iState_SabreCatDefault diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__sig.txt index e8e0eb0c7..86b35ebdd 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Skeever/Vanilla__sig.txt @@ -1 +1 @@ -iState_SkeeverDefault = 46 \ No newline at end of file +iState_SkeeverDefault diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__sig.txt index 04acdd8f9..8a88bb8ac 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Wolf/Vanilla__sig.txt @@ -1 +1 @@ -iState_WolfDefault = 46 \ No newline at end of file +iState_WolfDefault diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__sig.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__sig.txt index 7dcbac2f5..ba035fef3 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__sig.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__sig.txt @@ -1,2 +1,2 @@ -bHumanoidFootIKEnable +bHumanoidFootIKEnable,FemaleOffset From ed1f93e1c1792659260947075891cffb44bd13f6 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 13 Mar 2024 17:08:34 -0400 Subject: [PATCH 38/86] Updated README.md --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 82d8d1312..23d8f7cb3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,15 @@ -# Tilted Online Nemesis +# Skyrim Together Reborn for Modded Animations -The first couple of commits on the fork are to retain the work of Edho08 and Spvvd and give appropriate credit to them for their initial efforts to support animation mods with Skyrim Together Reborn. -Subsequent commits are the efforts of rfortier (Ujave on Discord) and MostExcellent / MagicWizardMan. +No permission to post any variation of this fork on Nexus. For now. It's coming, there are just more things to fix first so we don't get flooded with support requests. + +# Credits +This fork is inspired by Edho08's original effort to figure out how to patch Nemesis (and now Pandora) support into TiltedPhoques Skyrim Together Reborn. Since then, Spvvd and Ragley have put in a lot of maintainance effort. @rfortier and @MostExcellent have been working on this verison. + +# Status + +This version is a substantial rewrite, fixing a lot of bugs, adding flexibility that enables the STR development team and modders to work independently without breaking each other (as much). It has been ported to v1.6.3-preview of Skyrim Together Reborn. + +Includes TDM, TUDM and dragon behavior patches. Sometimes animations still don't sync, restarting game+server or rerunning Nemesis and syncing the output with your friends can fix it in most cases. @@ -21,6 +29,7 @@ the rest that the STR dev team selects will be picked up automatically for you. # TODO * Currently, BehaviorVar.cpp works, but it's blobby; when I get some time I'll simplify it. * Build up a fomod for a proper mod installer again, put a proper precompiled release up, and document the simplified behaviorvar support. +* Well, that last one is actually staring to exist. # Tilted Online From 25ff963295e138a9a7bf473f712d47656802857c Mon Sep 17 00:00:00 2001 From: MostExcellent Date: Thu, 7 Mar 2024 00:53:46 -0800 Subject: [PATCH 39/86] Tolerate misspellings of BehaviorVar string names Incorporating MostExcellent's PR. We've observed several instances of the stock game having typos in variable names, like improper capitalization and the like. Tolerate case-sensitive misspellings. if a vanilla behavior variable isn't found, capitalize the first letter, the most common misspelling. Then try all lower case, then case insensitive. Things would be a lot easier if people paid attention to case-sensitive variable names. --- Code/client/ModCompat/BehaviorVar.cpp | 136 +++++++++++++++++++------- 1 file changed, 100 insertions(+), 36 deletions(-) diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 90022c1ca..6b1dbad37 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -10,9 +10,11 @@ // One of the greatest features ensuring the longevity of Bethesda games is their support // for community modification, and many of the most popular mods also change the behavior // of creatures. STR and FTR don't support mods as a matter of policy. And supporting -// behavior mods is particularly difficult. +// behavior mods is particularly difficult. This mod provides the option to use modified +// behaviors in Skyrim|Fallout Together Reborn, but has yet to be endorsed by the TiltedPhoques +// team. Use at own risk. // -// The game determines a set of behavior variables that must be synced and locks thatdown. +// The game determines a set of behavior variables that must be synced and locks that down. // Changing the list is difficult, because behavior mods won't just add to the list, they // will change the order of the list also changing the shorthand numeric codes for behavior // vars to sync. @@ -61,6 +63,76 @@ const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apMana return BehaviorVar::Get()->Patch(apManager, apActor); } +// Utility function to convert a string to lowercase +// This is useful as at least one vanilla variable, "Speed", is sometimes lowercase +// We'd like to be able to handle other vars for which this may be the case. +namespace +{ +std::string toLowerCase(const std::string& aStr) +{ + std::string lowerCaseStr; + lowerCaseStr.reserve(aStr.size()); + std::transform(aStr.begin(), aStr.end(), lowerCaseStr.begin(), + [](unsigned char c) { return std::tolower(c); }); + return lowerCaseStr; +} + +// Converts the keys of a map (which are const std::string) to lowercase. +// This is our "Plan C" if a vanilla var isn't found to make sure it isn't just a case-sensitivity issue. +void lowerCaseKeys(const std::map& map, + std::map& lowerCaseMap) +{ + for (const auto& item : map) + lowerCaseMap.insert({toLowerCase(item.first), item.second}); +} + +// Process a set of variables, adding them to the aVariableSet +void processVariableSet(const std::map& acReverseMap, + std::set& aVariableSet, const std::vector& acVariables, + spdlog::level::level_enum aLogLevel) +{ + // Not filled until needed, which should be never. + std::map lowerCaseMap; + + for (const auto& item : acVariables) + { + std::string foundForm = item; + auto found = acReverseMap.find(item); + if (found == acReverseMap.end()) + { + // Check if first letter incorrectly lowercase. + foundForm[0] = std::toupper(item[0]); + found = acReverseMap.find(foundForm); + } + + if (found == acReverseMap.end()) + { + // Check lower case. + foundForm = toLowerCase(item); + found = acReverseMap.find(foundForm); + } + + if (found == acReverseMap.end()) + { + // Check case-independent + if (lowerCaseMap.empty()) + lowerCaseKeys(acReverseMap, lowerCaseMap); + found = lowerCaseMap.find(foundForm); + } + + if (found == acReverseMap.end()) + spdlog::warn("BehaviorVar::processVariableSet: unable to find variable {} in any of the common misspellings", item); + else + { + aVariableSet.insert(found->second); + if (item != found->first) + spdlog::warn("BehaviorVar::processVariableSet: misspelled variable {} found as {}", item, foundForm); + } + } +} + +} // End anonymous namespace + // // Translate modded behavior numeric values. // When a behavior is modified (at least by Nemesis) it can rearrange the order of BehaviorVars. @@ -69,8 +141,8 @@ const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apMana // We do this with a hack to translate old numeric value back to a string, then we // can forward-translate the string to its new numeric value. // -// The machine-generated table hack to do this can be removed with STR-devs -// permission to also embed the string invformation in the Code\encoding\structs files. +// The machine-generated table hack to do this can be removed with STR-devs' +// permission to also embed the string information in the Code\encoding\structs files. // void BehaviorVar::seedAnimationVariables( uint64_t hash, @@ -82,42 +154,35 @@ void BehaviorVar::seedAnimationVariables( { auto& origVars = BehaviorVarsMap::getInstance(); - // Defensive code to detect if for some reason we have a number - // without a string, or a string without a number. + // Prepare lists of variables to process + std::vector boolVarNames; + std::vector floatVarNames; + std::vector intVarNames; + + // Populate lists from the original descriptor + std::string strValue; for (auto& item : pDescriptor->BooleanLookUpTable) - { - const auto strValue = origVars.find(hash, item); - if (strValue.empty()) + if ((strValue = origVars.find(hash, item)).empty()) spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original BooleanVar {}", item); - else if (reversemap.find(strValue) == reversemap.end()) - spdlog::error("BehaviorVar::seedAnimationVariables unable to find BooleanVar {}", strValue); else - boolVars.insert(reversemap[strValue]); - } - for (auto& item : pDescriptor->FloatLookupTable) - { - auto strValue = origVars.find(hash, item); - if (strValue.empty()) - spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original FloatVar {}", item); - else if (reversemap.find(strValue) == reversemap.end()) - if (strValue == "Speed" && reversemap.find("speed") != reversemap.end()) // Fix typo in base game. - strValue = "speed", spdlog::error("BehaviorVar::seedAnimationVariables successfully compensated for incorrect capitalization of Floatvar 'speed'"); + boolVarNames.push_back(strValue); - if (reversemap.find(strValue) == reversemap.end()) - spdlog::error("BehaviorVar::seedAnimationVariables unable to find FloatVar {}", strValue); + for (auto& item : pDescriptor->FloatLookupTable) + if ((strValue = origVars.find(hash, item)).empty()) + spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original FloatVar {}", item); else - floatVars.insert(reversemap[strValue]); - } - for (auto& item : pDescriptor->IntegerLookupTable) - { - const auto strValue = origVars.find(hash, item); - if (strValue.empty()) - spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original IntegerVar {}", item); - else if (reversemap.find(strValue) == reversemap.end()) - spdlog::error("BehaviorVar::seedAnimationVariables unable to find IntegerVar {}", strValue); + floatVarNames.push_back(strValue); + + for (auto& item : pDescriptor->IntegerLookupTable) + if ((strValue = origVars.find(hash, item)).empty()) + spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original IntVar {}", item); else - intVars.insert(reversemap[strValue]); - } + intVarNames.push_back(strValue); + + // Process each set of variables + processVariableSet(reversemap, boolVars, boolVarNames, spdlog::level::level_enum::err); + processVariableSet(reversemap, floatVars, floatVarNames, spdlog::level::level_enum::err); + processVariableSet(reversemap, intVars, intVarNames, spdlog::level::level_enum::err); } // Syntax for a signature is [!]sig1[,[!]sig2]... Must be at least one. Each signature var possibly negated @@ -127,7 +192,6 @@ void BehaviorVar::seedAnimationVariables( // const std::vector BehaviorVar::tokenizeBehaviorSig(const std::string signature) const { - const static std::string notVal{"!"}; std::vector retVal; size_t commaPos; @@ -298,7 +362,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa spdlog::info("BehaviorVar::Patch: actor with formID {:x} with hash of {} has modded (or not synced) behavior", hexFormID, hash); - // Get all animation variables for this actor, then create a reversemap to go from strings to animation enum. + // Get all animation variables for this actor, then create a acReverseMap to go from strings to animation enum. auto pDumpVar = apManager->DumpAnimationVariables(false); std::map reversemap; spdlog::info("Known behavior variables for formID {:x}:", hexFormID); From 087e26196f6f600bb13a63e80985393199a8ba2f Mon Sep 17 00:00:00 2001 From: rfortier Date: Thu, 14 Mar 2024 16:55:19 -0400 Subject: [PATCH 40/86] README.md update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 23d8f7cb3..64aab8567 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ This fork is inspired by Edho08's original effort to figure out how to patch Nem This version is a substantial rewrite, fixing a lot of bugs, adding flexibility that enables the STR development team and modders to work independently without breaking each other (as much). It has been ported to v1.6.3-preview of Skyrim Together Reborn. -Includes TDM, TUDM and dragon behavior patches. +Includes TDM, TUDM, Modern Combat Overhaul, Elden Counter and dragon behavior patches. Oh, and humans don't skate around. Sometimes animations still don't sync, restarting game+server or rerunning Nemesis and syncing the output with your friends can fix it in most cases. -Works only with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR. It might work with the latest Skyrim and the correct address library, but it has barely been tested. +Tested only with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR. It might work with the latest Skyrim and the correct address library, but it has barely been tested. And the STR team has not released 1.6.x yet. This version by RFortier and MostExcellent adds these goals: From 8ed94ccc0e1e09297247eb8bf5a001faec4fcd31 Mon Sep 17 00:00:00 2001 From: rfortier Date: Sun, 17 Mar 2024 18:30:36 -0400 Subject: [PATCH 41/86] Better logging --- Code/client/ModCompat/BehaviorVar.cpp | 39 +++++++++++++++------------ 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 6b1dbad37..4abc321ed 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -121,12 +121,12 @@ void processVariableSet(const std::map& acRev } if (found == acReverseMap.end()) - spdlog::warn("BehaviorVar::processVariableSet: unable to find variable {} in any of the common misspellings", item); + spdlog::warn(__FUNCTION__ ": unable to find variable {} in any of the common misspellings", item); else { aVariableSet.insert(found->second); if (item != found->first) - spdlog::warn("BehaviorVar::processVariableSet: misspelled variable {} found as {}", item, foundForm); + spdlog::warn(__FUNCTION__ ": misspelled variable {} found as {}", item, found->first); } } } @@ -163,19 +163,19 @@ void BehaviorVar::seedAnimationVariables( std::string strValue; for (auto& item : pDescriptor->BooleanLookUpTable) if ((strValue = origVars.find(hash, item)).empty()) - spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original BooleanVar {}", item); + spdlog::error(__FUNCTION__ ": unable to find string for original BooleanVar {}", item); else boolVarNames.push_back(strValue); for (auto& item : pDescriptor->FloatLookupTable) if ((strValue = origVars.find(hash, item)).empty()) - spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original FloatVar {}", item); + spdlog::error(__FUNCTION__ ": unable to find string for original FloatVar {}", item); else floatVarNames.push_back(strValue); for (auto& item : pDescriptor->IntegerLookupTable) if ((strValue = origVars.find(hash, item)).empty()) - spdlog::error("BehaviorVar::seedAnimationVariables unable to find string for original IntVar {}", item); + spdlog::error(__FUNCTION__ ": unable to find string for original IntVar {}", item); else intVarNames.push_back(strValue); @@ -232,7 +232,7 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin if (acReplacer.origHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(acReplacer.origHash))) { seedAnimationVariables(acReplacer.origHash, pTmpGraph, acReverseMap, boolVar, floatVar, intVar); - spdlog::info("Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", + spdlog::info(__FUNCTION__ ": Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", acReplacer.origHash, boolVar.size(), floatVar.size(), intVar.size()); } @@ -283,7 +283,8 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin } } if (foundCount) - spdlog::info("Now have {} intVar descriptors after searching {} BehavivorVar strings", intVar.size(), + spdlog::info(__FUNCTION__ ": now have {} intVar descriptors after searching {} BehavivorVar strings", + intVar.size(), acReplacer.syncIntegerVar.size()); // Reshape the (sorted, unique) sets to vectors @@ -358,9 +359,10 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa // With that case filtered out, keep a counter to see if we need to defend against other // cases (like a modded behavior where we CAN't find the signature var). if (invocations++ == 100) - spdlog::warn("BehaviorVar::Patch: warning, more than 100 invocations, investigate why"); + spdlog::warn(__FUNCTION__ ": warning, more than 100 invocations, investigate why"); - spdlog::info("BehaviorVar::Patch: actor with formID {:x} with hash of {} has modded (or not synced) behavior", hexFormID, hash); + spdlog::info(__FUNCTION__ ": actor with formID {:x} with hash of {} has modded (or not synced) behavior", hexFormID, + hash); // Get all animation variables for this actor, then create a acReverseMap to go from strings to animation enum. auto pDumpVar = apManager->DumpAnimationVariables(false); @@ -405,7 +407,9 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa switch (matchedReplacers.size()) { case 0: - spdlog::warn("No original behavior found for behavior hash {:x} (found on formID {:x}), adding to fail list", hash, hexFormID); + spdlog::warn(__FUNCTION__ ": no original behavior found for behavior hash {:x} (found on formID {:x}), adding to " + "fail list", + hash, hexFormID); failList(hash); return nullptr; @@ -413,7 +417,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa break; default: - spdlog::critical("BehaviorVar::Patch: multiple behavior replacers have the same signature, this must be corrected:"); + spdlog::critical(__FUNCTION__ ": multiple behavior replacers have the same signature, this must be corrected:"); for (auto& item : matchedReplacers) spdlog::critical(" {}", behaviorPool[item].creatureName); failList(hash); @@ -422,7 +426,8 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa } auto& foundRep = behaviorPool[matchedReplacers[0]]; - spdlog::info("Found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", hash, + spdlog::info(__FUNCTION__ ": found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", + hash, hexFormID, foundRep.creatureName, foundRep.signatureVar); // Save the new hash for the actor, and save it as the original actor hash. @@ -537,7 +542,7 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aD erase_if(sigVar, isspace); // removes any inadvertant whitespace if (sigVar.size() == 0) return nullptr; - spdlog::info("BehaviorVar::loadReplacerFromDir found {} with signature variable {}", creatureName, sigVar); + spdlog::info(__FUNCTION__ ": found {} with signature variable {}", creatureName, sigVar); // Check to see if there is a hash file. // This is recommended, and shouild contain the ORIGINAL hash, @@ -680,16 +685,16 @@ void BehaviorVar::Init() switch (matches.size()) { case 0: - spdlog::critical("BehaviorVar::Init: failure to find self in behaviorPool, {}", signature.creatureName); + spdlog::critical(__FUNCTION__ ": failure to find self in behaviorPool, {}", signature.creatureName); case 1: break; default: if (firsttime++ == 0) - spdlog::warn("BehaviorVar::Init: some creatures have ambiguous signatures. This is expected for now, " - "but a modder must create a unique signature in their mod."); + spdlog::warn(__FUNCTION__ ": some creatures have ambiguous signatures. This is expected for now,\n" + " but a modder must create a unique signature in their mod."); - spdlog::warn("BehaviorVar::Init: {} signature {} matches:", signature.creatureName, signature.signatureVar); + spdlog::warn(__FUNCTION__ ": {} signature {} matches:", signature.creatureName, signature.signatureVar); for (auto hash : matches) { auto iter = std::find(behaviorPool.begin(), behaviorPool.end(), hash); From f30bb9f7dd6fddaee028b9f49ba80a45adf088ce Mon Sep 17 00:00:00 2001 From: rfortier Date: Tue, 16 Apr 2024 12:15:18 -0400 Subject: [PATCH 42/86] Behavior strings generator improvements to support Fallout4 --- Code/client/ModCompat/BehaviorOrigGenerate.ps1 | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Code/client/ModCompat/BehaviorOrigGenerate.ps1 b/Code/client/ModCompat/BehaviorOrigGenerate.ps1 index 2c0b0f533..de0205f9e 100644 --- a/Code/client/ModCompat/BehaviorOrigGenerate.ps1 +++ b/Code/client/ModCompat/BehaviorOrigGenerate.ps1 @@ -1,8 +1,17 @@ param ( - [string]$path = "..\..\encoding\Structs\Skyrim" + [string]$name = "Skyrim", ) + +Set-PSDebug -Trace 1 + +$output = "BehaviorOrig$name.obs" +$path = "..\..\encoding\Structs\$name" $files = Get-ChildItem $path -Filter *_*.cpp -Set-PSDebug -Trace 0 + +# Output everything to the target file. +$( + + "// DO NOT EDIT, MACHINE-GENERATED CODE // // This is an admittedly dirty approach, but done with the best of intentions. @@ -92,3 +101,7 @@ foreach ($f in $files) $creatures = $creatures + "};`r`n" $creatures + + +) *>&1 > $output +# Close redirection From 2e0cc0f6e637efa391e80965ee2295739e48eff6 Mon Sep 17 00:00:00 2001 From: rfortier Date: Thu, 18 Apr 2024 13:05:20 -0400 Subject: [PATCH 43/86] Fix #ifdefs to clean up the MODDED_BEHAVIOR_COMPATIBILITY conditional compile, and better mark the dead code for deletion. --- Code/client/ModCompat/BehaviorOrig.cpp | 3 ++ Code/client/ModCompat/BehaviorVarsMap.cpp | 2 ++ .../AnimationGraphDescriptorManager.cpp | 35 ++++++++++--------- .../Structs/AnimationGraphDescriptorManager.h | 5 +-- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/Code/client/ModCompat/BehaviorOrig.cpp b/Code/client/ModCompat/BehaviorOrig.cpp index 2e079b695..b60f27b06 100644 --- a/Code/client/ModCompat/BehaviorOrig.cpp +++ b/Code/client/ModCompat/BehaviorOrig.cpp @@ -1,3 +1,4 @@ +#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include "BehaviorVarsMap.h" #define MAGIC_ENUM_RANGE_MAX 400 @@ -37,3 +38,5 @@ template void GenerateFromEnum(uint64_t key) #endif } // using namespace BehaviorOrig + +#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/ModCompat/BehaviorVarsMap.cpp b/Code/client/ModCompat/BehaviorVarsMap.cpp index baf01717b..a5a3ab676 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.cpp +++ b/Code/client/ModCompat/BehaviorVarsMap.cpp @@ -1,3 +1,4 @@ +#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include "BehaviorVarsMap.h" @@ -47,3 +48,4 @@ BehaviorVarsMap& BehaviorVarsMap::getInstance() return instance; } +#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp b/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp index 7ce38522f..d6b2a564f 100644 --- a/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp +++ b/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp @@ -16,7 +16,22 @@ const AnimationGraphDescriptor* AnimationGraphDescriptorManager::GetDescriptor(u return nullptr; } -const TiltedPhoques::Map AnimationGraphDescriptorManager::GetDescriptors() const noexcept +AnimationGraphDescriptorManager::Builder::Builder(AnimationGraphDescriptorManager& aManager, uint64_t aKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept +{ + aManager.Register(aKey, std::move(aAnimationGraphDescriptor)); +} + +void AnimationGraphDescriptorManager::Register(uint64_t aKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept +{ + if (m_descriptors.count(aKey)) + return; + + m_descriptors[aKey] = std::move(aAnimationGraphDescriptor); +} + +#ifdef MODDED_BEHAVIOR_COMPATIBILITY +const TiltedPhoques::Map& AnimationGraphDescriptorManager::GetDescriptors() + const noexcept { return m_descriptors; } @@ -41,25 +56,11 @@ void AnimationGraphDescriptorManager::Update(uint64_t aKey, uint64_t newKey, Ani m_descriptors.erase(it); } } -#endif -AnimationGraphDescriptorManager::Builder::Builder(AnimationGraphDescriptorManager& aManager, uint64_t aKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept -{ - aManager.Register(aKey, std::move(aAnimationGraphDescriptor)); -} - -void AnimationGraphDescriptorManager::Register(uint64_t aKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept -{ - if (m_descriptors.count(aKey)) - return; - - m_descriptors[aKey] = std::move(aAnimationGraphDescriptor); -} - -#ifdef MODDED_BEHAVIOR_KEEP_UNUSED void AnimationGraphDescriptorManager::ReRegister(uint64_t aKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept { m_descriptors[aKey] = std::move(aAnimationGraphDescriptor); } -#endif +#endif MODDED_BEHAVIOR_KEEP_UNUSED +#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/encoding/Structs/AnimationGraphDescriptorManager.h b/Code/encoding/Structs/AnimationGraphDescriptorManager.h index 3478a2658..8285308b1 100644 --- a/Code/encoding/Structs/AnimationGraphDescriptorManager.h +++ b/Code/encoding/Structs/AnimationGraphDescriptorManager.h @@ -9,10 +9,11 @@ struct AnimationGraphDescriptorManager static AnimationGraphDescriptorManager& Get() noexcept; const AnimationGraphDescriptor* GetDescriptor(uint64_t aKey) const noexcept; - - const TiltedPhoques::Map GetDescriptors() const noexcept; +#ifdef MODDED_BEHAVIOR_COMPATIBILITY + const TiltedPhoques::Map& GetDescriptors() const noexcept; void UpdateKey(uint64_t aKey, uint64_t newKey) noexcept; void Update(uint64_t aKey, uint64_t newKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept; +#endif MODDED_BEHAVIOR_COMPATIBILITY struct Builder { From 7225a3521b0495ee97ea1b30786f76f1dbee061e Mon Sep 17 00:00:00 2001 From: rfortier Date: Mon, 22 Apr 2024 16:37:53 -0400 Subject: [PATCH 44/86] Revert all changes to the standard README.md. Add a new README-ANIMATIONS-MODS.md with updated information. --- README-ANIMATION-MODS.md | 55 ++++++++++++++++++++++++++++++++++++++++ README.md | 34 ------------------------- 2 files changed, 55 insertions(+), 34 deletions(-) create mode 100644 README-ANIMATION-MODS.md diff --git a/README-ANIMATION-MODS.md b/README-ANIMATION-MODS.md new file mode 100644 index 000000000..5ff0208de --- /dev/null +++ b/README-ANIMATION-MODS.md @@ -0,0 +1,55 @@ +# Skyrim Together Reborn for Modded Animations + +_The Tilted Phoques Development Team only supports strictly required mods, no others._ See their disclaimers on their wiki, [here](https://wiki.tiltedphoques.com/tilted-online) +and [here](https://wiki.tiltedphoques.com/tilted-online/guides/getting-started#readme-before-installing). If you can't reproduce an issue with nothing but the required mods installed, +don't bother the development team. + +That said, the developers have graciously included contributed, limited support for behaviors/animations mods such as those generated by Nemesis, or the newer Pandora. If you use this capability, +report issues to the author(s) of the support. Preferably file an issue with the authors on github, [here](https://github.com/rfortier/TiltedEvolution-rwf/issues), or you may find help from Ujave or MagicWizardMan on the +Skyrim Together Reborn Discord. + +## License +[![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html) + +However, no permission to post any variation of this fork on Nexus. For now. It's coming, there are just more things to fix first so we don't get flooded with support requests. + +# Credits +This fork is inspired by Edho08's original effort to figure out how to patch Nemesis (and now Pandora) support into TiltedPhoques Skyrim Together Reborn. +Since then, Spvvd and Ragley have put maintenance effort into versions up to 1.5.0 of STR. This version targets the upcoming v1.6.x release of STR and adds a ton of features. +@rfortier and @MostExcellent have contributed to it. + +# Status + +This version is a substantial rewrite, fixing a lot of bugs, adding flexibility that enables the STR development team and modders to work more independently without breaking each other (as much). +It has been ported to v1.6.x-preview of Skyrim Together Reborn. + +Importantly, _the goal is for it to be wire-protocol comnpatible with vanilla public STR servers._ This goal still needs to be proven. And as always, only clients with the same version and the same modlist +can connect to the same server. + +Includes TDM, TUDM, Modern Combat Overhaul, Elden Counter and dragon behavior patches. Oh, and humans don't skate around. + +Sometimes animations still don't sync, restarting game+server or rerunning Nemesis and syncing the output with your friends can fix it in most cases. + +Tested extensively with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR. It might work with the latest Skyrim and the correct address library, but it has barely been tested. +And the STR team has not released 1.6.x yet. + +This version by RFortier and MostExcellent adds these goals: +* Wire protocol compatibility. +* Beast mode (werewolf, vampire lord) support. +* Pure feature branch to make it easily rebaseable. +* Minimal intrusion in the base code. +* Feature is conditionally compiled. Enabled by a single commit in the history which will show the one(-ish) line to comment out to turn it off. Or, don't include that commit. +* In theory, if a client with modded animations support is compile to the same version as the vanilla STR, the vanilla server will support that client. +* Tries to remove as much of the complexity for modders as possible. To mod a behavior you don't need anything about the behavior variables the Dev team has chosen, nor do you need +to know the old or new hashes that will be generated by your new behaviors; the game calculates them. +That's pretty important because _every_ mod that changes behavior changes the hash, and the order of mods may also change the hash (unless you use Pandora which fixes that evil). +That means a mod author _can't_ know the new hash for the mods a user selects, +it is only known for a specific modlist in a specific order. +* It's to your advantage to know the _original STR game behavior hash_ you are moddifying, though; if you do, you only need to list the behavior variables your mod needs, +the rest that the STR dev team selects will be picked up automatically for you. This helps give your mod STR version-independence. The SkyrimTogetherRebornBehaviors tree is pre-populated with this +information for the creatures supported by STR. + +# TODO +* Hoping to win support of the Dev team to include this in their build, which will make it easier to stay in sync with the servers. +* In the interim, compiled versions are available on [github](https://github.com/rfortier/TiltedEvolution-rwf/releases), but they will only work with the server that is included. +* Need some help figuring out an xmake change to automatically compile behavior string names when anything changes. For now, manually generated and output files checked in. diff --git a/README.md b/README.md index 64aab8567..f9a84df33 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,3 @@ -# Skyrim Together Reborn for Modded Animations - -No permission to post any variation of this fork on Nexus. For now. It's coming, there are just more things to fix first so we don't get flooded with support requests. - -# Credits -This fork is inspired by Edho08's original effort to figure out how to patch Nemesis (and now Pandora) support into TiltedPhoques Skyrim Together Reborn. Since then, Spvvd and Ragley have put in a lot of maintainance effort. @rfortier and @MostExcellent have been working on this verison. - -# Status - -This version is a substantial rewrite, fixing a lot of bugs, adding flexibility that enables the STR development team and modders to work independently without breaking each other (as much). It has been ported to v1.6.3-preview of Skyrim Together Reborn. - -Includes TDM, TUDM, Modern Combat Overhaul, Elden Counter and dragon behavior patches. Oh, and humans don't skate around. - -Sometimes animations still don't sync, restarting game+server or rerunning Nemesis and syncing the output with your friends can fix it in most cases. - -Tested only with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR. It might work with the latest Skyrim and the correct address library, but it has barely been tested. -And the STR team has not released 1.6.x yet. - -This version by RFortier and MostExcellent adds these goals: -* Pure feature branch to make it easily rebaseable. -* Minimal intrusion in the base code. -* Feature is conditionally compiled. Enabled by a single commit in the history which will show the one(-ish) line to change to turn it off. Or, don't include that commit. -* Tries to remove as much of the complexity for modders as possible. To mod a behavior you don't need to know the new hashes of your modded behaviors, the game calculates them. -That's pretty important because _every_ mod that changes behavior changes the hash, and the order of mods may also change the hash. So a mod author can't know the new hash for the mods a user selects, -it is only known for a specific modlist in a specific order. -* It's to your advantage to know the _original STR game behavior hash_ you are moddifying, though; if you do, you only need to list the behavior variables your mod needs, -the rest that the STR dev team selects will be picked up automatically for you. This helps give your mod STR version-independence. - -# TODO -* Currently, BehaviorVar.cpp works, but it's blobby; when I get some time I'll simplify it. -* Build up a fomod for a proper mod installer again, put a proper precompiled release up, and document the simplified behaviorvar support. -* Well, that last one is actually staring to exist. - - # Tilted Online ![Build status](https://github.com/tiltedphoques/TiltedEvolution/workflows/Build%20windows/badge.svg?branch=master) [![Build linux](https://github.com/tiltedphoques/TiltedEvolution/actions/workflows/linux.yml/badge.svg)](https://github.com/tiltedphoques/TiltedEvolution/actions/workflows/linux.yml) [![Discord](https://img.shields.io/discord/247835175860305931.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/skyrimtogether) From cd441cd8fc37901dabe45d439146c8e9cb6d6583 Mon Sep 17 00:00:00 2001 From: rfortier Date: Mon, 22 Apr 2024 17:51:17 -0400 Subject: [PATCH 45/86] Style guide fixes. --- Code/client/ModCompat/BehaviorOrig.cpp | 4 +- Code/client/ModCompat/BehaviorVar.cpp | 52 +++++++++++------------ Code/client/ModCompat/BehaviorVar.h | 24 +++++------ Code/client/ModCompat/BehaviorVarsMap.cpp | 16 +++---- Code/client/ModCompat/BehaviorVarsMap.h | 6 +-- 5 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Code/client/ModCompat/BehaviorOrig.cpp b/Code/client/ModCompat/BehaviorOrig.cpp index b60f27b06..56b4e650d 100644 --- a/Code/client/ModCompat/BehaviorOrig.cpp +++ b/Code/client/ModCompat/BehaviorOrig.cpp @@ -7,7 +7,7 @@ namespace BehaviorOrig { -template void GenerateFromEnum(uint64_t key) +template void GenerateFromEnum(uint64_t aKey) { using namespace magic_enum; constexpr size_t count = enum_count(); @@ -15,7 +15,7 @@ template void GenerateFromEnum(uint64_t key) constexpr auto variables_names = enum_names(); BehaviorVars sig; - sig.m_key = key; + sig.m_key = aKey; for (size_t index = 0; index < count; index++) { std::string name = static_cast(variables_names[index]); diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 4abc321ed..fffe15808 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -68,22 +68,22 @@ const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apMana // We'd like to be able to handle other vars for which this may be the case. namespace { -std::string toLowerCase(const std::string& aStr) +std::string toLowerCase(const std::string& acStr) { std::string lowerCaseStr; - lowerCaseStr.reserve(aStr.size()); - std::transform(aStr.begin(), aStr.end(), lowerCaseStr.begin(), + lowerCaseStr.reserve(acStr.size()); + std::transform(acStr.begin(), acStr.end(), lowerCaseStr.begin(), [](unsigned char c) { return std::tolower(c); }); return lowerCaseStr; } // Converts the keys of a map (which are const std::string) to lowercase. // This is our "Plan C" if a vanilla var isn't found to make sure it isn't just a case-sensitivity issue. -void lowerCaseKeys(const std::map& map, - std::map& lowerCaseMap) +void lowerCaseKeys(const std::map& acMap, + std::map& aLowerCaseMap) { - for (const auto& item : map) - lowerCaseMap.insert({toLowerCase(item.first), item.second}); + for (const auto& item : acMap) + aLowerCaseMap.insert({toLowerCase(item.first), item.second}); } // Process a set of variables, adding them to the aVariableSet @@ -145,12 +145,12 @@ void processVariableSet(const std::map& acRev // permission to also embed the string information in the Code\encoding\structs files. // void BehaviorVar::seedAnimationVariables( - uint64_t hash, - const AnimationGraphDescriptor* pDescriptor, - std::map& reversemap, - std::set& boolVars, - std::set& floatVars, - std::set& intVars) + const uint64_t acHash, + const AnimationGraphDescriptor* acpDescriptor, + const std::map& acReversemap, + std::set& aBoolVars, + std::set& aFloatVars, + std::set& aIntVars) { auto& origVars = BehaviorVarsMap::getInstance(); @@ -161,28 +161,28 @@ void BehaviorVar::seedAnimationVariables( // Populate lists from the original descriptor std::string strValue; - for (auto& item : pDescriptor->BooleanLookUpTable) - if ((strValue = origVars.find(hash, item)).empty()) + for (auto& item : acpDescriptor->BooleanLookUpTable) + if ((strValue = origVars.find(acHash, item)).empty()) spdlog::error(__FUNCTION__ ": unable to find string for original BooleanVar {}", item); else boolVarNames.push_back(strValue); - for (auto& item : pDescriptor->FloatLookupTable) - if ((strValue = origVars.find(hash, item)).empty()) + for (auto& item : acpDescriptor->FloatLookupTable) + if ((strValue = origVars.find(acHash, item)).empty()) spdlog::error(__FUNCTION__ ": unable to find string for original FloatVar {}", item); else floatVarNames.push_back(strValue); - for (auto& item : pDescriptor->IntegerLookupTable) - if ((strValue = origVars.find(hash, item)).empty()) + for (auto& item : acpDescriptor->IntegerLookupTable) + if ((strValue = origVars.find(acHash, item)).empty()) spdlog::error(__FUNCTION__ ": unable to find string for original IntVar {}", item); else intVarNames.push_back(strValue); // Process each set of variables - processVariableSet(reversemap, boolVars, boolVarNames, spdlog::level::level_enum::err); - processVariableSet(reversemap, floatVars, floatVarNames, spdlog::level::level_enum::err); - processVariableSet(reversemap, intVars, intVarNames, spdlog::level::level_enum::err); + processVariableSet(acReversemap, aBoolVars, boolVarNames, spdlog::level::level_enum::err); + processVariableSet(acReversemap, aFloatVars, floatVarNames, spdlog::level::level_enum::err); + processVariableSet(acReversemap, aIntVars, intVarNames, spdlog::level::level_enum::err); } // Syntax for a signature is [!]sig1[,[!]sig2]... Must be at least one. Each signature var possibly negated @@ -190,7 +190,7 @@ void BehaviorVar::seedAnimationVariables( // Requires that whitespace has already been deleted (which it was, when directories were loaded). // Tokenize on ',' // -const std::vector BehaviorVar::tokenizeBehaviorSig(const std::string signature) const +const std::vector BehaviorVar::tokenizeBehaviorSig(const std::string acSignature) const { const static std::string notVal{"!"}; std::vector retVal; @@ -199,14 +199,14 @@ const std::vector BehaviorVar::tokenizeBehaviorSig(const std::strin do { - if (signature[offset] == '!') + if (acSignature[offset] == '!') { offset++; retVal.push_back(notVal); } - commaPos = signature.find(',', offset); - retVal.push_back(signature.substr(offset, commaPos)); + commaPos = acSignature.find(',', offset); + retVal.push_back(acSignature.substr(offset, commaPos)); offset = commaPos + 1; } while (commaPos != std::string::npos); diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index 27a813093..4aeec398e 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -22,8 +22,8 @@ struct BehaviorVar static BehaviorVar* Get(); const AnimationGraphDescriptor* Patch(BSAnimationGraphManager* apManager, Actor* apActor); - boolean failListed(uint64_t hash); - void failList(uint64_t hash); + boolean failListed(const uint64_t acHash); + void failList(const uint64_t acHash); void Init(); void Debug(); @@ -33,20 +33,20 @@ struct BehaviorVar uint64_t invocations = 0; void seedAnimationVariables( - uint64_t hash, - const AnimationGraphDescriptor* pDescriptor, - std::map& reversemap, - std::set& boolVars, - std::set& floatVars, - std::set& intVars); - - const std::vector tokenizeBehaviorSig(const std::string signature) const; + const uint64_t acHash, + const AnimationGraphDescriptor* acpDescriptor, + const std::map& acReversemap, + std::set& aBoolVars, + std::set& aFloatVars, + std::set& aIntVars); + + const std::vector tokenizeBehaviorSig(const std::string acSignature) const; const AnimationGraphDescriptor* constructModdedDescriptor( - const uint64_t acNewHash, const Replacer& acOldBehavior, + const uint64_t acNewHash, const Replacer& acReplacer, std::map& acReverseMap); std::vector loadDirs(const std::filesystem::path& acPATH); - Replacer* loadReplacerFromDir(std::filesystem::path aDir); + Replacer* loadReplacerFromDir(const std::filesystem::path acDir); std::vector signatureMatches(const uint64_t acHash, const std::string acSignature) const; std::vector behaviorPool; // Pool for loaded behaviours diff --git a/Code/client/ModCompat/BehaviorVarsMap.cpp b/Code/client/ModCompat/BehaviorVarsMap.cpp index a5a3ab676..17cb6c0a8 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.cpp +++ b/Code/client/ModCompat/BehaviorVarsMap.cpp @@ -2,13 +2,13 @@ #include "BehaviorVarsMap.h" -uint32_t BehaviorVarsMap::find(const uint64_t key, const std::string name) +uint32_t BehaviorVarsMap::find(const uint64_t acKey, const std::string acName) { - auto map = m_map.find(key); + auto map = m_map.find(acKey); if (map != m_map.end()) { - auto map2 = map->second.m_namemap.find(name); + auto map2 = map->second.m_namemap.find(acName); if (map2 != map->second.m_namemap.end()) return map2->second; @@ -17,14 +17,14 @@ uint32_t BehaviorVarsMap::find(const uint64_t key, const std::string name) return UINT32_MAX; } -std::string BehaviorVarsMap::find(const uint64_t key, const uint32_t value) +std::string BehaviorVarsMap::find(const uint64_t acKey, const uint32_t acValue) { constexpr std::string empty; - auto map = m_map.find(key); + auto map = m_map.find(acKey); if (map != m_map.end()) { - auto map2 = map->second.m_valuemap.find(value); + auto map2 = map->second.m_valuemap.find(acValue); if (map2 != map->second.m_valuemap.end()) return map2->second; @@ -33,9 +33,9 @@ std::string BehaviorVarsMap::find(const uint64_t key, const uint32_t value) return empty; } -void BehaviorVarsMap::Register(const BehaviorVars map) +void BehaviorVarsMap::Register(const BehaviorVars aMap) { - m_map.insert_or_assign(map.m_key, map); + m_map.insert_or_assign(aMap.m_key, aMap); } diff --git a/Code/client/ModCompat/BehaviorVarsMap.h b/Code/client/ModCompat/BehaviorVarsMap.h index 837dc373f..6a291ad5d 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.h +++ b/Code/client/ModCompat/BehaviorVarsMap.h @@ -21,9 +21,9 @@ class BehaviorVarsMap void operator=(BehaviorVarsMap const&) = delete; public: - uint32_t find(const uint64_t key, const std::string name); + uint32_t find(const uint64_t acKey, const std::string acName); - std::string find(const uint64_t key, const uint32_t value); + std::string find(const uint64_t acKey, const uint32_t acValue); void hashes(std::vector& aHashes) const { aHashes.clear(); @@ -31,7 +31,7 @@ class BehaviorVarsMap aHashes.push_back(item.first); }; - void Register(const BehaviorVars map); + void Register(const BehaviorVars aMap); static BehaviorVarsMap& getInstance(); }; From e1ef621035dd18d782d56ef78942bb797eede6a4 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 24 Apr 2024 22:40:03 -0400 Subject: [PATCH 46/86] Corrected two issues: found IsDragon() test was failing when dragon behavior is modified (it always is with Nemesis installed). And fixed a case where humanoids exiting beast mode would similarly fail if Nemesis wasn't installed. --- Code/client/Games/ActorExtension.h | 3 ++- Code/client/Games/Skyrim/Actor.cpp | 11 +++++++++++ Code/client/Games/Skyrim/PlayerCharacter.cpp | 5 ++++- Code/client/ModCompat/BehaviorVar.cpp | 13 ++++++++----- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Code/client/Games/ActorExtension.h b/Code/client/Games/ActorExtension.h index 19273ec3d..f7bc8e11a 100644 --- a/Code/client/Games/ActorExtension.h +++ b/Code/client/Games/ActorExtension.h @@ -21,7 +21,8 @@ struct ActorExtension ActionEvent LatestAnimation{}; size_t GraphDescriptorHash = 0; #ifdef MODDED_BEHAVIOR_COMPATIBILITY - size_t OrigGraphDescriptorHash = 0; // To aid popping back from beast forms. + size_t UnmoddedGraphDescriptorHash = 0; // Hash before any mods change it. + size_t HumanoidGraphDescriptorHash = 0; // Copy of hash before overwritten by beast form. #endif MODDED_BEHAVIOR_COMPATIBILITY private: diff --git a/Code/client/Games/Skyrim/Actor.cpp b/Code/client/Games/Skyrim/Actor.cpp index 8f67f5cb1..eb54d5388 100644 --- a/Code/client/Games/Skyrim/Actor.cpp +++ b/Code/client/Games/Skyrim/Actor.cpp @@ -542,6 +542,17 @@ bool Actor::IsDead() const noexcept bool Actor::IsDragon() const noexcept { +#ifdef MODDED_BEHAVIOR_COMPATIBILITY + const ActorExtension* pExtension = const_cast(this)->GetExtension(); + auto hash = pExtension->UnmoddedGraphDescriptorHash; + + if (hash) + return AnimationGraphDescriptor_BHR_Master::m_key == hash; + + // Still want to continue with the original code, because if Nemesis/Pandora + // isn't on the client at all, BehaviorVar::Patch doesn't run on the Dragons. +#endif MODDED_BEHAVIOR_COMPATIBILITY + // TODO: if anyone has a better way of doing this, please do tell. BSAnimationGraphManager* pManager = nullptr; animationGraphHolder.GetBSAnimationGraph(&pManager); diff --git a/Code/client/Games/Skyrim/PlayerCharacter.cpp b/Code/client/Games/Skyrim/PlayerCharacter.cpp index 951f6bd78..ab0af8320 100644 --- a/Code/client/Games/Skyrim/PlayerCharacter.cpp +++ b/Code/client/Games/Skyrim/PlayerCharacter.cpp @@ -164,7 +164,10 @@ void TP_MAKE_THISCALL(HookSetBeastForm, void, void* apUnk1, void* apUnk2, bool a { PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = AnimationGraphDescriptor_Master_Behavior::m_key; #ifdef MODDED_BEHAVIOR_COMPATIBILITY - PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = PlayerCharacter::Get()->GetExtension()->OrigGraphDescriptorHash; + // Restore instead to saved, modified behavior hash. IF Nemesis/Pandora is installed, otherwise BehaviorVar::Patch() doesn't run. + auto hash = PlayerCharacter::Get()->GetExtension()->HumanoidGraphDescriptorHash; + if (hash) + PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = hash; #endif MODDED_BEHAVIOR_COMPATIBILITY World::Get().GetRunner().Trigger(BeastFormChangeEvent()); diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index fffe15808..d218dba99 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -314,8 +314,8 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apManager, Actor* apActor) { - // Serialize, Actors are multi-threaded. Might not be strictly necessary, I think we're on - // the main game loop, but if so it won't hurt anything. + // Serialize, Actors are multi-threaded. Might not be strictly necessary between being on + // the main game loop and under a BSRecursiveLock, but if so it won't hurt anything. std::lock_guard guard(mutex_lock); // Check if the animation descriptor has already been built. @@ -430,10 +430,13 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa hash, hexFormID, foundRep.creatureName, foundRep.signatureVar); - // Save the new hash for the actor, and save it as the original actor hash. - // The latter is to assist with humanoid actors popping back from a beast form. + // Save the new hash for the actor. Save a copy to restore to if overwritten; this currently + // only happens when humanoids enter beast mode, Humanoid copy is used to change back. + // We also save the original (unmodded) STR hash, because there are some hardwired tests + // that need it (like the IsDragon() test). pExtendedActor->GraphDescriptorHash = hash; - pExtendedActor->OrigGraphDescriptorHash = hash; + pExtendedActor->HumanoidGraphDescriptorHash = hash; + pExtendedActor->UnmoddedGraphDescriptorHash = foundRep.origHash; return constructModdedDescriptor(hash, foundRep, reversemap); } From 93cf9b5f54908b7d933afb23f1e0f9207f1c9506 Mon Sep 17 00:00:00 2001 From: rfortier Date: Thu, 25 Apr 2024 12:01:19 -0400 Subject: [PATCH 47/86] Correct typo. --- Code/client/ModCompat/BehaviorOrigGenerate.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/client/ModCompat/BehaviorOrigGenerate.ps1 b/Code/client/ModCompat/BehaviorOrigGenerate.ps1 index de0205f9e..dc618778d 100644 --- a/Code/client/ModCompat/BehaviorOrigGenerate.ps1 +++ b/Code/client/ModCompat/BehaviorOrigGenerate.ps1 @@ -1,5 +1,5 @@ param ( - [string]$name = "Skyrim", + [string]$name = "Skyrim" ) Set-PSDebug -Trace 1 From 2949d8989ed9d7c97698e98941a6906324f57651 Mon Sep 17 00:00:00 2001 From: rfortier Date: Sun, 28 Apr 2024 16:35:22 -0400 Subject: [PATCH 48/86] Bugfix for case I haven't seen but may happen, where variable name strings must be compared case-independent to match. --- Code/client/ModCompat/BehaviorVar.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index d218dba99..575b3ff2f 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -70,8 +70,7 @@ namespace { std::string toLowerCase(const std::string& acStr) { - std::string lowerCaseStr; - lowerCaseStr.reserve(acStr.size()); + std::string lowerCaseStr(acStr); std::transform(acStr.begin(), acStr.end(), lowerCaseStr.begin(), [](unsigned char c) { return std::tolower(c); }); return lowerCaseStr; From fe4dfa90dae1b18c64cbfba384f2e31cb1e5acf5 Mon Sep 17 00:00:00 2001 From: rfortier Date: Sat, 4 May 2024 13:45:58 -0400 Subject: [PATCH 49/86] Clearer error message. --- Code/client/ModCompat/BehaviorVar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 575b3ff2f..7f169f85e 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -125,7 +125,7 @@ void processVariableSet(const std::map& acRev { aVariableSet.insert(found->second); if (item != found->first) - spdlog::warn(__FUNCTION__ ": misspelled variable {} found as {}", item, found->first); + spdlog::warn(__FUNCTION__ ": misspelled variable {} corrected to {}", item, found->first); } } } From 4af29d1c1aca6cb1c461c281847b61a1568e4706 Mon Sep 17 00:00:00 2001 From: rfortier Date: Sun, 5 May 2024 12:18:12 -0400 Subject: [PATCH 50/86] Move magic_enum.hpp to its proper home in \Libraries --- Code/client/xmake.lua | 2 +- {Code/client/ModCompat => Libraries}/magic_enum.hpp | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {Code/client/ModCompat => Libraries}/magic_enum.hpp (100%) diff --git a/Code/client/xmake.lua b/Code/client/xmake.lua index 88a4a6ee6..2aac9769c 100644 --- a/Code/client/xmake.lua +++ b/Code/client/xmake.lua @@ -5,7 +5,7 @@ target(name) set_group("Client") add_defines(def) - add_includedirs(".") + add_includedirs(".","../../Libraries/") set_pcxxheader("TiltedOnlinePCH.h") -- exclude game specifc stuff diff --git a/Code/client/ModCompat/magic_enum.hpp b/Libraries/magic_enum.hpp similarity index 100% rename from Code/client/ModCompat/magic_enum.hpp rename to Libraries/magic_enum.hpp From 232e906fe77388f98c1489efe20d29681339b681 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 15 May 2024 20:53:40 -0400 Subject: [PATCH 51/86] Clean up now-redundant behavior variable declarations. The base STR Dev-selected variables are now merged with what the mods need, so it is no longer necessary to request inclusion. And it's probably confusing as they shouldn't be there (and devs could change them). --- .../Dragon_BHR_Master/Vanilla__bool.txt | 25 -------- .../Dragon_BHR_Master/Vanilla__float.txt | 27 --------- .../Dragon_BHR_Master/Vanilla__int.txt | 3 - .../humanoid_Master/Vanilla__bool.txt | 60 ------------------- .../humanoid_Master/Vanilla__float.txt | 13 ---- .../humanoid_Master/Vanilla__int.txt | 14 ----- 6 files changed, 142 deletions(-) diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__bool.txt index ce85a02af..e69de29bb 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__bool.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__bool.txt @@ -1,25 +0,0 @@ -bAnimationDriven -bVoiceReady -bWantCastVoice -IsAttackReady -IsShouting -isMoving -bSpeedSynced -IsOnGround -bLookAtTarget -bCanLookAtTarget -bEquipOk -IsBusy -bIsSynced -IsFlapping -IsGliding -HasTweenSpeed -IsTurningLeft -IsTurningRight -IsMovingForward -BSLookAtModifier_CanLookOutsideLimit -MoveDirZ -bFullyMotionDriven -bNoFootIK -bFootIK -LookAtOutOfRange \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__float.txt index 54e9990bf..e69de29bb 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__float.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__float.txt @@ -1,27 +0,0 @@ -Pitch -TurnDelta -Direction -Speed -TargetSpeed -TurnDeltaDamped -PitchDeltaDamped -TargetSpeedDamped -MaxSpeedDamped -LookAtHeadingMaxAngle -m_errorOut -FlightPitchBlend -TweenEntryDirection -LipBigAah -LipDST -LipEee -LipFV -PitchDelta -DistToGoal -PathAngle -BSLookAtModifier_m_onGain -BSLookAtModifier_m_offGain -TimeStep -DirectionDamped -TurnDeltaTarget -PitchDeltaTarget -FlightPitchBlendTarget \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__int.txt index e68d0a8d6..e69de29bb 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__int.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/Dragon_BHR_Master/Vanilla__int.txt @@ -1,3 +0,0 @@ -iSyncIdleLocomotion -iSyncTurnState -iState \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__bool.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__bool.txt index d61840fe2..e69de29bb 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__bool.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__bool.txt @@ -1,60 +0,0 @@ -bEquipOk -bMotionDriven -IsBeastRace -IsSneaking -IsBleedingOut -IsCastingDual -Is1HM -IsCastingRight -IsCastingLeft -IsBlockHit -IsPlayer -IsNPC -bIsSynced -bVoiceReady -bWantCastLeft -bWantCastRight -bWantCastVoice -b1HM_MLh_attack -b1HMCombat -bAnimationDriven -bCastReady -IsAttacking -bAllowRotation -bMagicDraw -bMLh_Ready -bMRh_Ready -bInMoveState -bSprintOK -bIdlePlaying -bIsDialogueExpressive -bAnimObjectLoaded -bEquipUnequip -bAttached -bIsH2HSolo -bHeadTracking -bIsRiding -bTalkable -bRitualSpellActive -bInJumpState -bHeadTrackSpine -bLeftHandAttack -bIsInMT -bHumanoidFootIKEnable -bHumanoidFootIKDisable -bStaggerPlayerOverride -bNoStagger -bIsStaffLeftCasting -bPerkShieldCharge -bPerkQuickShot -IsBlocking -IsBashing -IsStaggering -IsRecoiling -IsEquipping -IsUnequipping -isInFurniture -bNeutralState -bBowDrawn -PitchOverride -NotCasting \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__float.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__float.txt index d5575a0a8..e69de29bb 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__float.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__float.txt @@ -1,13 +0,0 @@ -TurnDelta -Direction -SpeedSampled -weapAdj -Speed -CastBlend -PitchOffset -SpeedDamped -Pitch -VelocityZ -1stPRot -1stPRotDamped -CastBlendDamped \ No newline at end of file diff --git a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__int.txt b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__int.txt index 28da60975..e69de29bb 100644 --- a/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__int.txt +++ b/GameFiles/Skyrim/SkyrimTogetherRebornBehaviors/humanoid_Master/Vanilla__int.txt @@ -1,14 +0,0 @@ -iRightHandEquipped -iLeftHandEquipped -i1HMState -iState -iLeftHandType -iRightHandType -iSyncIdleLocomotion -iSyncForwardState -iSyncTurnState -iIsInSneak -iWantBlock -iRegularAttack -testint -currentDefaultState \ No newline at end of file From 8f7a18cb6e290ab0ab9bb80c65dbe94a3cdf51b8 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 24 Apr 2024 22:43:06 -0400 Subject: [PATCH 52/86] Isolated change to enable conditional compilation of MODDED_BEHAVIOR_COMPATIBILITY. Should be an xmake option, but that doesn't seem to work properly. --- xmake.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xmake.lua b/xmake.lua index c0378f318..3b1739ada 100644 --- a/xmake.lua +++ b/xmake.lua @@ -30,6 +30,9 @@ if has_config("unitybuild") then add_rules("c++.unity_build", {batchsize = 12}) end +-- Single-commit enable MODDED_BEHAVIOR_COMPATIBILITY +add_defines("MODDED_BEHAVIOR_COMPATIBILITY") + -- direct dependencies version pinning add_requires( "entt v3.10.0", From e9ac13514a1934317d3df282ab8cfc30963d2630 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 2 Oct 2024 15:50:13 -0400 Subject: [PATCH 53/86] Apply review fixes, minus clang-format. Conditional compilation is ON now. clang-format will get an isolated commit. Replaces lingering std:: types with TiltedPhoques:: types wherever feasible; there are a couple of cases where TP is missing function or breaks type conversion. Applies style guide naming conventions where there were misses. Fixes missing failure check on file opens. The paths must exist (they are from a directory iterator), but read permission could be missing. Cleaned up readme. --- Code/client/ModCompat/BehaviorOrig.cpp | 6 +- Code/client/ModCompat/BehaviorVar.cpp | 223 ++++++++++++---------- Code/client/ModCompat/BehaviorVar.h | 49 ++--- Code/client/ModCompat/BehaviorVarsMap.cpp | 18 +- Code/client/ModCompat/BehaviorVarsMap.h | 12 +- README-ANIMATION-MODS.md | 20 +- 6 files changed, 172 insertions(+), 156 deletions(-) diff --git a/Code/client/ModCompat/BehaviorOrig.cpp b/Code/client/ModCompat/BehaviorOrig.cpp index 56b4e650d..8eea5fa59 100644 --- a/Code/client/ModCompat/BehaviorOrig.cpp +++ b/Code/client/ModCompat/BehaviorOrig.cpp @@ -18,14 +18,14 @@ template void GenerateFromEnum(uint64_t aKey) sig.m_key = aKey; for (size_t index = 0; index < count; index++) { - std::string name = static_cast(variables_names[index]); + TiltedPhoques::String name(variables_names[index]); uint32_t value = enum_integer(variables_values[index]); // Remove the leading 'k' name = name.substr(1, name.size() - 1); - sig.m_namemap[name] = value; - sig.m_valuemap[value] = name; + sig.m_nameMap[name] = value; + sig.m_valueMap[value] = name; } BehaviorVarsMap::getInstance().Register(sig); diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 7f169f85e..bd9293757 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -68,34 +68,35 @@ const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apMana // We'd like to be able to handle other vars for which this may be the case. namespace { -std::string toLowerCase(const std::string& acStr) +TiltedPhoques::String ToLowerCase(const TiltedPhoques::String& acStr) { - std::string lowerCaseStr(acStr); + TiltedPhoques::String lowerCaseStr(acStr); std::transform(acStr.begin(), acStr.end(), lowerCaseStr.begin(), [](unsigned char c) { return std::tolower(c); }); return lowerCaseStr; } -// Converts the keys of a map (which are const std::string) to lowercase. +// Converts the keys of a map (which are TiltedPhoques::String) to lowercase. // This is our "Plan C" if a vanilla var isn't found to make sure it isn't just a case-sensitivity issue. -void lowerCaseKeys(const std::map& acMap, - std::map& aLowerCaseMap) +void LowerCaseKeys(const TiltedPhoques::Map& acMap, TiltedPhoques::Map& aLowerCaseMap) { for (const auto& item : acMap) - aLowerCaseMap.insert({toLowerCase(item.first), item.second}); + aLowerCaseMap.insert({ToLowerCase(item.first), item.second}); } // Process a set of variables, adding them to the aVariableSet -void processVariableSet(const std::map& acReverseMap, - std::set& aVariableSet, const std::vector& acVariables, - spdlog::level::level_enum aLogLevel) +void ProcessVariableSet( + TiltedPhoques::Map& acReverseMap, + TiltedPhoques::Set& aVariableSet, + const TiltedPhoques::Vector& acVariables, + spdlog::level::level_enum aLogLevel) { // Not filled until needed, which should be never. - std::map lowerCaseMap; + TiltedPhoques::Map lowerCaseMap; for (const auto& item : acVariables) { - std::string foundForm = item; + auto foundForm = item; auto found = acReverseMap.find(item); if (found == acReverseMap.end()) { @@ -107,7 +108,7 @@ void processVariableSet(const std::map& acRev if (found == acReverseMap.end()) { // Check lower case. - foundForm = toLowerCase(item); + foundForm = ToLowerCase(item); found = acReverseMap.find(foundForm); } @@ -115,7 +116,7 @@ void processVariableSet(const std::map& acRev { // Check case-independent if (lowerCaseMap.empty()) - lowerCaseKeys(acReverseMap, lowerCaseMap); + LowerCaseKeys(acReverseMap, lowerCaseMap); found = lowerCaseMap.find(foundForm); } @@ -143,23 +144,23 @@ void processVariableSet(const std::map& acRev // The machine-generated table hack to do this can be removed with STR-devs' // permission to also embed the string information in the Code\encoding\structs files. // -void BehaviorVar::seedAnimationVariables( +void BehaviorVar::SeedAnimationVariables( const uint64_t acHash, const AnimationGraphDescriptor* acpDescriptor, - const std::map& acReversemap, - std::set& aBoolVars, - std::set& aFloatVars, - std::set& aIntVars) + TiltedPhoques::Map& acReverseMap, + TiltedPhoques::Set& aBoolVars, + TiltedPhoques::Set& aFloatVars, + TiltedPhoques::Set& aIntVars) { auto& origVars = BehaviorVarsMap::getInstance(); // Prepare lists of variables to process - std::vector boolVarNames; - std::vector floatVarNames; - std::vector intVarNames; + TiltedPhoques::Vector boolVarNames; + TiltedPhoques::Vector floatVarNames; + TiltedPhoques::Vector intVarNames; // Populate lists from the original descriptor - std::string strValue; + TiltedPhoques::String strValue; for (auto& item : acpDescriptor->BooleanLookUpTable) if ((strValue = origVars.find(acHash, item)).empty()) spdlog::error(__FUNCTION__ ": unable to find string for original BooleanVar {}", item); @@ -179,9 +180,9 @@ void BehaviorVar::seedAnimationVariables( intVarNames.push_back(strValue); // Process each set of variables - processVariableSet(acReversemap, aBoolVars, boolVarNames, spdlog::level::level_enum::err); - processVariableSet(acReversemap, aFloatVars, floatVarNames, spdlog::level::level_enum::err); - processVariableSet(acReversemap, aIntVars, intVarNames, spdlog::level::level_enum::err); + ProcessVariableSet(acReverseMap, aBoolVars, boolVarNames, spdlog::level::level_enum::err); + ProcessVariableSet(acReverseMap, aFloatVars, floatVarNames, spdlog::level::level_enum::err); + ProcessVariableSet(acReverseMap, aIntVars, intVarNames, spdlog::level::level_enum::err); } // Syntax for a signature is [!]sig1[,[!]sig2]... Must be at least one. Each signature var possibly negated @@ -189,10 +190,10 @@ void BehaviorVar::seedAnimationVariables( // Requires that whitespace has already been deleted (which it was, when directories were loaded). // Tokenize on ',' // -const std::vector BehaviorVar::tokenizeBehaviorSig(const std::string acSignature) const +const TiltedPhoques::Vector BehaviorVar::TokenizeBehaviorSig(const TiltedPhoques::String& acSignature) const { - const static std::string notVal{"!"}; - std::vector retVal; + const static TiltedPhoques::String notVal{"!"}; + TiltedPhoques::Vector retVal; size_t commaPos; size_t offset = 0; @@ -212,16 +213,12 @@ const std::vector BehaviorVar::tokenizeBehaviorSig(const std::strin return retVal; } - -const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uint64_t acNewHash, const Replacer& acReplacer, std::map& acReverseMap) +const AnimationGraphDescriptor* BehaviorVar::ConstructModdedDescriptor(const uint64_t acNewHash, const Replacer& acReplacer, TiltedPhoques::Map& acReverseMap) { // Build the set of BehaviorVar strings as sets (not vectors) to eliminate dups - // Also, we want the set sorted, so these have to be std::sets. TiltedPhoques::Set - // uses a hash map instead of a sorted tree, and I don't want to have to figure - // out how to override that. - std::set boolVar; - std::set floatVar; - std::set intVar; + TiltedPhoques::Set boolVar; + TiltedPhoques::Set floatVar; + TiltedPhoques::Set intVar; // If we can find the original behavior that is being modded, // get the descriptor and seed the behavior vars with it. @@ -230,7 +227,7 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin const AnimationGraphDescriptor* pTmpGraph = nullptr; if (acReplacer.origHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(acReplacer.origHash))) { - seedAnimationVariables(acReplacer.origHash, pTmpGraph, acReverseMap, boolVar, floatVar, intVar); + SeedAnimationVariables(acReplacer.origHash, pTmpGraph, acReverseMap, boolVar, floatVar, intVar); spdlog::info(__FUNCTION__ ": Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", acReplacer.origHash, boolVar.size(), floatVar.size(), intVar.size()); } @@ -286,10 +283,17 @@ const AnimationGraphDescriptor* BehaviorVar::constructModdedDescriptor(const uin intVar.size(), acReplacer.syncIntegerVar.size()); + // We need the sets sorted, and TiltedPhoques::Set is not. Copying to an std::set + // isn't the most efficient approach, but it is simple and doesn't happen often enough + // to worry about. And doing it here isolates/minimizes use of std::set. + std::set boolVarSorted(boolVar.begin(), boolVar.end()); + std::set floatVarSorted(floatVar.begin(), floatVar.end()); + std::set intVarSorted(intVar.begin(), intVar.end()); + // Reshape the (sorted, unique) sets to vectors - TiltedPhoques::Vector boolVector(boolVar.begin(), boolVar.end()); - TiltedPhoques::Vector floatVector(floatVar.begin(), floatVar.end()); - TiltedPhoques::Vector intVector(intVar.begin(), intVar.end()); + TiltedPhoques::Vector boolVector(boolVarSorted.begin(), boolVarSorted.end()); + TiltedPhoques::Vector floatVector(floatVarSorted.begin(), floatVarSorted.end()); + TiltedPhoques::Vector intVector(intVarSorted.begin(), intVarSorted.end()); // Construct a new descriptor auto panimGraphDescriptor = new AnimationGraphDescriptor(); @@ -350,7 +354,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa // modded behavior. Only failListed for minutes to occasionally get log messages // so we can think about fixing it. Or the case of dynamic behavior and behavior // signature changes that might work later (yes, mods like that exist) - if (failListed(hash)) + if (FailListed(hash)) return nullptr; // Up to here the routine is pretty cheap, and WILL be called a bunch of times @@ -365,12 +369,12 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa // Get all animation variables for this actor, then create a acReverseMap to go from strings to animation enum. auto pDumpVar = apManager->DumpAnimationVariables(false); - std::map reversemap; + TiltedPhoques::Map< TiltedPhoques::String, uint32_t> reverseMap; spdlog::info("Known behavior variables for formID {:x}:", hexFormID); for (auto& item : pDumpVar) { spdlog::info(" {}:{}", item.first, item.second); - reversemap.insert({static_cast(item.second), item.first}); + reverseMap.insert({item.second, item.first}); } // See if these animation variables include a signature for one of the replacers. @@ -389,15 +393,15 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa for (size_t i = 0; i < behaviorPool.size(); i++) { - auto tokens = tokenizeBehaviorSig(behaviorPool[i].signatureVar); + auto tokens = TokenizeBehaviorSig(behaviorPool[i].signatureVar); auto found = tokens.size() > 0; for (auto titer = tokens.begin(); found && titer < tokens.end(); titer++) { if (*titer == "!") - found = reversemap.find(*++titer) == reversemap.end(); + found = reverseMap.find(*++titer) == reverseMap.end(); else - found = reversemap.find(*titer) != reversemap.end(); + found = reverseMap.find(*titer) != reverseMap.end(); } if (found) matchedReplacers.push_back(i); @@ -409,7 +413,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa spdlog::warn(__FUNCTION__ ": no original behavior found for behavior hash {:x} (found on formID {:x}), adding to " "fail list", hash, hexFormID); - failList(hash); + FailList(hash); return nullptr; case 1: @@ -419,15 +423,14 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa spdlog::critical(__FUNCTION__ ": multiple behavior replacers have the same signature, this must be corrected:"); for (auto& item : matchedReplacers) spdlog::critical(" {}", behaviorPool[item].creatureName); - failList(hash); + FailList(hash); return nullptr; } auto& foundRep = behaviorPool[matchedReplacers[0]]; spdlog::info(__FUNCTION__ ": found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", - hash, - hexFormID, foundRep.creatureName, foundRep.signatureVar); + hash, hexFormID, foundRep.creatureName, foundRep.signatureVar); // Save the new hash for the actor. Save a copy to restore to if overwritten; this currently // only happens when humanoids enter beast mode, Humanoid copy is used to change back. @@ -437,33 +440,33 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa pExtendedActor->HumanoidGraphDescriptorHash = hash; pExtendedActor->UnmoddedGraphDescriptorHash = foundRep.origHash; - return constructModdedDescriptor(hash, foundRep, reversemap); + return ConstructModdedDescriptor(hash, foundRep, reverseMap); } // Check if the behavior hash is on the failed liist -boolean BehaviorVar::failListed(uint64_t hash) +bool BehaviorVar::FailListed(uint64_t hash) { auto iter = failedBehaviors.find(hash); return iter != failedBehaviors.end() && std::chrono::steady_clock::now() < iter->second; } //Place the behavior hash on the failed list -void BehaviorVar::failList(uint64_t hash) +void BehaviorVar::FailList(uint64_t hash) { failedBehaviors.insert_or_assign(hash, std::chrono::steady_clock::now() + FAILLIST_DURATION); } // Find all the subdirectories of behavior variables -std::vector BehaviorVar::loadDirs(const std::filesystem::path& acPATH) +TiltedPhoques::Vector BehaviorVar::LoadDirs(const std::filesystem::path& acPath) { - std::vector result; - for (auto& p : std::filesystem::directory_iterator(acPATH)) + TiltedPhoques::Vector result; + for (auto& p : std::filesystem::directory_iterator(acPath)) if (p.is_directory()) result.push_back(p.path().string()); return result; } -BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aDir) +BehaviorVar::Replacer* BehaviorVar::LoadReplacerFromDir(const std::filesystem::path& aDir) { // Enumerate all files in the directory and push bools, ints and floats // to their respective vectors @@ -478,16 +481,16 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aD // modded actor, that we can use to connect the actor to their modded behavior variables. // It's not actually sync'ed, just there so we can find the match. For example, currently // bSTRMaster is used for humanoid/Player actors, and bSTRDragon for dragon behavior. - std::string hashFile; - std::string signatureFile; - std::vector floatVarsFile; - std::vector intVarsFile; - std::vector boolVarsFile; + TiltedPhoques::String hashFile; + TiltedPhoques::String signatureFile; + TiltedPhoques::Vector floatVarsFile; + TiltedPhoques::Vector intVarsFile; + TiltedPhoques::Vector boolVarsFile; for (auto& p : std::filesystem::directory_iterator(aDir)) { - std::string path = p.path().string(); - std::string base_filename = path.substr(path.find_last_of("/\\") + 1); + TiltedPhoques::String path(p.path().string()); + TiltedPhoques::String base_filename = path.substr(path.find_last_of("/\\") + 1); spdlog::debug("base_path: {}", base_filename); @@ -531,17 +534,21 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aD return nullptr; // Prepare reading files - std::string sigVar; - std::string creatureName = aDir.filename().string(); - std::vector floatVar; - std::vector intVar; - std::vector boolVar; - std::string tempString; // Temp string - - std::ifstream fileSig(signatureFile); + TiltedPhoques::String sigVar; + TiltedPhoques::String creatureName(aDir.filename().string()); + TiltedPhoques::Vector floatVar; + TiltedPhoques::Vector intVar; + TiltedPhoques::Vector boolVar; + TiltedPhoques::String tempString; // Temp string + + // If signature file is unreadable, this directory is useless. + std::ifstream fileSig(signatureFile.c_str(), std::ifstream::in); + if (!fileSig.is_open()) + return nullptr; + getline(fileSig, sigVar); // grab the signature variable fileSig.close(); - erase_if(sigVar, isspace); // removes any inadvertant whitespace + erase_if(sigVar, isspace); // removes any inadvertent whitespace if (sigVar.size() == 0) return nullptr; spdlog::info(__FUNCTION__ ": found {} with signature variable {}", creatureName, sigVar); @@ -561,12 +568,15 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aD uint64_t orgHash = 0; if (hashFile.size()) { - std::ifstream file(hashFile); - getline(file, tempString); - file.close(); - erase_if(tempString, isspace); // removes any inadvertant whitespace - orgHash = std::strtoull(tempString.c_str(), nullptr, 10); - spdlog::info("Replacer specifies original hash {} for {}", orgHash, creatureName); + std::ifstream file(hashFile.c_str(), std::ifstream::in); + if (file.is_open()) + { + getline(file, tempString); + file.close(); + erase_if(tempString, isspace); // removes any inadvertant whitespace + orgHash = std::strtoull(tempString.c_str(), nullptr, 10); + spdlog::info("Replacer specifies original hash {} for {}", orgHash, creatureName); + } } // Build lists of variables to sync @@ -574,48 +584,57 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aD spdlog::debug("reading float var"); for (auto& item : floatVarsFile) { - std::ifstream file(item); - while (std::getline(file, tempString)) + std::ifstream file(item.c_str(), std::ifstream::in); + if (file.is_open()) { - floatVar.push_back(tempString); + while (std::getline(file, tempString)) + { + floatVar.push_back(tempString); - spdlog::debug(" " + tempString); + spdlog::debug(" " + tempString); + } + file.close(); } - file.close(); } // Read integer behavior variables spdlog::debug("reading int vars"); for (auto& item : intVarsFile) { - std::ifstream file(item); - while (std::getline(file, tempString)) + std::ifstream file(item.c_str(), std::ifstream::in); + if (file.is_open()) { - intVar.push_back(tempString); + while (std::getline(file, tempString)) + { + intVar.push_back(tempString); - spdlog::debug(" " + tempString); + spdlog::debug(" " + tempString); + } + file.close(); } - file.close(); } // Read boolean behavior variables spdlog::debug("reading bool vars"); for (auto& item : boolVarsFile) { - std::ifstream file(item); - while (std::getline(file, tempString)) + std::ifstream file(item.c_str(), std::ifstream::in); + if (file.is_open()) { - boolVar.push_back(tempString); + while (std::getline(file, tempString)) + { + boolVar.push_back(tempString); - spdlog::debug(" " + tempString); + spdlog::debug(" " + tempString); + } + file.close(); } - file.close(); } // Create the replacer Replacer* result = new Replacer(); - result->origHash = orgHash; + result->origHash = orgHash; result->signatureVar = sigVar; result->creatureName = creatureName; result->syncBooleanVar = boolVar; @@ -628,13 +647,13 @@ BehaviorVar::Replacer* BehaviorVar::loadReplacerFromDir(std::filesystem::path aD // Find any behaviors which match the signature. // There should be exactly one. // -std::vector BehaviorVar::signatureMatches(const uint64_t acHash, const std::string acSignature) const +TiltedPhoques::Vector BehaviorVar::SignatureMatches(const uint64_t acHash, const TiltedPhoques::String& acSignature) const { auto& bvMap = BehaviorVarsMap::getInstance(); - std::vector hashes; + TiltedPhoques::Vector hashes; - bvMap.hashes(hashes); - auto tokens = tokenizeBehaviorSig(acSignature); + bvMap.Hashes(hashes); + auto tokens = TokenizeBehaviorSig(acSignature); for (size_t i = 0; i < hashes.size(); i++) { if (hashes[i] == acHash) @@ -667,11 +686,11 @@ void BehaviorVar::Init() if (!std::filesystem::is_directory(pBehaviorsPath)) return; - auto behaviorDirs = loadDirs(pBehaviorsPath); + auto behaviorDirs = LoadDirs(pBehaviorsPath); for (auto& dir : behaviorDirs) { - Replacer* sig = loadReplacerFromDir(dir); + Replacer* sig = LoadReplacerFromDir(dir); if (sig) { behaviorPool.push_back(*sig); @@ -683,7 +702,7 @@ void BehaviorVar::Init() { static size_t firsttime = 0; - auto matches = signatureMatches(signature.origHash, signature.signatureVar); + auto matches = SignatureMatches(signature.origHash, signature.signatureVar); switch (matches.size()) { case 0: diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index 4aeec398e..7caab8e35 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -9,11 +9,11 @@ struct BehaviorVar { uint64_t origHash; uint64_t newHash; - std::string signatureVar; - std::string creatureName; - std::vector syncBooleanVar; - std::vector syncFloatVar; - std::vector syncIntegerVar; + TiltedPhoques::String signatureVar; + TiltedPhoques::String creatureName; + TiltedPhoques::Vector syncBooleanVar; + TiltedPhoques::Vector syncFloatVar; + TiltedPhoques::Vector syncIntegerVar; bool operator==(const uint64_t& acRHS) const { return origHash == acRHS; @@ -22,8 +22,8 @@ struct BehaviorVar static BehaviorVar* Get(); const AnimationGraphDescriptor* Patch(BSAnimationGraphManager* apManager, Actor* apActor); - boolean failListed(const uint64_t acHash); - void failList(const uint64_t acHash); + bool FailListed(const uint64_t acHash); + void FailList(const uint64_t acHash); void Init(); void Debug(); @@ -32,25 +32,26 @@ struct BehaviorVar static BehaviorVar* single; uint64_t invocations = 0; - void seedAnimationVariables( + void SeedAnimationVariables( const uint64_t acHash, const AnimationGraphDescriptor* acpDescriptor, - const std::map& acReversemap, - std::set& aBoolVars, - std::set& aFloatVars, - std::set& aIntVars); - - const std::vector tokenizeBehaviorSig(const std::string acSignature) const; - const AnimationGraphDescriptor* constructModdedDescriptor( - const uint64_t acNewHash, const Replacer& acReplacer, - std::map& acReverseMap); - - std::vector loadDirs(const std::filesystem::path& acPATH); - Replacer* loadReplacerFromDir(const std::filesystem::path acDir); - std::vector signatureMatches(const uint64_t acHash, const std::string acSignature) const; - - std::vector behaviorPool; // Pool for loaded behaviours - std::map failedBehaviors; + TiltedPhoques::Map& acReverseMap, + TiltedPhoques::Set& aBoolVars, + TiltedPhoques::Set& aFloatVars, + TiltedPhoques::Set& aIntVars); + + const TiltedPhoques::Vector TokenizeBehaviorSig(const TiltedPhoques::String& acSignature) const; + const AnimationGraphDescriptor* ConstructModdedDescriptor( + const uint64_t acNewHash, + const Replacer& acReplacer, + TiltedPhoques::Map& acReverseMap); + + TiltedPhoques::Vector LoadDirs(const std::filesystem::path& acPath); + Replacer* LoadReplacerFromDir(const std::filesystem::path& acDir); + TiltedPhoques::Vector SignatureMatches(const uint64_t acHash, const TiltedPhoques::String& acSignature) const; + + TiltedPhoques::Vector behaviorPool; // Pool for loaded behaviors + TiltedPhoques::Map failedBehaviors; }; extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apManager, Actor* apActor); diff --git a/Code/client/ModCompat/BehaviorVarsMap.cpp b/Code/client/ModCompat/BehaviorVarsMap.cpp index 17cb6c0a8..6a8f29ef7 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.cpp +++ b/Code/client/ModCompat/BehaviorVarsMap.cpp @@ -2,31 +2,31 @@ #include "BehaviorVarsMap.h" -uint32_t BehaviorVarsMap::find(const uint64_t acKey, const std::string acName) +const uint32_t BehaviorVarsMap::find(const uint64_t acBehaviorVarsKey, const TiltedPhoques::String acName) { - auto map = m_map.find(acKey); + auto map = m_map.find(acBehaviorVarsKey); if (map != m_map.end()) { - auto map2 = map->second.m_namemap.find(acName); + auto map2 = map->second.m_nameMap.find(acName); - if (map2 != map->second.m_namemap.end()) + if (map2 != map->second.m_nameMap.end()) return map2->second; } return UINT32_MAX; } -std::string BehaviorVarsMap::find(const uint64_t acKey, const uint32_t acValue) +const TiltedPhoques::String BehaviorVarsMap::find(const uint64_t acBehaviorVarsKey, const uint32_t acValue) { - constexpr std::string empty; + const TiltedPhoques::String empty; - auto map = m_map.find(acKey); + auto map = m_map.find(acBehaviorVarsKey); if (map != m_map.end()) { - auto map2 = map->second.m_valuemap.find(acValue); + auto map2 = map->second.m_valueMap.find(acValue); - if (map2 != map->second.m_valuemap.end()) + if (map2 != map->second.m_valueMap.end()) return map2->second; } diff --git a/Code/client/ModCompat/BehaviorVarsMap.h b/Code/client/ModCompat/BehaviorVarsMap.h index 6a291ad5d..0ff354bbf 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.h +++ b/Code/client/ModCompat/BehaviorVarsMap.h @@ -4,8 +4,8 @@ struct BehaviorVars { uint64_t m_key; - std::map m_namemap; - std::map m_valuemap; + TiltedPhoques::Map m_nameMap; + TiltedPhoques::Map m_valueMap; }; @@ -13,7 +13,7 @@ struct BehaviorVars class BehaviorVarsMap { private: - std::map m_map; + TiltedPhoques::Map m_map; // Singleton BehaviorVarsMap(){}; @@ -21,10 +21,10 @@ class BehaviorVarsMap void operator=(BehaviorVarsMap const&) = delete; public: - uint32_t find(const uint64_t acKey, const std::string acName); + const uint32_t find(const uint64_t acBehaviorVarKey, const TiltedPhoques::String acName); - std::string find(const uint64_t acKey, const uint32_t acValue); - void hashes(std::vector& aHashes) const + const TiltedPhoques::String find(const uint64_t acBehaviorVarKey, const uint32_t acValue); + void Hashes(TiltedPhoques::Vector& aHashes) const { aHashes.clear(); for (auto& item : m_map) diff --git a/README-ANIMATION-MODS.md b/README-ANIMATION-MODS.md index 5ff0208de..e17250c8c 100644 --- a/README-ANIMATION-MODS.md +++ b/README-ANIMATION-MODS.md @@ -5,47 +5,43 @@ and [here](https://wiki.tiltedphoques.com/tilted-online/guides/getting-started#r don't bother the development team. That said, the developers have graciously included contributed, limited support for behaviors/animations mods such as those generated by Nemesis, or the newer Pandora. If you use this capability, -report issues to the author(s) of the support. Preferably file an issue with the authors on github, [here](https://github.com/rfortier/TiltedEvolution-rwf/issues), or you may find help from Ujave or MagicWizardMan on the -Skyrim Together Reborn Discord. +report issues to the author(s) of animation. Preferably file an issue with the authors on github, [here](https://github.com/rfortier/TiltedEvolution-rwf/issues), or you may find help from Ujave or others on the +Skyrim Together Reborn #modding Discord channel. ## License [![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html) -However, no permission to post any variation of this fork on Nexus. For now. It's coming, there are just more things to fix first so we don't get flooded with support requests. - # Credits This fork is inspired by Edho08's original effort to figure out how to patch Nemesis (and now Pandora) support into TiltedPhoques Skyrim Together Reborn. -Since then, Spvvd and Ragley have put maintenance effort into versions up to 1.5.0 of STR. This version targets the upcoming v1.6.x release of STR and adds a ton of features. +Since then, Spvvd and Ragley have put maintenance effort into versions up to 1.5.0 of STR. This version targets the upcoming v1.6.x and later releases of STR and adds a ton of features. @rfortier and @MostExcellent have contributed to it. # Status This version is a substantial rewrite, fixing a lot of bugs, adding flexibility that enables the STR development team and modders to work more independently without breaking each other (as much). -It has been ported to v1.6.x-preview of Skyrim Together Reborn. +It has been ported to v1.6.x+ of Skyrim Together Reborn. -Importantly, _the goal is for it to be wire-protocol comnpatible with vanilla public STR servers._ This goal still needs to be proven. And as always, only clients with the same version and the same modlist +Importantly, _the goal is for it to be wire-protocol compatible with vanilla public STR servers._ As always, only clients with the same version and the same modlist can connect to the same server. Includes TDM, TUDM, Modern Combat Overhaul, Elden Counter and dragon behavior patches. Oh, and humans don't skate around. Sometimes animations still don't sync, restarting game+server or rerunning Nemesis and syncing the output with your friends can fix it in most cases. -Tested extensively with Skyrim Version 1.6.640.0 and you can only join servers running this build of STR. It might work with the latest Skyrim and the correct address library, but it has barely been tested. -And the STR team has not released 1.6.x yet. +Tested extensively with Skyrim Version 1.6.1170.0 and you can only join servers running this build of STR. It might work with the earlier 1.6+ versions of Skyrim with the correct address library, but it has barely been tested +on those older releases. This version by RFortier and MostExcellent adds these goals: * Wire protocol compatibility. * Beast mode (werewolf, vampire lord) support. -* Pure feature branch to make it easily rebaseable. * Minimal intrusion in the base code. * Feature is conditionally compiled. Enabled by a single commit in the history which will show the one(-ish) line to comment out to turn it off. Or, don't include that commit. -* In theory, if a client with modded animations support is compile to the same version as the vanilla STR, the vanilla server will support that client. * Tries to remove as much of the complexity for modders as possible. To mod a behavior you don't need anything about the behavior variables the Dev team has chosen, nor do you need to know the old or new hashes that will be generated by your new behaviors; the game calculates them. That's pretty important because _every_ mod that changes behavior changes the hash, and the order of mods may also change the hash (unless you use Pandora which fixes that evil). That means a mod author _can't_ know the new hash for the mods a user selects, it is only known for a specific modlist in a specific order. -* It's to your advantage to know the _original STR game behavior hash_ you are moddifying, though; if you do, you only need to list the behavior variables your mod needs, +* It's to your advantage to know the _original STR game behavior hash_ you are modifying, though; if you do, you only need to list the behavior variables your mod needs, the rest that the STR dev team selects will be picked up automatically for you. This helps give your mod STR version-independence. The SkyrimTogetherRebornBehaviors tree is pre-populated with this information for the creatures supported by STR. From 7b3dad78c2d3b1b7a872cbff4cf913796e9e1502 Mon Sep 17 00:00:00 2001 From: rfortier Date: Wed, 2 Oct 2024 17:15:47 -0400 Subject: [PATCH 54/86] clang-format changes in isolated commit Also rebase to lateest /dev --- Code/client/ModCompat/BehaviorOrig.cpp | 5 +- Code/client/ModCompat/BehaviorVar.cpp | 178 +++++++++++----------- Code/client/ModCompat/BehaviorVar.h | 22 ++- Code/client/ModCompat/BehaviorVarsMap.cpp | 4 +- Code/client/ModCompat/BehaviorVarsMap.h | 11 +- 5 files changed, 104 insertions(+), 116 deletions(-) diff --git a/Code/client/ModCompat/BehaviorOrig.cpp b/Code/client/ModCompat/BehaviorOrig.cpp index 8eea5fa59..e58d6e367 100644 --- a/Code/client/ModCompat/BehaviorOrig.cpp +++ b/Code/client/ModCompat/BehaviorOrig.cpp @@ -4,7 +4,6 @@ #define MAGIC_ENUM_RANGE_MAX 400 #include "magic_enum.hpp" - namespace BehaviorOrig { template void GenerateFromEnum(uint64_t aKey) @@ -24,7 +23,7 @@ template void GenerateFromEnum(uint64_t aKey) // Remove the leading 'k' name = name.substr(1, name.size() - 1); - sig.m_nameMap[name] = value; + sig.m_nameMap[name] = value; sig.m_valueMap[value] = name; } @@ -37,6 +36,6 @@ template void GenerateFromEnum(uint64_t aKey) #include "BehaviorOrig.Fallout4" #endif -} // using namespace BehaviorOrig +} // namespace BehaviorOrig #endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index bd9293757..e35372a63 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -6,14 +6,14 @@ // for unlimited behavior variables, for seeding modded behaviors with the original BehaviorVars // (decoupling STR devs decisions from what modders need to know) and support for beast forms // among many more changes. -// +// // One of the greatest features ensuring the longevity of Bethesda games is their support -// for community modification, and many of the most popular mods also change the behavior +// for community modification, and many of the most popular mods also change the behavior // of creatures. STR and FTR don't support mods as a matter of policy. And supporting // behavior mods is particularly difficult. This mod provides the option to use modified -// behaviors in Skyrim|Fallout Together Reborn, but has yet to be endorsed by the TiltedPhoques +// behaviors in Skyrim|Fallout Together Reborn, but has yet to be endorsed by the TiltedPhoques // team. Use at own risk. -// +// // The game determines a set of behavior variables that must be synced and locks that down. // Changing the list is difficult, because behavior mods won't just add to the list, they // will change the order of the list also changing the shorthand numeric codes for behavior @@ -25,7 +25,7 @@ // 3) We must add in the additional behavior variables requested by modders // 4) Finally, that will push us over some hard-coded limits, in particular // a limit of 64 boolean vars that can be synced. Remove the limit. -// +// #ifdef MODDED_BEHAVIOR_COMPATIBILITY #include @@ -36,7 +36,7 @@ #if TP_SKYRIM64 #include -#include // Camera 1st person is only in Skyrim? +#include // Camera 1st person is only in Skyrim? #include #endif @@ -56,7 +56,7 @@ BehaviorVar* BehaviorVar::Get() return BehaviorVar::single; } -// A simple function can be declared, caller file doesn't have to include our +// A simple function can be declared, caller file doesn't have to include our // class/struct header. const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apManager, Actor* apActor) { @@ -71,7 +71,7 @@ namespace TiltedPhoques::String ToLowerCase(const TiltedPhoques::String& acStr) { TiltedPhoques::String lowerCaseStr(acStr); - std::transform(acStr.begin(), acStr.end(), lowerCaseStr.begin(), + std::transform(acStr.begin(), acStr.end(), lowerCaseStr.begin(), [](unsigned char c) { return std::tolower(c); }); return lowerCaseStr; } @@ -86,8 +86,8 @@ void LowerCaseKeys(const TiltedPhoques::Map& ac // Process a set of variables, adding them to the aVariableSet void ProcessVariableSet( - TiltedPhoques::Map& acReverseMap, - TiltedPhoques::Set& aVariableSet, + TiltedPhoques::Map& acReverseMap, + TiltedPhoques::Set& aVariableSet, const TiltedPhoques::Vector& acVariables, spdlog::level::level_enum aLogLevel) { @@ -130,7 +130,7 @@ void ProcessVariableSet( } } } - + } // End anonymous namespace // @@ -140,16 +140,16 @@ void ProcessVariableSet( // BehaviorVars chosen (numerically) by the STR devs to their new numeric values. // We do this with a hack to translate old numeric value back to a string, then we // can forward-translate the string to its new numeric value. -// +// // The machine-generated table hack to do this can be removed with STR-devs' // permission to also embed the string information in the Code\encoding\structs files. // void BehaviorVar::SeedAnimationVariables( - const uint64_t acHash, + const uint64_t acHash, const AnimationGraphDescriptor* acpDescriptor, - TiltedPhoques::Map& acReverseMap, - TiltedPhoques::Set& aBoolVars, - TiltedPhoques::Set& aFloatVars, + TiltedPhoques::Map& acReverseMap, + TiltedPhoques::Set& aBoolVars, + TiltedPhoques::Set& aFloatVars, TiltedPhoques::Set& aIntVars) { auto& origVars = BehaviorVarsMap::getInstance(); @@ -167,22 +167,22 @@ void BehaviorVar::SeedAnimationVariables( else boolVarNames.push_back(strValue); - for (auto& item : acpDescriptor->FloatLookupTable) + for (auto& item : acpDescriptor->FloatLookupTable) if ((strValue = origVars.find(acHash, item)).empty()) spdlog::error(__FUNCTION__ ": unable to find string for original FloatVar {}", item); else floatVarNames.push_back(strValue); - for (auto& item : acpDescriptor->IntegerLookupTable) + for (auto& item : acpDescriptor->IntegerLookupTable) if ((strValue = origVars.find(acHash, item)).empty()) spdlog::error(__FUNCTION__ ": unable to find string for original IntVar {}", item); else intVarNames.push_back(strValue); // Process each set of variables - ProcessVariableSet(acReverseMap, aBoolVars, boolVarNames, spdlog::level::level_enum::err); - ProcessVariableSet(acReverseMap, aFloatVars, floatVarNames, spdlog::level::level_enum::err); - ProcessVariableSet(acReverseMap, aIntVars, intVarNames, spdlog::level::level_enum::err); + ProcessVariableSet(acReverseMap, aBoolVars, boolVarNames, spdlog::level::level_enum::err); + ProcessVariableSet(acReverseMap, aFloatVars, floatVarNames, spdlog::level::level_enum::err); + ProcessVariableSet(acReverseMap, aIntVars, intVarNames, spdlog::level::level_enum::err); } // Syntax for a signature is [!]sig1[,[!]sig2]... Must be at least one. Each signature var possibly negated @@ -213,12 +213,15 @@ const TiltedPhoques::Vector BehaviorVar::TokenizeBehavior return retVal; } -const AnimationGraphDescriptor* BehaviorVar::ConstructModdedDescriptor(const uint64_t acNewHash, const Replacer& acReplacer, TiltedPhoques::Map& acReverseMap) +const AnimationGraphDescriptor* BehaviorVar::ConstructModdedDescriptor( + const uint64_t acNewHash, + const Replacer& acReplacer, + TiltedPhoques::Map& acReverseMap) { // Build the set of BehaviorVar strings as sets (not vectors) to eliminate dups TiltedPhoques::Set boolVar; TiltedPhoques::Set floatVar; - TiltedPhoques::Set intVar; + TiltedPhoques::Set intVar; // If we can find the original behavior that is being modded, // get the descriptor and seed the behavior vars with it. @@ -228,8 +231,12 @@ const AnimationGraphDescriptor* BehaviorVar::ConstructModdedDescriptor(const uin if (acReplacer.origHash && (pTmpGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(acReplacer.origHash))) { SeedAnimationVariables(acReplacer.origHash, pTmpGraph, acReverseMap, boolVar, floatVar, intVar); - spdlog::info(__FUNCTION__ ": Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", - acReplacer.origHash, boolVar.size(), floatVar.size(), intVar.size()); + spdlog::info( + __FUNCTION__ ": Original game descriptor with hash {} has {} boolean, {} float, {} integer behavior vars", + acReplacer.origHash, + boolVar.size(), + floatVar.size(), + intVar.size()); } // Check requested behavior vars for those that ARE legit @@ -247,8 +254,7 @@ const AnimationGraphDescriptor* BehaviorVar::ConstructModdedDescriptor(const uin } } if (foundCount) - spdlog::info("Now have {} boolVar descriptors after searching {} BehavivorVar strings", boolVar.size(), - acReplacer.syncBooleanVar.size()); + spdlog::info("Now have {} boolVar descriptors after searching {} BehavivorVar strings", boolVar.size(), acReplacer.syncBooleanVar.size()); foundCount = 0; for (auto& item : acReplacer.syncFloatVar) @@ -263,8 +269,7 @@ const AnimationGraphDescriptor* BehaviorVar::ConstructModdedDescriptor(const uin } } if (foundCount) - spdlog::info("Now have {} floatVar descriptors after searching {} BehavivorVar strings", floatVar.size(), - acReplacer.syncFloatVar.size()); + spdlog::info("Now have {} floatVar descriptors after searching {} BehavivorVar strings", floatVar.size(), acReplacer.syncFloatVar.size()); foundCount = 0; for (auto& item : acReplacer.syncIntegerVar) @@ -279,9 +284,7 @@ const AnimationGraphDescriptor* BehaviorVar::ConstructModdedDescriptor(const uin } } if (foundCount) - spdlog::info(__FUNCTION__ ": now have {} intVar descriptors after searching {} BehavivorVar strings", - intVar.size(), - acReplacer.syncIntegerVar.size()); + spdlog::info(__FUNCTION__ ": now have {} intVar descriptors after searching {} BehavivorVar strings", intVar.size(), acReplacer.syncIntegerVar.size()); // We need the sets sorted, and TiltedPhoques::Set is not. Copying to an std::set // isn't the most efficient approach, but it is simple and doesn't happen often enough @@ -306,15 +309,13 @@ const AnimationGraphDescriptor* BehaviorVar::ConstructModdedDescriptor(const uin // Add the new graph to the known behavior graphs // TODO: doesn't handle case of the acNewHash already existing. - // That has to be addressed before we can support just adding - // more pre-existing vars to sync. For now, only get here + // That has to be addressed before we can support just adding + // more pre-existing vars to sync. For now, only get here // when mods have changed the hash. new AnimationGraphDescriptorManager::Builder(AnimationGraphDescriptorManager::Get(), acNewHash, *panimGraphDescriptor); return AnimationGraphDescriptorManager::Get().GetDescriptor(acNewHash); } - - const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apManager, Actor* apActor) { // Serialize, Actors are multi-threaded. Might not be strictly necessary between being on @@ -334,7 +335,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa // Remote players are ALWAYS in 3rd person by definition if (hexFormID == 0x14 && PlayerCamera::Get()->IsFirstPerson()) { - hash = AnimationGraphDescriptor_Master_Behavior::m_key; + hash = AnimationGraphDescriptor_Master_Behavior::m_key; pGraph = AnimationGraphDescriptorManager::Get().GetDescriptor(hash); } #endif @@ -342,7 +343,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa // If we found the descriptor we're done. if (pGraph) return pGraph; - + // If BehaviorVar replacement fails, the hash is failListed for a period of time. // This handles a number of special cases for us. Many behaviors are not synced; the // game just ignores them and let's the multiple clients each handle it. @@ -359,17 +360,16 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa // Up to here the routine is pretty cheap, and WILL be called a bunch of times // if the only humanoid Actor is the Dragonborn/player in 1st person. - // With that case filtered out, keep a counter to see if we need to defend against other + // With that case filtered out, keep a counter to see if we need to defend against other // cases (like a modded behavior where we CAN't find the signature var). if (invocations++ == 100) spdlog::warn(__FUNCTION__ ": warning, more than 100 invocations, investigate why"); - - spdlog::info(__FUNCTION__ ": actor with formID {:x} with hash of {} has modded (or not synced) behavior", hexFormID, - hash); + + spdlog::info(__FUNCTION__ ": actor with formID {:x} with hash of {} has modded (or not synced) behavior", hexFormID, hash); // Get all animation variables for this actor, then create a acReverseMap to go from strings to animation enum. auto pDumpVar = apManager->DumpAnimationVariables(false); - TiltedPhoques::Map< TiltedPhoques::String, uint32_t> reverseMap; + TiltedPhoques::Map reverseMap; spdlog::info("Known behavior variables for formID {:x}:", hexFormID); for (auto& item : pDumpVar) { @@ -385,7 +385,7 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa // // That's enough info to create a unique signature in the base game descriptors. At least, // it was at the time of writing. - // + // // O(N) loop, but this typically only gets executed a few times (once for each modded // creature TYPE, not each modded creature). // @@ -394,13 +394,13 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa for (size_t i = 0; i < behaviorPool.size(); i++) { auto tokens = TokenizeBehaviorSig(behaviorPool[i].signatureVar); - auto found = tokens.size() > 0; + auto found = tokens.size() > 0; for (auto titer = tokens.begin(); found && titer < tokens.end(); titer++) { if (*titer == "!") found = reverseMap.find(*++titer) == reverseMap.end(); - else + else found = reverseMap.find(*titer) != reverseMap.end(); } if (found) @@ -409,29 +409,32 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa switch (matchedReplacers.size()) { - case 0: - spdlog::warn(__FUNCTION__ ": no original behavior found for behavior hash {:x} (found on formID {:x}), adding to " - "fail list", - hash, hexFormID); - FailList(hash); - return nullptr; - - case 1: - break; + case 0: + spdlog::warn( + __FUNCTION__ ": no original behavior found for behavior hash {:x} (found on formID {:x}), adding to fail list", + hash, + hexFormID); + FailList(hash); + return nullptr; - default: - spdlog::critical(__FUNCTION__ ": multiple behavior replacers have the same signature, this must be corrected:"); - for (auto& item : matchedReplacers) - spdlog::critical(" {}", behaviorPool[item].creatureName); - FailList(hash); - return nullptr; + case 1: break; + default: + spdlog::critical(__FUNCTION__ ": multiple behavior replacers have the same signature, this must be corrected:"); + for (auto& item : matchedReplacers) + spdlog::critical(" {}", behaviorPool[item].creatureName); + FailList(hash); + return nullptr; } auto& foundRep = behaviorPool[matchedReplacers[0]]; - spdlog::info(__FUNCTION__ ": found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", - hash, hexFormID, foundRep.creatureName, foundRep.signatureVar); - + spdlog::info( + __FUNCTION__ ": found match, behavior hash {:x} (found on formID {:x}) has original behavior {} signature {}", + hash, + hexFormID, + foundRep.creatureName, + foundRep.signatureVar); + // Save the new hash for the actor. Save a copy to restore to if overwritten; this currently // only happens when humanoids enter beast mode, Humanoid copy is used to change back. // We also save the original (unmodded) STR hash, because there are some hardwired tests @@ -450,7 +453,7 @@ bool BehaviorVar::FailListed(uint64_t hash) return iter != failedBehaviors.end() && std::chrono::steady_clock::now() < iter->second; } -//Place the behavior hash on the failed list +// Place the behavior hash on the failed list void BehaviorVar::FailList(uint64_t hash) { failedBehaviors.insert_or_assign(hash, std::chrono::steady_clock::now() + FAILLIST_DURATION); @@ -468,11 +471,11 @@ TiltedPhoques::Vector BehaviorVar::LoadDirs(const std::fi BehaviorVar::Replacer* BehaviorVar::LoadReplacerFromDir(const std::filesystem::path& aDir) { - // Enumerate all files in the directory and push bools, ints and floats + // Enumerate all files in the directory and push bools, ints and floats // to their respective vectors // The hashFile *__hash.txt file should contain the hashed signature of the ORIGINAL GAME - // actor. That enables us to look up the synced animation variables selected by + // actor. That enables us to look up the synced animation variables selected by // the STR devs and include them in the updated behavior/animation sync. Mod // devs don't have to know anything but what they've added, and this support for // Nemesis will work with more versions of the game. @@ -486,7 +489,7 @@ BehaviorVar::Replacer* BehaviorVar::LoadReplacerFromDir(const std::filesystem::p TiltedPhoques::Vector floatVarsFile; TiltedPhoques::Vector intVarsFile; TiltedPhoques::Vector boolVarsFile; - + for (auto& p : std::filesystem::directory_iterator(aDir)) { TiltedPhoques::String path(p.path().string()); @@ -544,27 +547,27 @@ BehaviorVar::Replacer* BehaviorVar::LoadReplacerFromDir(const std::filesystem::p // If signature file is unreadable, this directory is useless. std::ifstream fileSig(signatureFile.c_str(), std::ifstream::in); if (!fileSig.is_open()) - return nullptr; + return nullptr; - getline(fileSig, sigVar); // grab the signature variable + getline(fileSig, sigVar); // grab the signature variable fileSig.close(); erase_if(sigVar, isspace); // removes any inadvertent whitespace if (sigVar.size() == 0) return nullptr; spdlog::info(__FUNCTION__ ": found {} with signature variable {}", creatureName, sigVar); - // Check to see if there is a hash file. - // This is recommended, and shouild contain the ORIGINAL hash, + // Check to see if there is a hash file. + // This is recommended, and shouild contain the ORIGINAL hash, // before modding, of the behavior. It's not reasonable for a mod - // developer to have to "know" the complete set of variables the STR + // developer to have to "know" the complete set of variables the STR // devs have selected, so we'll want to get them from the original behaviors // via the original hash. If provided, we'll start with those vars and the // mod developer only lists the added ones they need. - // + // // The orginal version of this patch by Spvvd also included the "new" hash, // but that seems to be another thing a mod dev has no easy way to get their hands // on. So stripped off the need to provide the new hash, we'll just calculate it. - // + // uint64_t orgHash = 0; if (hashFile.size()) { @@ -575,7 +578,7 @@ BehaviorVar::Replacer* BehaviorVar::LoadReplacerFromDir(const std::filesystem::p file.close(); erase_if(tempString, isspace); // removes any inadvertant whitespace orgHash = std::strtoull(tempString.c_str(), nullptr, 10); - spdlog::info("Replacer specifies original hash {} for {}", orgHash, creatureName); + spdlog::info("Replacer specifies original hash {} for {}", orgHash, creatureName); } } @@ -634,11 +637,11 @@ BehaviorVar::Replacer* BehaviorVar::LoadReplacerFromDir(const std::filesystem::p // Create the replacer Replacer* result = new Replacer(); - result->origHash = orgHash; - result->signatureVar = sigVar; - result->creatureName = creatureName; + result->origHash = orgHash; + result->signatureVar = sigVar; + result->creatureName = creatureName; result->syncBooleanVar = boolVar; - result->syncFloatVar = floatVar; + result->syncFloatVar = floatVar; result->syncIntegerVar = intVar; return result; @@ -678,7 +681,7 @@ void BehaviorVar::Init() { // Initialize original (base STR) behaviors so we can search them. BehaviorOrig::BehaviorOrigInit(); - + // Check if the behaviors folder exists std::filesystem::path pBehaviorsPath; pBehaviorsPath = launcher::GetLaunchContext()->gamePath / L"Data" / L"SkyrimTogetherRebornBehaviors"; @@ -705,15 +708,13 @@ void BehaviorVar::Init() auto matches = SignatureMatches(signature.origHash, signature.signatureVar); switch (matches.size()) { - case 0: - spdlog::critical(__FUNCTION__ ": failure to find self in behaviorPool, {}", signature.creatureName); - case 1: - break; + case 0: spdlog::critical(__FUNCTION__ ": failure to find self in behaviorPool, {}", signature.creatureName); + case 1: break; default: if (firsttime++ == 0) spdlog::warn(__FUNCTION__ ": some creatures have ambiguous signatures. This is expected for now,\n" - " but a modder must create a unique signature in their mod."); + " but a modder must create a unique signature in their mod."); spdlog::warn(__FUNCTION__ ": {} signature {} matches:", signature.creatureName, signature.signatureVar); for (auto hash : matches) @@ -722,14 +723,11 @@ void BehaviorVar::Init() if (iter < behaviorPool.end()) spdlog::warn(" {}", std::find(behaviorPool.begin(), behaviorPool.end(), hash)->creatureName); else - spdlog::warn( - " {}: unable to find creature name for this hash, likely typo in SkyrimTogetherReborn tree", - hash); + spdlog::warn(" {}: unable to find creature name for this hash, likely typo in SkyrimTogetherReborn tree", hash); } break; } } - } void BehaviorVar::Debug() diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index 7caab8e35..e1bf0cc5a 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -14,10 +14,7 @@ struct BehaviorVar TiltedPhoques::Vector syncBooleanVar; TiltedPhoques::Vector syncFloatVar; TiltedPhoques::Vector syncIntegerVar; - bool operator==(const uint64_t& acRHS) const - { - return origHash == acRHS; - } + bool operator==(const uint64_t& acRHS) const { return origHash == acRHS; } }; static BehaviorVar* Get(); @@ -28,22 +25,22 @@ struct BehaviorVar void Init(); void Debug(); - private: +private: static BehaviorVar* single; uint64_t invocations = 0; void SeedAnimationVariables( - const uint64_t acHash, - const AnimationGraphDescriptor* acpDescriptor, - TiltedPhoques::Map& acReverseMap, - TiltedPhoques::Set& aBoolVars, - TiltedPhoques::Set& aFloatVars, + const uint64_t acHash, + const AnimationGraphDescriptor* acpDescriptor, + TiltedPhoques::Map& acReverseMap, + TiltedPhoques::Set& aBoolVars, + TiltedPhoques::Set& aFloatVars, TiltedPhoques::Set& aIntVars); const TiltedPhoques::Vector TokenizeBehaviorSig(const TiltedPhoques::String& acSignature) const; const AnimationGraphDescriptor* ConstructModdedDescriptor( - const uint64_t acNewHash, - const Replacer& acReplacer, + const uint64_t acNewHash, + const Replacer& acReplacer, TiltedPhoques::Map& acReverseMap); TiltedPhoques::Vector LoadDirs(const std::filesystem::path& acPath); @@ -56,5 +53,4 @@ struct BehaviorVar extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apManager, Actor* apActor); - #endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/ModCompat/BehaviorVarsMap.cpp b/Code/client/ModCompat/BehaviorVarsMap.cpp index 6a8f29ef7..bbaf8f017 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.cpp +++ b/Code/client/ModCompat/BehaviorVarsMap.cpp @@ -1,7 +1,6 @@ #ifdef MODDED_BEHAVIOR_COMPATIBILITY #include "BehaviorVarsMap.h" - const uint32_t BehaviorVarsMap::find(const uint64_t acBehaviorVarsKey, const TiltedPhoques::String acName) { auto map = m_map.find(acBehaviorVarsKey); @@ -20,7 +19,7 @@ const uint32_t BehaviorVarsMap::find(const uint64_t acBehaviorVarsKey, const Til const TiltedPhoques::String BehaviorVarsMap::find(const uint64_t acBehaviorVarsKey, const uint32_t acValue) { const TiltedPhoques::String empty; - + auto map = m_map.find(acBehaviorVarsKey); if (map != m_map.end()) { @@ -38,7 +37,6 @@ void BehaviorVarsMap::Register(const BehaviorVars aMap) m_map.insert_or_assign(aMap.m_key, aMap); } - BehaviorVarsMap& BehaviorVarsMap::getInstance() { // The only instance. Guaranteed lazy initiated diff --git a/Code/client/ModCompat/BehaviorVarsMap.h b/Code/client/ModCompat/BehaviorVarsMap.h index 0ff354bbf..cdf9615b7 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.h +++ b/Code/client/ModCompat/BehaviorVarsMap.h @@ -1,6 +1,5 @@ #pragma once - struct BehaviorVars { uint64_t m_key; @@ -8,19 +7,17 @@ struct BehaviorVars TiltedPhoques::Map m_valueMap; }; - - class BehaviorVarsMap { - private: +private: TiltedPhoques::Map m_map; // Singleton BehaviorVarsMap(){}; BehaviorVarsMap(BehaviorVarsMap const&) = delete; - void operator=(BehaviorVarsMap const&) = delete; + void operator=(BehaviorVarsMap const&) = delete; - public: +public: const uint32_t find(const uint64_t acBehaviorVarKey, const TiltedPhoques::String acName); const TiltedPhoques::String find(const uint64_t acBehaviorVarKey, const uint32_t acValue); @@ -38,5 +35,5 @@ class BehaviorVarsMap namespace BehaviorOrig { - extern void BehaviorOrigInit(); +extern void BehaviorOrigInit(); }; From 6570778681e2a6a164ff1f83c7312f5ac50305b7 Mon Sep 17 00:00:00 2001 From: rfortier Date: Sun, 27 Oct 2024 13:45:58 -0400 Subject: [PATCH 55/86] Removed MODDED_BEHAVIOR_COMPATIBILITY conditional compilation; support always compiled now. --- Code/client/Games/ActorExtension.h | 2 -- Code/client/Games/References.cpp | 6 ---- Code/client/Games/Skyrim/Actor.cpp | 2 -- Code/client/Games/Skyrim/PlayerCharacter.cpp | 4 +-- Code/client/ModCompat/BehaviorOrig.cpp | 4 --- Code/client/ModCompat/BehaviorVar.cpp | 3 -- Code/client/ModCompat/BehaviorVar.h | 3 -- Code/client/ModCompat/BehaviorVarsMap.cpp | 3 -- .../Services/Debug/Views/AnimDebugView.cpp | 6 +--- Code/client/World.cpp | 4 --- .../AnimationGraphDescriptorManager.cpp | 29 ------------------- .../Structs/AnimationGraphDescriptorManager.h | 2 -- xmake.lua | 3 -- 13 files changed, 2 insertions(+), 69 deletions(-) diff --git a/Code/client/Games/ActorExtension.h b/Code/client/Games/ActorExtension.h index f7bc8e11a..5c13652da 100644 --- a/Code/client/Games/ActorExtension.h +++ b/Code/client/Games/ActorExtension.h @@ -20,10 +20,8 @@ struct ActorExtension ActionEvent LatestAnimation{}; size_t GraphDescriptorHash = 0; -#ifdef MODDED_BEHAVIOR_COMPATIBILITY size_t UnmoddedGraphDescriptorHash = 0; // Hash before any mods change it. size_t HumanoidGraphDescriptorHash = 0; // Copy of hash before overwritten by beast form. -#endif MODDED_BEHAVIOR_COMPATIBILITY private: uint32_t onlineFlags{0}; diff --git a/Code/client/Games/References.cpp b/Code/client/Games/References.cpp index 3bbbf8a1c..2b1871bd3 100644 --- a/Code/client/Games/References.cpp +++ b/Code/client/Games/References.cpp @@ -50,9 +50,7 @@ #include #endif -#ifdef MODDED_BEHAVIOR_COMPATIBILITY extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* pManager, Actor* pActor); -#endif MODDED_BEHAVIOR_COMPATIBILITY using ScopedReferencesOverride = ScopedOverride; thread_local uint32_t ScopedReferencesOverride::s_refCount = 0; @@ -224,12 +222,10 @@ void TESObjectREFR::SaveAnimationVariables(AnimationVariables& aVariables) const auto pDescriptor = AnimationGraphDescriptorManager::Get().GetDescriptor(pExtendedActor->GraphDescriptorHash); -#ifdef MODDED_BEHAVIOR_COMPATIBILITY // Modded behavior check if descriptor wasn't found extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager * pManager, Actor * pActor); if (!pDescriptor) pDescriptor = BehaviorVarPatch(pManager, pActor); -#endif MODDED_BEHAVIOR_COMPATIBILITY if (!pDescriptor) return; @@ -350,11 +346,9 @@ void TESObjectREFR::LoadAnimationVariables(const AnimationVariables& aVariables) auto pDescriptor = AnimationGraphDescriptorManager::Get().GetDescriptor(pExtendedActor->GraphDescriptorHash); -#ifdef MODDED_BEHAVIOR_COMPATIBILITY // Modded behavior check if descriptor wasn't found if (!pDescriptor) pDescriptor = BehaviorVarPatch(pManager, pActor); -#endif MODDED_BEHAVIOR_COMPATIBILITY if (!pDescriptor) return; diff --git a/Code/client/Games/Skyrim/Actor.cpp b/Code/client/Games/Skyrim/Actor.cpp index eb54d5388..0086d724d 100644 --- a/Code/client/Games/Skyrim/Actor.cpp +++ b/Code/client/Games/Skyrim/Actor.cpp @@ -542,7 +542,6 @@ bool Actor::IsDead() const noexcept bool Actor::IsDragon() const noexcept { -#ifdef MODDED_BEHAVIOR_COMPATIBILITY const ActorExtension* pExtension = const_cast(this)->GetExtension(); auto hash = pExtension->UnmoddedGraphDescriptorHash; @@ -551,7 +550,6 @@ bool Actor::IsDragon() const noexcept // Still want to continue with the original code, because if Nemesis/Pandora // isn't on the client at all, BehaviorVar::Patch doesn't run on the Dragons. -#endif MODDED_BEHAVIOR_COMPATIBILITY // TODO: if anyone has a better way of doing this, please do tell. BSAnimationGraphManager* pManager = nullptr; diff --git a/Code/client/Games/Skyrim/PlayerCharacter.cpp b/Code/client/Games/Skyrim/PlayerCharacter.cpp index ab0af8320..cd60171f3 100644 --- a/Code/client/Games/Skyrim/PlayerCharacter.cpp +++ b/Code/client/Games/Skyrim/PlayerCharacter.cpp @@ -163,12 +163,10 @@ void TP_MAKE_THISCALL(HookSetBeastForm, void, void* apUnk1, void* apUnk2, bool a if (!aEntering) { PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = AnimationGraphDescriptor_Master_Behavior::m_key; -#ifdef MODDED_BEHAVIOR_COMPATIBILITY - // Restore instead to saved, modified behavior hash. IF Nemesis/Pandora is installed, otherwise BehaviorVar::Patch() doesn't run. + // Restore to saved, modified behavior hash, IFF Nemesis/Pandora is installed, otherwise BehaviorVar::Patch() doesn't run. auto hash = PlayerCharacter::Get()->GetExtension()->HumanoidGraphDescriptorHash; if (hash) PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = hash; -#endif MODDED_BEHAVIOR_COMPATIBILITY World::Get().GetRunner().Trigger(BeastFormChangeEvent()); } diff --git a/Code/client/ModCompat/BehaviorOrig.cpp b/Code/client/ModCompat/BehaviorOrig.cpp index e58d6e367..ac0457cb8 100644 --- a/Code/client/ModCompat/BehaviorOrig.cpp +++ b/Code/client/ModCompat/BehaviorOrig.cpp @@ -1,5 +1,3 @@ -#ifdef MODDED_BEHAVIOR_COMPATIBILITY - #include "BehaviorVarsMap.h" #define MAGIC_ENUM_RANGE_MAX 400 #include "magic_enum.hpp" @@ -37,5 +35,3 @@ template void GenerateFromEnum(uint64_t aKey) #endif } // namespace BehaviorOrig - -#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index e35372a63..841784189 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -26,7 +26,6 @@ // 4) Finally, that will push us over some hard-coded limits, in particular // a limit of 64 boolean vars that can be synced. Remove the limit. // -#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include #include @@ -767,5 +766,3 @@ void BehaviorVar::Debug() } } } - -#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index e1bf0cc5a..527799942 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -1,5 +1,4 @@ #pragma once -#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include @@ -52,5 +51,3 @@ struct BehaviorVar }; extern const AnimationGraphDescriptor* BehaviorVarPatch(BSAnimationGraphManager* apManager, Actor* apActor); - -#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/ModCompat/BehaviorVarsMap.cpp b/Code/client/ModCompat/BehaviorVarsMap.cpp index bbaf8f017..1d2b63305 100644 --- a/Code/client/ModCompat/BehaviorVarsMap.cpp +++ b/Code/client/ModCompat/BehaviorVarsMap.cpp @@ -1,4 +1,3 @@ -#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include "BehaviorVarsMap.h" const uint32_t BehaviorVarsMap::find(const uint64_t acBehaviorVarsKey, const TiltedPhoques::String acName) @@ -45,5 +44,3 @@ BehaviorVarsMap& BehaviorVarsMap::getInstance() return instance; } - -#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/client/Services/Debug/Views/AnimDebugView.cpp b/Code/client/Services/Debug/Views/AnimDebugView.cpp index 04315c16b..542921b87 100644 --- a/Code/client/Services/Debug/Views/AnimDebugView.cpp +++ b/Code/client/Services/Debug/Views/AnimDebugView.cpp @@ -25,9 +25,7 @@ #include #include -#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include -#endif MODDED_BEHAVIOR_COMPATIBILITY uint64_t DisplayGraphDescriptorKey(BSAnimationGraphManager* pManager) noexcept { @@ -87,10 +85,8 @@ void DebugService::DrawAnimDebugView() if (ImGui::Button("Show cached hash")) { spdlog::info("{}", pActor->GetExtension()->GraphDescriptorHash); -#ifdef MODDED_BEHAVIOR_COMPATIBILITY BehaviorVar::Get()->Debug(); -#endif MODDED_BEHAVIOR_COMPATIBILITY - } + } if (ImGui::Button("Clear all")) { diff --git a/Code/client/World.cpp b/Code/client/World.cpp index b9f70f77a..b0596604b 100644 --- a/Code/client/World.cpp +++ b/Code/client/World.cpp @@ -25,9 +25,7 @@ #include #include -#ifdef MODDED_BEHAVIOR_COMPATIBILITY #include -#endif MODDED_BEHAVIOR_COMPATIBILITY World::World() : m_runner(m_dispatcher) @@ -57,9 +55,7 @@ World::World() ctx().emplace(*this, m_transport, m_dispatcher); ctx().emplace(*this, m_dispatcher, m_transport); -#ifdef MODDED_BEHAVIOR_COMPATIBILITY BehaviorVar::Get()->Init(); -#endif MODDED_BEHAVIOR_COMPATIBILITY } World::~World() = default; diff --git a/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp b/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp index d6b2a564f..96c5f181d 100644 --- a/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp +++ b/Code/encoding/Structs/AnimationGraphDescriptorManager.cpp @@ -29,38 +29,9 @@ void AnimationGraphDescriptorManager::Register(uint64_t aKey, AnimationGraphDesc m_descriptors[aKey] = std::move(aAnimationGraphDescriptor); } -#ifdef MODDED_BEHAVIOR_COMPATIBILITY const TiltedPhoques::Map& AnimationGraphDescriptorManager::GetDescriptors() const noexcept { return m_descriptors; } -#ifdef MODDED_BEHAVIOR_KEEP_UNUSED -void AnimationGraphDescriptorManager::UpdateKey(uint64_t aKey, uint64_t newKey) noexcept -{ - auto it = m_descriptors.find(aKey); - if (it != m_descriptors.end()) - { - m_descriptors[newKey] = it->second; - m_descriptors.erase(it); - } -} - -void AnimationGraphDescriptorManager::Update(uint64_t aKey, uint64_t newKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept -{ - const auto it = m_descriptors.find(aKey); - if (it != std::end(m_descriptors)) - { - m_descriptors.insert_or_assign(newKey, aAnimationGraphDescriptor); - m_descriptors.erase(it); - } -} - -void AnimationGraphDescriptorManager::ReRegister(uint64_t aKey, - AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept -{ - m_descriptors[aKey] = std::move(aAnimationGraphDescriptor); -} -#endif MODDED_BEHAVIOR_KEEP_UNUSED -#endif MODDED_BEHAVIOR_COMPATIBILITY diff --git a/Code/encoding/Structs/AnimationGraphDescriptorManager.h b/Code/encoding/Structs/AnimationGraphDescriptorManager.h index 8285308b1..5fd8cddf6 100644 --- a/Code/encoding/Structs/AnimationGraphDescriptorManager.h +++ b/Code/encoding/Structs/AnimationGraphDescriptorManager.h @@ -9,11 +9,9 @@ struct AnimationGraphDescriptorManager static AnimationGraphDescriptorManager& Get() noexcept; const AnimationGraphDescriptor* GetDescriptor(uint64_t aKey) const noexcept; -#ifdef MODDED_BEHAVIOR_COMPATIBILITY const TiltedPhoques::Map& GetDescriptors() const noexcept; void UpdateKey(uint64_t aKey, uint64_t newKey) noexcept; void Update(uint64_t aKey, uint64_t newKey, AnimationGraphDescriptor aAnimationGraphDescriptor) noexcept; -#endif MODDED_BEHAVIOR_COMPATIBILITY struct Builder { diff --git a/xmake.lua b/xmake.lua index 3b1739ada..c0378f318 100644 --- a/xmake.lua +++ b/xmake.lua @@ -30,9 +30,6 @@ if has_config("unitybuild") then add_rules("c++.unity_build", {batchsize = 12}) end --- Single-commit enable MODDED_BEHAVIOR_COMPATIBILITY -add_defines("MODDED_BEHAVIOR_COMPATIBILITY") - -- direct dependencies version pinning add_requires( "entt v3.10.0", From 479ca9fd12db7faadd14419be6b6cca2280131ea Mon Sep 17 00:00:00 2001 From: rfortier Date: Mon, 28 Oct 2024 13:58:33 -0400 Subject: [PATCH 56/86] Simplify (and correct) tracking of modified Master behavior. New to remember the modified MasterBehavior hash, since it is used to return from Beast mode. Previous implementation stored in ActorExtension, but would only get set on the first modified humanoid which might not be the PlayerCharacter. Similar issue for dragons, remember the modified hash so Actor::IsDragon() test will work for all modded dragons, not just the first one. --- Code/client/Games/ActorExtension.h | 2 -- Code/client/Games/Skyrim/Actor.cpp | 23 +++-------------- Code/client/Games/Skyrim/PlayerCharacter.cpp | 9 +++---- Code/client/ModCompat/BehaviorVar.cpp | 26 +++++++++++++------- Code/client/ModCompat/BehaviorVar.h | 10 ++++++++ 5 files changed, 33 insertions(+), 37 deletions(-) diff --git a/Code/client/Games/ActorExtension.h b/Code/client/Games/ActorExtension.h index 5c13652da..485dbaa00 100644 --- a/Code/client/Games/ActorExtension.h +++ b/Code/client/Games/ActorExtension.h @@ -20,8 +20,6 @@ struct ActorExtension ActionEvent LatestAnimation{}; size_t GraphDescriptorHash = 0; - size_t UnmoddedGraphDescriptorHash = 0; // Hash before any mods change it. - size_t HumanoidGraphDescriptorHash = 0; // Copy of hash before overwritten by beast form. private: uint32_t onlineFlags{0}; diff --git a/Code/client/Games/Skyrim/Actor.cpp b/Code/client/Games/Skyrim/Actor.cpp index 0086d724d..a1dd82baf 100644 --- a/Code/client/Games/Skyrim/Actor.cpp +++ b/Code/client/Games/Skyrim/Actor.cpp @@ -49,6 +49,8 @@ #include #include +#include + #ifdef SAVE_STUFF #include @@ -543,26 +545,7 @@ bool Actor::IsDead() const noexcept bool Actor::IsDragon() const noexcept { const ActorExtension* pExtension = const_cast(this)->GetExtension(); - auto hash = pExtension->UnmoddedGraphDescriptorHash; - - if (hash) - return AnimationGraphDescriptor_BHR_Master::m_key == hash; - - // Still want to continue with the original code, because if Nemesis/Pandora - // isn't on the client at all, BehaviorVar::Patch doesn't run on the Dragons. - - // TODO: if anyone has a better way of doing this, please do tell. - BSAnimationGraphManager* pManager = nullptr; - animationGraphHolder.GetBSAnimationGraph(&pManager); - - if (!pManager) - return false; - - const auto* pGraph = pManager->animationGraphs.Get(pManager->animationGraphIndex); - if (!pGraph) - return false; - - return AnimationGraphDescriptor_BHR_Master::m_key == pManager->GetDescriptorKey(); + return BehaviorVar::IsDragon(pExtension->GraphDescriptorHash); } void Actor::Kill() noexcept diff --git a/Code/client/Games/Skyrim/PlayerCharacter.cpp b/Code/client/Games/Skyrim/PlayerCharacter.cpp index cd60171f3..ebb501571 100644 --- a/Code/client/Games/Skyrim/PlayerCharacter.cpp +++ b/Code/client/Games/Skyrim/PlayerCharacter.cpp @@ -22,6 +22,8 @@ #include +#include + int32_t PlayerCharacter::LastUsedCombatSkill = -1; TP_THIS_FUNCTION(TPickUpObject, char, PlayerCharacter, TESObjectREFR* apObject, int32_t aCount, bool aUnk1, bool aUnk2); @@ -162,12 +164,7 @@ void TP_MAKE_THISCALL(HookSetBeastForm, void, void* apUnk1, void* apUnk2, bool a { if (!aEntering) { - PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = AnimationGraphDescriptor_Master_Behavior::m_key; - // Restore to saved, modified behavior hash, IFF Nemesis/Pandora is installed, otherwise BehaviorVar::Patch() doesn't run. - auto hash = PlayerCharacter::Get()->GetExtension()->HumanoidGraphDescriptorHash; - if (hash) - PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = hash; - + PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = BehaviorVar::GetHumanoidHash(); World::Get().GetRunner().Trigger(BeastFormChangeEvent()); } diff --git a/Code/client/ModCompat/BehaviorVar.cpp b/Code/client/ModCompat/BehaviorVar.cpp index 841784189..cd007c738 100644 --- a/Code/client/ModCompat/BehaviorVar.cpp +++ b/Code/client/ModCompat/BehaviorVar.cpp @@ -34,7 +34,6 @@ #include "BehaviorVarsMap.h" #if TP_SKYRIM64 -#include #include // Camera 1st person is only in Skyrim? #include #endif @@ -361,8 +360,8 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa // if the only humanoid Actor is the Dragonborn/player in 1st person. // With that case filtered out, keep a counter to see if we need to defend against other // cases (like a modded behavior where we CAN't find the signature var). - if (invocations++ == 100) - spdlog::warn(__FUNCTION__ ": warning, more than 100 invocations, investigate why"); + if (invocations++ == 1000) + spdlog::warn(__FUNCTION__ ": warning, more than 1000 invocations, investigate why"); spdlog::info(__FUNCTION__ ": actor with formID {:x} with hash of {} has modded (or not synced) behavior", hexFormID, hash); @@ -434,13 +433,22 @@ const AnimationGraphDescriptor* BehaviorVar::Patch(BSAnimationGraphManager* apMa foundRep.creatureName, foundRep.signatureVar); - // Save the new hash for the actor. Save a copy to restore to if overwritten; this currently - // only happens when humanoids enter beast mode, Humanoid copy is used to change back. - // We also save the original (unmodded) STR hash, because there are some hardwired tests - // that need it (like the IsDragon() test). + // Save the new hash for the actor. Save copies of the new hash when humanoids (Master_Behavior) + // or dragons (BHR_Master) are modified. The humanoid hash is used to return from beast mode + // (werewolf or vampire), and the dragon hash is used to implement an IsDragon() primitive. pExtendedActor->GraphDescriptorHash = hash; - pExtendedActor->HumanoidGraphDescriptorHash = hash; - pExtendedActor->UnmoddedGraphDescriptorHash = foundRep.origHash; + switch (foundRep.origHash) + { + case AnimationGraphDescriptor_Master_Behavior::m_key: + m_humanoidGraphDescriptorHash = hash; + spdlog::info(__FUNCTION__ ": captured modified Master_Behavior hash {:X}", hash); + break; + + case AnimationGraphDescriptor_BHR_Master::m_key: + m_dragonGraphDescriptorHash = hash; + spdlog::info(__FUNCTION__ ": captured modified BHR_Master (dragon) hash {:X}", hash); + break; + } return ConstructModdedDescriptor(hash, foundRep, reverseMap); } diff --git a/Code/client/ModCompat/BehaviorVar.h b/Code/client/ModCompat/BehaviorVar.h index 527799942..a70e0a3e8 100644 --- a/Code/client/ModCompat/BehaviorVar.h +++ b/Code/client/ModCompat/BehaviorVar.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include struct BehaviorVar { @@ -20,6 +22,8 @@ struct BehaviorVar const AnimationGraphDescriptor* Patch(BSAnimationGraphManager* apManager, Actor* apActor); bool FailListed(const uint64_t acHash); void FailList(const uint64_t acHash); + static const bool IsDragon(const uint64_t acHash) { return acHash == Get()->m_dragonGraphDescriptorHash; } + static const uint64_t GetHumanoidHash() { return Get()->m_humanoidGraphDescriptorHash; } void Init(); void Debug(); @@ -28,6 +32,12 @@ struct BehaviorVar static BehaviorVar* single; uint64_t invocations = 0; + // These start out with the unmodded hashes and save the modded + // hash if behavior is modified. Humanoid is used to return from + // beast mode, and dragon is used for IsDragon() test. + uint64_t m_humanoidGraphDescriptorHash {AnimationGraphDescriptor_Master_Behavior::m_key}; + uint64_t m_dragonGraphDescriptorHash {AnimationGraphDescriptor_BHR_Master::m_key}; + void SeedAnimationVariables( const uint64_t acHash, const AnimationGraphDescriptor* acpDescriptor, From 3e4fd7d13e58aaa94dd0517232266f346b3dbc45 Mon Sep 17 00:00:00 2001 From: Robbe Bryssinck Date: Sat, 2 Nov 2024 11:40:12 +0100 Subject: [PATCH 57/86] tweak: removed TP_SKYRIM from client --- Code/client/Events/ActivateEvent.h | 20 - Code/client/FalloutVM.cpp | 63 - Code/client/Games/Animation.cpp | 6 - Code/client/Games/Fallout4/AI/AIProcess.h | 13 - Code/client/Games/Fallout4/Actor.cpp | 465 -- Code/client/Games/Fallout4/Actor.h | 200 - .../Games/Fallout4/BSAnimationGraphManager.h | 34 - Code/client/Games/Fallout4/BSCore/BSCRC16.cpp | 22 - Code/client/Games/Fallout4/BSCore/BSCRC16.h | 9 - Code/client/Games/Fallout4/BSCore/BSCRC32.cpp | 19 - Code/client/Games/Fallout4/BSCore/BSCRC32.h | 9 - .../client/Games/Fallout4/BSCore/BSTHashMap.h | 26 - .../Games/Fallout4/BSCore/BSTScatterTable.h | 919 --- Code/client/Games/Fallout4/BSFixedString.cpp | 51 - .../BSGraphics/BSGraphicsRenderer.cpp | 94 - .../Fallout4/BSGraphics/BSGraphicsRenderer.h | 142 - .../Fallout4/BSInput/BSInputDeviceManager.cpp | 43 - .../Components/BGSAttachParentArray.h | 12 - .../Fallout4/Components/BGSAttackDataForm.h | 15 - .../Fallout4/Components/BGSCharacterTint.h | 19 - .../Components/BGSDestructibleObjectForm.h | 12 - .../Fallout4/Components/BGSForcedLocRefType.h | 12 - .../Fallout4/Components/BGSKeywordForm.h | 15 - .../Components/BGSModelMaterialSwap.h | 12 - .../Components/BGSNativeTerminalForm.h | 10 - .../Components/BGSOverridePackCollection.h | 10 - .../Fallout4/Components/BGSPerkRankArray.h | 14 - .../Fallout4/Components/BGSPropertySheet.h | 10 - .../Games/Fallout4/Components/BGSSkinForm.h | 12 - .../Fallout4/Components/BaseFormComponent.h | 13 - .../Games/Fallout4/Components/TESAIForm.h | 10 - .../Fallout4/Components/TESActorBaseData.h | 46 - .../Games/Fallout4/Components/TESContainer.h | 20 - .../Games/Fallout4/Components/TESFullName.h | 14 - .../Fallout4/Components/TESLeveledList.h | 38 - .../Games/Fallout4/Components/TESModel.h | 20 - .../Games/Fallout4/Components/TESRaceForm.h | 12 - .../Fallout4/Components/TESSpellList.cpp | 12 - .../Games/Fallout4/Components/TESSpellList.h | 23 - .../Games/Fallout4/DefaultObjectManager.cpp | 8 - .../Games/Fallout4/DefaultObjectManager.h | 6 - .../Games/Fallout4/Effects/ActiveEffect.h | 35 - .../Fallout4/Effects/ValueModifierEffect.h | 24 - Code/client/Games/Fallout4/EquipManager.cpp | 133 - Code/client/Games/Fallout4/EquipManager.h | 15 - Code/client/Games/Fallout4/Events.h | 25 - .../Games/Fallout4/Events/EventDispacther.cpp | 36 - .../Games/Fallout4/Events/EventDispatcher.h | 94 - .../Games/Fallout4/ExtraData/ExtraData.h | 30 - .../Fallout4/ExtraData/ExtraDataList.cpp | 91 - .../Games/Fallout4/ExtraData/ExtraDataList.h | 29 - .../Fallout4/ExtraData/ExtraFactionChanges.h | 22 - .../Fallout4/ExtraData/ExtraLeveledCreature.h | 15 - .../Games/Fallout4/ExtraData/ExtraSoul.h | 23 - Code/client/Games/Fallout4/FormManager.cpp | 9 - Code/client/Games/Fallout4/FormManager.h | 15 - .../Games/Fallout4/Forms/ActorValueInfo.cpp | 11 - .../Games/Fallout4/Forms/ActorValueInfo.h | 152 - Code/client/Games/Fallout4/Forms/BGSAction.h | 8 - .../Games/Fallout4/Forms/BGSColorForm.h | 8 - .../client/Games/Fallout4/Forms/BGSHeadPart.h | 6 - .../Games/Fallout4/Forms/BGSInventoryItem.h | 58 - .../Games/Fallout4/Forms/BGSInventoryList.h | 22 - Code/client/Games/Fallout4/Forms/BGSKeyword.h | 11 - Code/client/Games/Fallout4/Forms/BGSNote.h | 10 - .../Fallout4/Forms/BGSObjectInstance.cpp | 8 - .../Games/Fallout4/Forms/BGSObjectInstance.h | 13 - Code/client/Games/Fallout4/Forms/BGSOutfit.h | 8 - .../Fallout4/Forms/BGSStoryManagerTree.h | 8 - .../Games/Fallout4/Forms/BGSTextureSet.h | 8 - .../Games/Fallout4/Forms/BGSVoiceType.h | 8 - Code/client/Games/Fallout4/Forms/SpellItem.h | 21 - .../Games/Fallout4/Forms/TESActorBase.h | 48 - Code/client/Games/Fallout4/Forms/TESAmmo.h | 7 - .../Games/Fallout4/Forms/TESBoundAnimObject.h | 7 - .../Games/Fallout4/Forms/TESBoundObject.h | 28 - Code/client/Games/Fallout4/Forms/TESClass.h | 8 - .../Games/Fallout4/Forms/TESCombatStyle.h | 8 - Code/client/Games/Fallout4/Forms/TESFaction.h | 8 - Code/client/Games/Fallout4/Forms/TESForm.h | 127 - Code/client/Games/Fallout4/Forms/TESGlobal.h | 18 - .../client/Games/Fallout4/Forms/TESIdleForm.h | 7 - .../Games/Fallout4/Forms/TESLevCharacter.h | 16 - Code/client/Games/Fallout4/Forms/TESNPC.cpp | 23 - Code/client/Games/Fallout4/Forms/TESNPC.h | 98 - Code/client/Games/Fallout4/Forms/TESObject.h | 19 - .../Games/Fallout4/Forms/TESObjectARMO.h | 45 - .../Games/Fallout4/Forms/TESObjectBOOK.h | 8 - .../Games/Fallout4/Forms/TESObjectCELL.cpp | 24 - .../Games/Fallout4/Forms/TESObjectCELL.h | 28 - .../Games/Fallout4/Forms/TESObjectMISC.h | 8 - .../Games/Fallout4/Forms/TESObjectWEAP.h | 7 - Code/client/Games/Fallout4/Forms/TESPackage.h | 7 - Code/client/Games/Fallout4/Forms/TESQuest.cpp | 50 - Code/client/Games/Fallout4/Forms/TESQuest.h | 92 - Code/client/Games/Fallout4/Forms/TESRace.h | 11 - .../Games/Fallout4/Forms/TESTopicInfo.cpp | 0 .../Games/Fallout4/Forms/TESTopicInfo.h | 12 - .../Games/Fallout4/Forms/TESValueForm.h | 6 - Code/client/Games/Fallout4/Forms/TESWeather.h | 5 - .../Games/Fallout4/Forms/TESWeightForm.h | 6 - .../Games/Fallout4/Forms/TESWorldSpace.h | 14 - Code/client/Games/Fallout4/Havok.h | 9 - .../Fallout4/Havok/BShkbAnimationGraph.h | 14 - Code/client/Games/Fallout4/Havok/BShkbHkxDB.h | 13 - .../client/Games/Fallout4/Havok/hkHashTable.h | 27 - .../Games/Fallout4/Havok/hkbBehaviorGraph.h | 15 - .../Games/Fallout4/Havok/hkbStateMachine.h | 11 - .../Fallout4/Havok/hkbVariableValueSet.h | 14 - .../client/Games/Fallout4/Interface/IMenu.cpp | 0 Code/client/Games/Fallout4/Interface/IMenu.h | 128 - Code/client/Games/Fallout4/Interface/UI.cpp | 329 - Code/client/Games/Fallout4/Interface/UI.h | 32 - Code/client/Games/Fallout4/LoadingScreen.cpp | 44 - Code/client/Games/Fallout4/LoadingScreen.h | 1 - .../Games/Fallout4/Magic/ActorMagicCaster.h | 13 - Code/client/Games/Fallout4/Magic/EffectItem.h | 18 - .../Games/Fallout4/Magic/EffectSetting.h | 13 - .../client/Games/Fallout4/Magic/MagicCaster.h | 31 - Code/client/Games/Fallout4/Magic/MagicItem.h | 23 - .../Games/Fallout4/Magic/MagicTarget.cpp | 119 - .../client/Games/Fallout4/Magic/MagicTarget.h | 56 - Code/client/Games/Fallout4/Misc/ActorState.h | 18 - .../Games/Fallout4/Misc/ActorValueOwner.h | 27 - .../Games/Fallout4/Misc/BSFixedString.h | 54 - Code/client/Games/Fallout4/Misc/BSScript.cpp | 70 - Code/client/Games/Fallout4/Misc/BSScript.h | 105 - Code/client/Games/Fallout4/Misc/BSString.h | 19 - Code/client/Games/Fallout4/Misc/GameVM.cpp | 10 - Code/client/Games/Fallout4/Misc/GameVM.h | 13 - .../Games/Fallout4/Misc/MiddleProcess.h | 14 - .../Games/Fallout4/Misc/NEW_REFR_DATA.cpp | 17 - .../Games/Fallout4/Misc/NEW_REFR_DATA.h | 28 - .../Games/Fallout4/Misc/NativeFunction.h | 18 - .../Games/Fallout4/Misc/TBO_InstanceData.h | 6 - Code/client/Games/Fallout4/Misc/TintMask.h | 1 - .../Games/Fallout4/Misc/WeatherManager.cpp | 10 - .../Games/Fallout4/Misc/WeatherManager.h | 8 - .../client/Games/Fallout4/PlayerCharacter.cpp | 61 - Code/client/Games/Fallout4/PlayerCharacter.h | 41 - .../Games/Fallout4/Projectiles/Projectile.cpp | 100 - .../Games/Fallout4/Projectiles/Projectile.h | 63 - Code/client/Games/Fallout4/RTTI.cpp | 6487 ---------------- Code/client/Games/Fallout4/RTTI.h | 6491 ----------------- Code/client/Games/Fallout4/Renderer.h | 52 - Code/client/Games/Fallout4/SaveLoad.h | 67 - Code/client/Games/Fallout4/Sky/Sky.h | 25 - Code/client/Games/Fallout4/TESObjectREFR.cpp | 188 - Code/client/Games/Fallout4/TESObjectREFR.h | 240 - Code/client/Games/Fallout4/TimeManager.h | 19 - Code/client/Games/Forms.cpp | 10 - Code/client/Games/Misc/BSScript.cpp | 19 - Code/client/Games/Misc/MenuTopicManager.cpp | 10 - Code/client/Games/Misc/SubtitleManager.cpp | 25 - Code/client/Games/References.cpp | 185 - Code/client/Games/Renderer.cpp | 33 - .../Games/Skyrim/Combat/CombatController.cpp | 4 - .../Games/Skyrim/ExtraData/ExtraDataList.cpp | 4 - .../Games/Skyrim/ExtraData/ExtraDataList.h | 9 - Code/client/Games/TES.h | 66 - Code/client/ScriptExtender.cpp | 20 +- Code/client/Services/Debug/DebugService.cpp | 14 - .../Services/Debug/Views/ActorValuesView.cpp | 3 - .../Services/Debug/Views/AnimDebugView.cpp | 2 - Code/client/Services/Debug/Views/CellView.cpp | 6 - .../Services/Debug/Views/CombatView.cpp | 4 - .../Services/Debug/Views/ComponentView.cpp | 14 - .../Debug/Views/ContainerDebugView.cpp | 103 - .../Debug/Views/DragonSpawnerView.cpp | 2 - .../Services/Debug/Views/EntitiesView.cpp | 2 - .../Services/Debug/Views/PlayerDebugView.cpp | 7 - .../Services/Debug/Views/QuestDebugView.cpp | 3 - .../client/Services/Debug/Views/SkillView.cpp | 3 - .../Services/Generic/ActorValueService.cpp | 4 - .../Services/Generic/CharacterService.cpp | 23 - .../client/Services/Generic/CombatService.cpp | 31 - .../Services/Generic/DiscordService.cpp | 4 - .../Services/Generic/DiscoveryService.cpp | 14 - Code/client/Services/Generic/InputService.cpp | 43 - .../Services/Generic/InventoryService.cpp | 18 - Code/client/Services/Generic/MagicService.cpp | 27 - Code/client/Services/Generic/MapService.cpp | 4 - .../client/Services/Generic/ObjectService.cpp | 32 - .../Services/Generic/OverlayService.cpp | 7 - Code/client/Services/Generic/PartyService.cpp | 4 - .../client/Services/Generic/PlayerService.cpp | 33 - Code/client/SkyrimVM64.cpp | 3 - Code/client/Systems/FaceGenSystem.cpp | 20 - Code/client/TiltedOnlinePCH.h | 16 - Code/client/Utils.cpp | 9 - Code/client/Utils.h | 13 - Code/client/main.cpp | 14 - Code/client/xmake.lua | 30 +- Code/immersive_launcher/xmake.lua | 11 - Code/server/Pch.h | 8 - Code/server/Services/ServerListService.cpp | 4 - 196 files changed, 12 insertions(+), 20281 deletions(-) delete mode 100644 Code/client/FalloutVM.cpp delete mode 100644 Code/client/Games/Fallout4/AI/AIProcess.h delete mode 100644 Code/client/Games/Fallout4/Actor.cpp delete mode 100644 Code/client/Games/Fallout4/Actor.h delete mode 100644 Code/client/Games/Fallout4/BSAnimationGraphManager.h delete mode 100644 Code/client/Games/Fallout4/BSCore/BSCRC16.cpp delete mode 100644 Code/client/Games/Fallout4/BSCore/BSCRC16.h delete mode 100644 Code/client/Games/Fallout4/BSCore/BSCRC32.cpp delete mode 100644 Code/client/Games/Fallout4/BSCore/BSCRC32.h delete mode 100644 Code/client/Games/Fallout4/BSCore/BSTHashMap.h delete mode 100644 Code/client/Games/Fallout4/BSCore/BSTScatterTable.h delete mode 100644 Code/client/Games/Fallout4/BSFixedString.cpp delete mode 100644 Code/client/Games/Fallout4/BSGraphics/BSGraphicsRenderer.cpp delete mode 100644 Code/client/Games/Fallout4/BSGraphics/BSGraphicsRenderer.h delete mode 100644 Code/client/Games/Fallout4/BSInput/BSInputDeviceManager.cpp delete mode 100644 Code/client/Games/Fallout4/Components/BGSAttachParentArray.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSAttackDataForm.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSCharacterTint.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSDestructibleObjectForm.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSForcedLocRefType.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSKeywordForm.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSModelMaterialSwap.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSNativeTerminalForm.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSOverridePackCollection.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSPerkRankArray.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSPropertySheet.h delete mode 100644 Code/client/Games/Fallout4/Components/BGSSkinForm.h delete mode 100644 Code/client/Games/Fallout4/Components/BaseFormComponent.h delete mode 100644 Code/client/Games/Fallout4/Components/TESAIForm.h delete mode 100644 Code/client/Games/Fallout4/Components/TESActorBaseData.h delete mode 100644 Code/client/Games/Fallout4/Components/TESContainer.h delete mode 100644 Code/client/Games/Fallout4/Components/TESFullName.h delete mode 100644 Code/client/Games/Fallout4/Components/TESLeveledList.h delete mode 100644 Code/client/Games/Fallout4/Components/TESModel.h delete mode 100644 Code/client/Games/Fallout4/Components/TESRaceForm.h delete mode 100644 Code/client/Games/Fallout4/Components/TESSpellList.cpp delete mode 100644 Code/client/Games/Fallout4/Components/TESSpellList.h delete mode 100644 Code/client/Games/Fallout4/DefaultObjectManager.cpp delete mode 100644 Code/client/Games/Fallout4/DefaultObjectManager.h delete mode 100644 Code/client/Games/Fallout4/Effects/ActiveEffect.h delete mode 100644 Code/client/Games/Fallout4/Effects/ValueModifierEffect.h delete mode 100644 Code/client/Games/Fallout4/EquipManager.cpp delete mode 100644 Code/client/Games/Fallout4/EquipManager.h delete mode 100644 Code/client/Games/Fallout4/Events.h delete mode 100644 Code/client/Games/Fallout4/Events/EventDispacther.cpp delete mode 100644 Code/client/Games/Fallout4/Events/EventDispatcher.h delete mode 100644 Code/client/Games/Fallout4/ExtraData/ExtraData.h delete mode 100644 Code/client/Games/Fallout4/ExtraData/ExtraDataList.cpp delete mode 100644 Code/client/Games/Fallout4/ExtraData/ExtraDataList.h delete mode 100644 Code/client/Games/Fallout4/ExtraData/ExtraFactionChanges.h delete mode 100644 Code/client/Games/Fallout4/ExtraData/ExtraLeveledCreature.h delete mode 100644 Code/client/Games/Fallout4/ExtraData/ExtraSoul.h delete mode 100644 Code/client/Games/Fallout4/FormManager.cpp delete mode 100644 Code/client/Games/Fallout4/FormManager.h delete mode 100644 Code/client/Games/Fallout4/Forms/ActorValueInfo.cpp delete mode 100644 Code/client/Games/Fallout4/Forms/ActorValueInfo.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSAction.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSColorForm.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSHeadPart.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSInventoryItem.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSInventoryList.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSKeyword.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSNote.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSObjectInstance.cpp delete mode 100644 Code/client/Games/Fallout4/Forms/BGSObjectInstance.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSOutfit.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSStoryManagerTree.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSTextureSet.h delete mode 100644 Code/client/Games/Fallout4/Forms/BGSVoiceType.h delete mode 100644 Code/client/Games/Fallout4/Forms/SpellItem.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESActorBase.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESAmmo.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESBoundAnimObject.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESBoundObject.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESClass.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESCombatStyle.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESFaction.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESForm.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESGlobal.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESIdleForm.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESLevCharacter.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESNPC.cpp delete mode 100644 Code/client/Games/Fallout4/Forms/TESNPC.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESObject.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESObjectARMO.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESObjectBOOK.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESObjectCELL.cpp delete mode 100644 Code/client/Games/Fallout4/Forms/TESObjectCELL.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESObjectMISC.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESObjectWEAP.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESPackage.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESQuest.cpp delete mode 100644 Code/client/Games/Fallout4/Forms/TESQuest.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESRace.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESTopicInfo.cpp delete mode 100644 Code/client/Games/Fallout4/Forms/TESTopicInfo.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESValueForm.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESWeather.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESWeightForm.h delete mode 100644 Code/client/Games/Fallout4/Forms/TESWorldSpace.h delete mode 100644 Code/client/Games/Fallout4/Havok.h delete mode 100644 Code/client/Games/Fallout4/Havok/BShkbAnimationGraph.h delete mode 100644 Code/client/Games/Fallout4/Havok/BShkbHkxDB.h delete mode 100644 Code/client/Games/Fallout4/Havok/hkHashTable.h delete mode 100644 Code/client/Games/Fallout4/Havok/hkbBehaviorGraph.h delete mode 100644 Code/client/Games/Fallout4/Havok/hkbStateMachine.h delete mode 100644 Code/client/Games/Fallout4/Havok/hkbVariableValueSet.h delete mode 100644 Code/client/Games/Fallout4/Interface/IMenu.cpp delete mode 100644 Code/client/Games/Fallout4/Interface/IMenu.h delete mode 100644 Code/client/Games/Fallout4/Interface/UI.cpp delete mode 100644 Code/client/Games/Fallout4/Interface/UI.h delete mode 100644 Code/client/Games/Fallout4/LoadingScreen.cpp delete mode 100644 Code/client/Games/Fallout4/LoadingScreen.h delete mode 100644 Code/client/Games/Fallout4/Magic/ActorMagicCaster.h delete mode 100644 Code/client/Games/Fallout4/Magic/EffectItem.h delete mode 100644 Code/client/Games/Fallout4/Magic/EffectSetting.h delete mode 100644 Code/client/Games/Fallout4/Magic/MagicCaster.h delete mode 100644 Code/client/Games/Fallout4/Magic/MagicItem.h delete mode 100644 Code/client/Games/Fallout4/Magic/MagicTarget.cpp delete mode 100644 Code/client/Games/Fallout4/Magic/MagicTarget.h delete mode 100644 Code/client/Games/Fallout4/Misc/ActorState.h delete mode 100644 Code/client/Games/Fallout4/Misc/ActorValueOwner.h delete mode 100644 Code/client/Games/Fallout4/Misc/BSFixedString.h delete mode 100644 Code/client/Games/Fallout4/Misc/BSScript.cpp delete mode 100644 Code/client/Games/Fallout4/Misc/BSScript.h delete mode 100644 Code/client/Games/Fallout4/Misc/BSString.h delete mode 100644 Code/client/Games/Fallout4/Misc/GameVM.cpp delete mode 100644 Code/client/Games/Fallout4/Misc/GameVM.h delete mode 100644 Code/client/Games/Fallout4/Misc/MiddleProcess.h delete mode 100644 Code/client/Games/Fallout4/Misc/NEW_REFR_DATA.cpp delete mode 100644 Code/client/Games/Fallout4/Misc/NEW_REFR_DATA.h delete mode 100644 Code/client/Games/Fallout4/Misc/NativeFunction.h delete mode 100644 Code/client/Games/Fallout4/Misc/TBO_InstanceData.h delete mode 100644 Code/client/Games/Fallout4/Misc/TintMask.h delete mode 100644 Code/client/Games/Fallout4/Misc/WeatherManager.cpp delete mode 100644 Code/client/Games/Fallout4/Misc/WeatherManager.h delete mode 100644 Code/client/Games/Fallout4/PlayerCharacter.cpp delete mode 100644 Code/client/Games/Fallout4/PlayerCharacter.h delete mode 100644 Code/client/Games/Fallout4/Projectiles/Projectile.cpp delete mode 100644 Code/client/Games/Fallout4/Projectiles/Projectile.h delete mode 100644 Code/client/Games/Fallout4/RTTI.cpp delete mode 100644 Code/client/Games/Fallout4/RTTI.h delete mode 100644 Code/client/Games/Fallout4/Renderer.h delete mode 100644 Code/client/Games/Fallout4/SaveLoad.h delete mode 100644 Code/client/Games/Fallout4/Sky/Sky.h delete mode 100644 Code/client/Games/Fallout4/TESObjectREFR.cpp delete mode 100644 Code/client/Games/Fallout4/TESObjectREFR.h delete mode 100644 Code/client/Games/Fallout4/TimeManager.h diff --git a/Code/client/Events/ActivateEvent.h b/Code/client/Events/ActivateEvent.h index b3b64a1fe..02b38448c 100644 --- a/Code/client/Events/ActivateEvent.h +++ b/Code/client/Events/ActivateEvent.h @@ -9,19 +9,6 @@ struct TESBoundObject; */ struct ActivateEvent { -#if TP_FALLOUT4 - ActivateEvent(TESObjectREFR* apObject, Actor* apActivator, TESBoundObject* apObjectToGet, int32_t aCount, bool aDefaultProcessing, bool aFromScript, bool aIsLooping, bool aActivateFlag = false) - : pObject(apObject) - , pActivator(apActivator) - , pObjectToGet(apObjectToGet) - , Count(aCount) - , DefaultProcessing(aDefaultProcessing) - , FromScript(aFromScript) - , IsLooping(aIsLooping) - , ActivateFlag(aActivateFlag) - { - } -#elif TP_SKYRIM64 ActivateEvent(TESObjectREFR* apObject, Actor* apActivator, TESBoundObject* apObjectToGet, int32_t aCount, bool aDefaultProcessing, uint8_t aUnk1, TESObjectREFR::OpenState aPreActivationOpenState, bool aActivateFlag = false) : pObject(apObject) , pActivator(apActivator) @@ -33,20 +20,13 @@ struct ActivateEvent , ActivateFlag(aActivateFlag) { } -#endif TESObjectREFR* pObject; Actor* pActivator; TESBoundObject* pObjectToGet; int32_t Count; bool DefaultProcessing; -#if TP_FALLOUT4 - bool FromScript; - bool IsLooping; -#elif TP_SKYRIM64 uint8_t Unk1; -#endif - TESObjectREFR::OpenState PreActivationOpenState; bool ActivateFlag; }; diff --git a/Code/client/FalloutVM.cpp b/Code/client/FalloutVM.cpp deleted file mode 100644 index a25470bb4..000000000 --- a/Code/client/FalloutVM.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include "TiltedOnlineApp.h" - -#if TP_FALLOUT4 - -#include - -extern std::unique_ptr g_appInstance; - -struct Main; -struct VMContext -{ - char pad[0x600]; - uint8_t inactive; // 0x600 -}; - -TP_THIS_FUNCTION(TVMUpdate, int, VMContext); -TP_THIS_FUNCTION(TMainLoop, short, Main); -TP_THIS_FUNCTION(TVMDestructor, uintptr_t, void); - -static TVMUpdate* VMUpdate = nullptr; -static TMainLoop* MainLoop = nullptr; -static TVMDestructor* VMDestructor = nullptr; - -int TP_MAKE_THISCALL(HookVMUpdate, VMContext) -{ - if (apThis->inactive == 0) - g_appInstance->Update(); - - return TiltedPhoques::ThisCall(VMUpdate, apThis); -} - -short TP_MAKE_THISCALL(HookMainLoop, Main) -{ - TP_EMPTY_HOOK_PLACEHOLDER; - - return TiltedPhoques::ThisCall(MainLoop, apThis); -} - -uintptr_t TP_MAKE_THISCALL(HookVMDestructor, void) -{ - TP_EMPTY_HOOK_PLACEHOLDER - - return TiltedPhoques::ThisCall(VMDestructor, apThis); -} - -static TiltedPhoques::Initializer s_mainHooks( - []() - { - POINTER_FALLOUT4(TMainLoop, cMainLoop, 633525); - POINTER_FALLOUT4(TVMUpdate, cVMUpdate, 759509); - POINTER_FALLOUT4(TVMDestructor, cVMDestructor, 694341); - - VMUpdate = cVMUpdate.Get(); - MainLoop = cMainLoop.Get(); - VMDestructor = cVMDestructor.Get(); - - TP_HOOK(&VMUpdate, HookVMUpdate); - TP_HOOK(&MainLoop, HookMainLoop); - TP_HOOK(&VMDestructor, HookVMDestructor); - }); - -#endif diff --git a/Code/client/Games/Animation.cpp b/Code/client/Games/Animation.cpp index 0c243f436..253b4278a 100644 --- a/Code/client/Games/Animation.cpp +++ b/Code/client/Games/Animation.cpp @@ -70,7 +70,6 @@ uint8_t TP_MAKE_THISCALL(HookPerformAction, ActorMediator, TESActionData* apActi ActorMediator* ActorMediator::Get() noexcept { - POINTER_FALLOUT4(ActorMediator*, s_actorMediator, 1358859); POINTER_SKYRIMSE(ActorMediator*, s_actorMediator, 403567); return *(s_actorMediator.Get()); @@ -116,7 +115,6 @@ bool ActorMediator::ForceAction(TESActionData* apAction) noexcept POINTER_SKYRIMSE(TAnimationStep, PerformComplexAction, 38953); POINTER_SKYRIMSE(void*, qword_142F271B8, 403566); - POINTER_FALLOUT4(TAnimationStep, PerformComplexAction, 1445653); uint8_t result = 0; auto pActor = static_cast(apAction->actor); @@ -124,9 +122,7 @@ bool ActorMediator::ForceAction(TESActionData* apAction) noexcept { result = TiltedPhoques::ThisCall(PerformComplexAction, this, apAction); -#if TP_SKYRIM64 ApplyAnimationVariables(*qword_142F271B8.Get(), apAction); -#endif } return result; @@ -175,7 +171,6 @@ BGSActionData::BGSActionData(uint32_t aParam1, Actor* apActor, BGSAction* apActi TESActionData::TESActionData(uint32_t aParam1, Actor* apActor, BGSAction* apAction, TESObjectREFR* apTarget) : BGSActionData(aParam1, apActor, apAction, apTarget) { - POINTER_FALLOUT4(void*, s_vtbl, 780201); POINTER_SKYRIMSE(void*, s_vtbl, 188603); someFlag = false; @@ -192,7 +187,6 @@ TESActionData::~TESActionData() static TiltedPhoques::Initializer s_animationHook( []() { - POINTER_FALLOUT4(TPerformAction, performAction, 502377); POINTER_SKYRIMSE(TPerformAction, performAction, 38949); RealPerformAction = performAction.Get(); diff --git a/Code/client/Games/Fallout4/AI/AIProcess.h b/Code/client/Games/Fallout4/AI/AIProcess.h deleted file mode 100644 index d69fcbe79..000000000 --- a/Code/client/Games/Fallout4/AI/AIProcess.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -struct MiddleProcess; - -struct AIProcess -{ - void KnockExplosion(Actor* apActor, const NiPoint3* aSourceLocation, float afMagnitude); - - uint8_t unk0[0x8]; - MiddleProcess* middleProcess; -}; - -static_assert(offsetof(AIProcess, middleProcess) == 0x8); diff --git a/Code/client/Games/Fallout4/Actor.cpp b/Code/client/Games/Fallout4/Actor.cpp deleted file mode 100644 index b4dab2e95..000000000 --- a/Code/client/Games/Fallout4/Actor.cpp +++ /dev/null @@ -1,465 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#include - -TP_THIS_FUNCTION(TActorConstructor, Actor*, Actor, uint8_t aUnk); -TP_THIS_FUNCTION(TActorConstructor2, Actor*, Actor, volatile int** aRefCount, uint8_t aUnk); -TP_THIS_FUNCTION(TActorDestructor, void*, Actor); - -static TActorConstructor* RealActorConstructor; -static TActorConstructor2* RealActorConstructor2; -static TActorDestructor* RealActorDestructor; - -Actor* TP_MAKE_THISCALL(HookActorContructor, Actor, uint8_t aUnk) -{ - TP_EMPTY_HOOK_PLACEHOLDER; - - const auto pActor = TiltedPhoques::ThisCall(RealActorConstructor, apThis, aUnk); - - return pActor; -} - -Actor* TP_MAKE_THISCALL(HookActorContructor2, Actor, volatile int** aRefCount, uint8_t aUnk) -{ - TP_EMPTY_HOOK_PLACEHOLDER; - - const auto pActor = TiltedPhoques::ThisCall(RealActorConstructor2, apThis, aRefCount, aUnk); - - return pActor; -} - -void* TP_MAKE_THISCALL(HookActorDestructor, Actor) -{ - // TODO: Actor dtor sometimes has garbage actor, causing a crash - return TiltedPhoques::ThisCall(RealActorDestructor, apThis); -} - -GamePtr Actor::New() noexcept -{ - const auto pActor = Memory::Allocate(); - - TiltedPhoques::ThisCall(HookActorContructor, pActor, uint8_t(1)); - - return pActor; -} - -TESForm* Actor::GetEquippedWeapon(uint32_t aSlotId) const noexcept -{ - using TGetEquippedWeapon = TESForm*(__fastcall)(void*, void*, const Actor*, uint32_t); - - POINTER_FALLOUT4(TGetEquippedWeapon, s_getEquippedWeapon, 811140); - - return s_getEquippedWeapon(nullptr, nullptr, this, aSlotId); -} - -Factions Actor::GetFactions() const noexcept -{ - Factions result; - - auto& modSystem = World::Get().GetModSystem(); - - auto* pNpc = Cast(baseForm); - if (pNpc) - { - auto& factions = pNpc->actorData.factions; - - for (auto i = 0u; i < factions.length; ++i) - { - Faction faction; - - modSystem.GetServerModId(factions[i].faction->formID, faction.Id); - faction.Rank = factions[i].rank; - - result.NpcFactions.push_back(faction); - } - } - - auto* pFactionExtras = Cast(extraData->GetByType(ExtraDataType::Faction)); - if (pFactionExtras) - { - for (auto i = 0u; i < pFactionExtras->entries.length; ++i) - { - Faction faction; - - modSystem.GetServerModId(pFactionExtras->entries[i].faction->formID, faction.Id); - faction.Rank = pFactionExtras->entries[i].rank; - - result.ExtraFactions.push_back(faction); - } - } - - return result; -} - -ActorValues Actor::GetEssentialActorValues() noexcept -{ - ActorValues actorValues; - - int essentialValues[] = {ActorValueInfo::kHealth}; - - for (auto i : essentialValues) - { - ActorValueInfo* pActorValueInfo = GetActorValueInfo(i); - float value = actorValueOwner.GetValue(pActorValueInfo); - actorValues.ActorValuesList.insert({i, value}); - float maxValue = actorValueOwner.GetMaxValue(pActorValueInfo); - actorValues.ActorMaxValuesList.insert({i, maxValue}); - } - - ActorValueInfo* pActorValueInfoRads = GetActorValueInfo(ActorValueInfo::kRads); - float valueRads = actorValueOwner.GetValue(pActorValueInfoRads); - actorValues.ActorValuesList.insert({ActorValueInfo::kRads, valueRads}); - ActorValueInfo* pActorValueInfoRadsMax = GetActorValueInfo(ActorValueInfo::kRadHealthMax); - float valueRadsMax = actorValueOwner.GetValue(pActorValueInfoRadsMax); - actorValues.ActorValuesList.insert({ActorValueInfo::kRadHealthMax, valueRadsMax}); - - return actorValues; -} - -// use this for fallout 4 projectile launching -void* Actor::GetCurrentWeapon(void* apResult, uint32_t aEquipIndex) noexcept -{ - TP_THIS_FUNCTION(TGetCurrentWeapon, void*, Actor, void* apResult, uint32_t aEquipIndex); - POINTER_FALLOUT4(TGetCurrentWeapon, getCurrentWeapon, 1277202); - return TiltedPhoques::ThisCall(getCurrentWeapon, this, apResult, aEquipIndex); -} - -float Actor::GetActorValue(uint32_t aId) const noexcept -{ - ActorValueInfo* pActorValueInfo = GetActorValueInfo(aId); - return actorValueOwner.GetValue(pActorValueInfo); -} - -float Actor::GetActorPermanentValue(uint32_t aId) const noexcept -{ - ActorValueInfo* pActorValueInfo = GetActorValueInfo(aId); - return actorValueOwner.GetMaxValue(pActorValueInfo); -} - -Inventory Actor::GetActorInventory() const noexcept -{ - return GetInventory(); -} - -Inventory Actor::GetEquipment() const noexcept -{ - Inventory inventory = GetInventory(); - inventory.RemoveByFilter([](const auto& entry) { return !entry.IsWorn(); }); - return inventory; -} - -void Actor::SetActorValue(uint32_t aId, float aValue) noexcept -{ - ActorValueInfo* pActorValueInfo = GetActorValueInfo(aId); - actorValueOwner.SetValue(pActorValueInfo, aValue); -} - -void Actor::ForceActorValue(ActorValueOwner::ForceMode aMode, uint32_t aId, float aValue) noexcept -{ - const float current = GetActorValue(aId); - ActorValueInfo* pActorValueInfo = GetActorValueInfo(aId); - actorValueOwner.ForceCurrent(aMode, pActorValueInfo, aValue - current); -} - -void Actor::SetActorValues(const ActorValues& acActorValues) noexcept -{ - for (auto& value : acActorValues.ActorMaxValuesList) - { - ActorValueInfo* pActorValueInfo = GetActorValueInfo(value.first); - float current = actorValueOwner.GetValue(pActorValueInfo); - actorValueOwner.ForceCurrent(ActorValueOwner::ForceMode::PERMANENT, pActorValueInfo, value.second - current); - } - - for (auto& value : acActorValues.ActorValuesList) - { - ActorValueInfo* pActorValueInfo = GetActorValueInfo(value.first); - if (value.first == ActorValueInfo::kRads || value.first == ActorValueInfo::kRadHealthMax) - actorValueOwner.SetValue(pActorValueInfo, value.second); - float current = actorValueOwner.GetValue(pActorValueInfo); - actorValueOwner.ForceCurrent(ActorValueOwner::ForceMode::DAMAGE, pActorValueInfo, value.second - current); - } -} - -void Actor::SetFactions(const Factions& acFactions) noexcept -{ - RemoveFromAllFactions(); - - auto& modSystem = World::Get().GetModSystem(); - - for (const auto& entry : acFactions.NpcFactions) - { - auto* pForm = GetById(modSystem.GetGameId(entry.Id)); - auto* pFaction = Cast(pForm); - if (pFaction) - { - SetFactionRank(pFaction, entry.Rank); - } - } - - for (const auto& entry : acFactions.ExtraFactions) - { - auto* pForm = GetById(modSystem.GetGameId(entry.Id)); - auto* pFaction = Cast(pForm); - if (pFaction) - { - SetFactionRank(pFaction, entry.Rank); - } - } -} - -void Actor::SetFactionRank(const TESFaction* acpFaction, int8_t aRank) noexcept -{ - PAPYRUS_FUNCTION(void, Actor, SetFactionRank, const TESFaction*, int8_t); - s_pSetFactionRank(this, acpFaction, aRank); -} - -void Actor::SetActorInventory(const Inventory& acInventory) noexcept -{ - spdlog::info("Setting actor inventory, form id: {:X}", formID); - - UnEquipAll(); - - SetInventory(acInventory); -} - -void Actor::UnEquipAll() noexcept -{ - TP_THIS_FUNCTION(TUnEquipAll, void, Actor); - POINTER_FALLOUT4(TUnEquipAll, s_unequipAll, 1260318); - TiltedPhoques::ThisCall(s_unequipAll, this); -} - -void Actor::RemoveFromAllFactions() noexcept -{ - PAPYRUS_FUNCTION(void, Actor, RemoveFromAllFactions); - s_pRemoveFromAllFactions(this); -} - -bool Actor::IsDead() const noexcept -{ - PAPYRUS_FUNCTION(bool, Actor, IsDead); - return s_pIsDead(this); -} - -void Actor::Kill() noexcept -{ - PAPYRUS_FUNCTION(void, Actor, Kill, void*); - s_pKill(this, NULL); -} - -void Actor::Reset() noexcept -{ - using ObjectReference = TESObjectREFR; - PAPYRUS_FUNCTION(void, ObjectReference, Reset, int, TESObjectREFR*); - s_pReset(this, 0, nullptr); -} - -void Actor::Respawn() noexcept -{ - Resurrect(false); - Reset(); -} - -// TODO(cosideci): this is flawed, since we need to equip specific stacks. -void Actor::ProcessScriptedEquip(TESBoundObject* apObj, bool abEquipLockState, bool abSilent) noexcept -{ - ScopedEquipOverride _; - - TP_THIS_FUNCTION(TProcessScriptedEquip, void, Actor, TESBoundObject*, bool, bool); - POINTER_FALLOUT4(TProcessScriptedEquip, processScriptedEquip, 868003); - TiltedPhoques::ThisCall(processScriptedEquip, this, apObj, abEquipLockState, abSilent); -} - -void Actor::DropOrPickUpObject(const Inventory::Entry& arEntry, NiPoint3* apPoint, NiPoint3* apRotate) noexcept -{ - ModSystem& modSystem = World::Get().GetModSystem(); - - uint32_t objectId = modSystem.GetGameId(arEntry.BaseId); - TESBoundObject* pObject = Cast(TESForm::GetById(objectId)); - if (!pObject) - { - spdlog::warn("Object to drop not found, {:X}:{:X}.", arEntry.BaseId.ModId, arEntry.BaseId.BaseId); - return; - } - - if (arEntry.Count < 0) - DropObject(pObject, -arEntry.Count, apPoint, apRotate); - // TODO: pick up -} - -void Actor::DropObject(TESBoundObject* apObject, int32_t aCount, NiPoint3* apPoint, NiPoint3* apRotate) noexcept -{ - BGSObjectInstance object(apObject, nullptr); - - TP_THIS_FUNCTION(TDropObject, BSPointerHandle*, Actor, BSPointerHandle*, BGSObjectInstance*, void*, int32_t, NiPoint3*, NiPoint3*); - POINTER_FALLOUT4(TDropObject, dropObject, 1482294); - - BSPointerHandle result{}; - TiltedPhoques::ThisCall(dropObject, this, &result, &object, nullptr, aCount, apPoint, apRotate); -} - -void Actor::UnequipItem(TESBoundObject* apObject) noexcept -{ - ScopedEquipOverride _; - - PAPYRUS_FUNCTION(void, Actor, UnequipItem, TESBoundObject*, bool, bool); - s_pUnequipItem(this, apObject, false, true); -} - -TP_THIS_FUNCTION(TDamageActor, bool, Actor, float aDamage, Actor* apHitter); -static TDamageActor* RealDamageActor = nullptr; - -bool TP_MAKE_THISCALL(HookDamageActor, Actor, float aDamage, Actor* apHitter) -{ - const auto pExHittee = apThis->GetExtension(); - if (pExHittee->IsLocalPlayer()) - { - World::Get().GetRunner().Trigger(HealthChangeEvent(apThis->formID, -aDamage)); - return TiltedPhoques::ThisCall(RealDamageActor, apThis, aDamage, apHitter); - } - else if (pExHittee->IsRemotePlayer()) - { - return false; - } - - if (apHitter) - { - const auto pExHitter = apHitter->GetExtension(); - if (pExHitter->IsLocalPlayer()) - { - World::Get().GetRunner().Trigger(HealthChangeEvent(apThis->formID, -aDamage)); - return TiltedPhoques::ThisCall(RealDamageActor, apThis, aDamage, apHitter); - } - if (pExHitter->IsRemotePlayer()) - { - return false; - } - } - - if (pExHittee->IsLocal()) - { - World::Get().GetRunner().Trigger(HealthChangeEvent(apThis->formID, -aDamage)); - return TiltedPhoques::ThisCall(RealDamageActor, apThis, aDamage, apHitter); - } - else - { - return false; - } -} - -TP_THIS_FUNCTION(TApplyActorEffect, void, ActiveEffect, Actor* apTarget, float aEffectValue, ActorValueInfo* apActorValueInfo); -static TApplyActorEffect* RealApplyActorEffect = nullptr; - -void TP_MAKE_THISCALL(HookApplyActorEffect, ActiveEffect, Actor* apTarget, float aEffectValue, ActorValueInfo* apActorValueInfo) -{ - const auto* pValueModEffect = Cast(apThis); - - if (pValueModEffect) - { - ActorValueInfo* pHealthActorValueInfo = apTarget->GetActorValueInfo(ActorValueInfo::kHealth); - if (pValueModEffect->actorValueInfo == pHealthActorValueInfo && aEffectValue > 0.0f) - { - if (apTarget && apTarget->GetExtension()) - { - const auto pExTarget = apTarget->GetExtension(); - if (pExTarget->IsLocal()) - { - World::Get().GetRunner().Trigger(HealthChangeEvent(apTarget->formID, aEffectValue)); - return TiltedPhoques::ThisCall(RealApplyActorEffect, apThis, apTarget, aEffectValue, apActorValueInfo); - } - return; - } - } - } - - return TiltedPhoques::ThisCall(RealApplyActorEffect, apThis, apTarget, aEffectValue, apActorValueInfo); -} - -TP_THIS_FUNCTION(TRunDetection, void, void, ActorKnowledge*); -static TRunDetection* RealRunDetection = nullptr; - -void TP_MAKE_THISCALL(HookRunDetection, void, ActorKnowledge* apTarget) -{ - auto pOwner = TESObjectREFR::GetByHandle(apTarget->hOwner); - auto pTarget = TESObjectREFR::GetByHandle(apTarget->hTarget); - - if (pOwner && pTarget) - { - auto pOwnerActor = Cast(pOwner); - auto pTargetActor = Cast(pTarget); - if (pOwnerActor && pTargetActor) - { - if (pOwnerActor->GetExtension()->IsRemotePlayer() && pTargetActor->GetExtension()->IsLocalPlayer()) - { - spdlog::info("Cancelling detection from remote player to local player"); - return; - } - } - } - - return TiltedPhoques::ThisCall(RealRunDetection, apThis, apTarget); -} - -TP_THIS_FUNCTION(TSpeakSoundFunction, float, Actor, const char* apName, uint32_t* aSoundHand, void* apArchTypeAnimation, int32_t aiStringLength, bool abSetEmotion, void* apOutputModel, bool abQueue, bool abLip, bool abPCapcall); -static TSpeakSoundFunction* RealSpeakSoundFunction = nullptr; - -bool TP_MAKE_THISCALL(HookSpeakSoundFunction, Actor, const char* apName, uint32_t* aSoundHand, void* apArchTypeAnimation, int32_t aiStringLength, bool abSetEmotion, void* apOutputModel, bool abQueue, bool abLip, bool abPCapcall) -{ - if (apThis->GetExtension()->IsLocal()) - World::Get().GetRunner().Trigger(DialogueEvent(apThis->formID, apName)); - - return TiltedPhoques::ThisCall(RealSpeakSoundFunction, apThis, apName, aSoundHand, apArchTypeAnimation, aiStringLength, abSetEmotion, apOutputModel, abQueue, abLip, abPCapcall); -} - -void Actor::SpeakSound(const char* pFile) -{ - uint32_t handle[4]{}; - handle[0] = -1; - TiltedPhoques::ThisCall(RealSpeakSoundFunction, this, pFile, handle, nullptr, 0, false, nullptr, false, true, false); -} - -static TiltedPhoques::Initializer s_specificReferencesHooks( - []() - { - POINTER_FALLOUT4(TActorConstructor, s_actorCtor, 1027501); - POINTER_FALLOUT4(TActorConstructor2, s_actorCtor2, 1331729); - POINTER_FALLOUT4(TActorDestructor, s_actorDtor, 1104083); - POINTER_FALLOUT4(TDamageActor, s_damageActor, 1539011); - // TODO: not sure about this ID, seems to interfere with jump when hooked? - POINTER_FALLOUT4(TApplyActorEffect, s_applyActorEffect, 703727); - POINTER_FALLOUT4(TRunDetection, s_runDetection, 906785); - POINTER_FALLOUT4(TSpeakSoundFunction, s_speakSoundFunction, 1567997); - - RealActorConstructor = s_actorCtor.Get(); - RealActorConstructor2 = s_actorCtor2.Get(); - RealActorDestructor = s_actorDtor.Get(); - RealDamageActor = s_damageActor.Get(); - RealApplyActorEffect = s_applyActorEffect.Get(); - RealRunDetection = s_runDetection.Get(); - RealSpeakSoundFunction = s_speakSoundFunction.Get(); - - TP_HOOK(&RealActorConstructor, HookActorContructor); - TP_HOOK(&RealActorConstructor2, HookActorContructor2); - TP_HOOK(&RealActorDestructor, HookActorDestructor); - TP_HOOK(&RealDamageActor, HookDamageActor); - TP_HOOK(&RealApplyActorEffect, HookApplyActorEffect); - TP_HOOK(&RealRunDetection, HookRunDetection); - TP_HOOK(&RealSpeakSoundFunction, HookSpeakSoundFunction); - }); diff --git a/Code/client/Games/Fallout4/Actor.h b/Code/client/Games/Fallout4/Actor.h deleted file mode 100644 index e356bca11..000000000 --- a/Code/client/Games/Fallout4/Actor.h +++ /dev/null @@ -1,200 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -struct ExActor; -struct ExPlayerCharacter; -struct ActorExtension; -struct TESNPC; -struct AIProcess; -struct TESFaction; -struct TESPackage; - -struct Actor : TESObjectREFR -{ - static constexpr FormType Type = FormType::Character; - - static GamePtr New() noexcept; - static GamePtr Create(TESNPC* apNpc) noexcept; - static GamePtr Spawn(uint32_t aBaseFormId) noexcept; - - virtual void sub_C4(); - virtual void sub_C5(); - virtual void sub_C6(); - virtual void sub_C7(); - virtual void sub_C8(); - virtual void SetWeaponDrawn(bool aIsDrawn); - virtual void SetPosition(const NiPoint3& acPosition, bool aSyncHavok = true); - virtual void sub_CB(); - virtual void Resurrect(bool aResetInventory); - virtual void sub_CD(); - virtual void sub_CE(); - virtual void sub_CF(); - virtual void sub_D0(); - virtual void sub_D1(); - virtual void sub_D2(); - virtual void sub_D3(); - virtual void sub_D4(); - virtual void sub_D5(); - virtual void sub_D6(); - virtual void sub_D7(); - virtual void sub_D8(); - virtual void sub_D9(); - virtual void sub_DA(); - virtual void sub_DB(); - virtual void sub_DC(); - virtual void sub_DD(); - virtual void sub_DE(); - virtual void sub_DF(); - virtual void sub_E0(); - virtual void sub_E1(); - virtual void sub_E2(); - virtual void sub_E3(); - virtual void sub_E4(); - virtual void sub_E5(); - virtual void sub_E6(); - virtual void sub_E7(); - virtual void sub_E8(); - virtual void sub_E9(); - virtual void sub_EA(); - virtual void sub_EB(); - virtual void sub_EC(); - virtual void sub_ED(); - virtual void sub_EE(); - virtual void sub_EF(); - virtual void sub_F0(); - virtual void sub_F1(); - virtual void sub_F2(); - virtual void sub_F3(); - virtual void sub_F4(); - virtual void sub_F5(); - virtual void sub_F6(); - virtual void sub_F7(); - virtual void sub_F8(); - virtual void sub_F9(); - virtual void sub_FA(); - virtual void sub_FB(); - virtual void sub_FC(); - virtual void sub_FD(); - virtual void sub_FE(); - virtual void PutCreatedPackage(struct TESPackage*, bool = false, bool = true, bool = true); - virtual void sub_100(); - //... - // virtual void sub_132(); - - // Casting - ActorExtension* GetExtension() noexcept; - ExActor* AsExActor() noexcept; - ExPlayerCharacter* AsExPlayerCharacter() noexcept; - - // Getters - float GetSpeed() noexcept; - TESForm* GetEquippedWeapon(uint32_t aSlotId) const noexcept; - Inventory GetActorInventory() const noexcept; - Inventory GetEquipment() const noexcept; - Factions GetFactions() const noexcept; - ActorValues GetEssentialActorValues() noexcept; - float GetActorValue(uint32_t aId) const noexcept; - float GetActorPermanentValue(uint32_t aId) const noexcept; - void* GetCurrentWeapon(void* apResult, uint32_t aEquipIndex) noexcept; - uint16_t GetLevel() const noexcept; - [[nodiscard]] bool IsDead() const noexcept; - [[nodiscard]] bool IsInCombat() const noexcept; - [[nodiscard]] Actor* GetCombatTarget() const noexcept; - [[nodiscard]] bool HasPerk(uint32_t aPerkFormId) const noexcept; - [[nodiscard]] uint8_t GetPerkRank(uint32_t aPerkFormId) const noexcept; - - // Setters - void SetSpeed(float aSpeed) noexcept; - void SetLevelMod(uint32_t aLevel) noexcept; - void SetActorInventory(const Inventory& acInventory) noexcept; - void SetActorValue(uint32_t aId, float aValue) noexcept; - void ForceActorValue(ActorValueOwner::ForceMode aMode, uint32_t aId, float aValue) noexcept; - void SetActorValues(const ActorValues& acActorValues) noexcept; - void SetFactions(const Factions& acFactions) noexcept; - void SetFactionRank(const TESFaction* acpFaction, int8_t aRank) noexcept; - void ForcePosition(const NiPoint3& acPosition) noexcept; - void SetWeaponDrawnEx(bool aDraw) noexcept; - void SetPackage(TESPackage* apPackage) noexcept; - void SetNoBleedoutRecovery(bool aSet) noexcept; - void SetEssentialEx(bool aSet) noexcept; - void SetPlayerRespawnMode(bool aSet = true) noexcept; - - // Actions - void UnEquipAll() noexcept; - void QueueUpdate() noexcept; - void RemoveFromAllFactions() noexcept; - void DispelAllSpells(bool aNow = false) noexcept; - void Kill() noexcept; - void Respawn() noexcept; - void Reset() noexcept; - void SpeakSound(const char* pFile); - void ProcessScriptedEquip(TESBoundObject* apObj, bool abEquipLockState = false, bool abSilent = true) noexcept; - void DropObject(TESBoundObject* apObject, int32_t aCount, NiPoint3* apPoint, NiPoint3* apRotate) noexcept; - void DropOrPickUpObject(const Inventory::Entry& arEntry, NiPoint3* apPoint, NiPoint3* apRotate) noexcept; - void UnequipItem(TESBoundObject* apObject) noexcept; - void StartCombatEx(Actor* apTarget) noexcept; - void SetCombatTargetEx(Actor* apTarget) noexcept; - void StartCombat(Actor* apTarget) noexcept; - void StopCombat() noexcept; - - enum ActorFlags - { - IS_A_MOUNT = 1 << 1, - IS_ESSENTIAL = 1 << 18, - }; - - struct ActorValueModifiers - { - float permanentModifier; - float temporaryModifier; - float damageModifier; - }; - - // TODO: ft verify, fallout has no mounts? unlikely, but maybe this flag is reused for something else? - // those helicopters maybe? - bool IsMount() const noexcept { return flags2 & ActorFlags::IS_A_MOUNT; } - - bool IsEssential() const noexcept { return flags2 & ActorFlags::IS_ESSENTIAL; } - void SetEssential(bool aSetEssential) noexcept - { - if (aSetEssential) - flags2 |= ActorFlags::IS_ESSENTIAL; - else - flags2 &= ~ActorFlags::IS_ESSENTIAL; - } - - MagicTarget magicTarget; - ActorState actorState; - BSTEventSink movementDataChangedSink; - BSTEventSink transformDeltaSink; - BSTEventSink subGraphActivationUpdateSink; - BSTEventSink characterMoveFinishSink; - BSTEventSink nonSupportContactSink; - BSTEventSink characterStateChangeSink; - void* postAnimationChannelUpdateFunctor; - uint8_t unk170[0x2D0 - 0x170]; - uint32_t actorFlags; - uint8_t unk2D8[0x300 - 0x2D8]; - AIProcess* currentProcess; - - uint8_t pad308[0x3E8 - 0x308]; - TESForm* magicItems[4]; - uint8_t pad408[0x43C - 0x408]; - uint32_t flags2; - uint8_t pad440[0x4]; - ActorValueModifiers healthModifiers; - uint8_t padActorEnd[0x490 - 0x450]; -}; - -static_assert(sizeof(Actor) == 0x490); -static_assert(offsetof(Actor, magicItems) == 0x3E8); diff --git a/Code/client/Games/Fallout4/BSAnimationGraphManager.h b/Code/client/Games/Fallout4/BSAnimationGraphManager.h deleted file mode 100644 index 4503616cb..000000000 --- a/Code/client/Games/Fallout4/BSAnimationGraphManager.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -struct BSFixedString; -struct BShkbAnimationGraph; - -struct BSAnimationGraphManager -{ - virtual ~BSAnimationGraphManager(); - virtual void sub_1(void* apUnk1); - - void Release() - { - if (InterlockedDecrement(&refCount) == 0) - this->~BSAnimationGraphManager(); - } - - volatile LONG refCount; - - void* pad_ptrs[6]; - BSTSmallArray animationGraphs; - uint8_t pad54[0xC8 - 0x58]; - BSRecursiveLock lock; // C8 - void* unkD0; // D0 - uint32_t animationGraphIndex; // D8 - - SortedMap DumpAnimationVariables(bool aPrintVariables); - uint64_t GetDescriptorKey(int aForceIndex = -1); -}; - -static_assert(offsetof(BSAnimationGraphManager, animationGraphs) == 0x40); -static_assert(offsetof(BSAnimationGraphManager, lock) == 0xC8); -static_assert(offsetof(BSAnimationGraphManager, animationGraphIndex) == 0xD8); diff --git a/Code/client/Games/Fallout4/BSCore/BSCRC16.cpp b/Code/client/Games/Fallout4/BSCore/BSCRC16.cpp deleted file mode 100644 index ec4e25357..000000000 --- a/Code/client/Games/Fallout4/BSCore/BSCRC16.cpp +++ /dev/null @@ -1,22 +0,0 @@ - -#include -#include "BSCore/BSCRC32.h" -#include "BSCRC16.h" - -namespace creation -{ -static uint16_t s_table[] = { - 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, - 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, - 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, - 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, - 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, - 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, - 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, -}; - -uint16_t* BSCRC16::GetCRCTable() -{ - return s_table; -} -} // namespace creation diff --git a/Code/client/Games/Fallout4/BSCore/BSCRC16.h b/Code/client/Games/Fallout4/BSCore/BSCRC16.h deleted file mode 100644 index 34f15c9c6..000000000 --- a/Code/client/Games/Fallout4/BSCore/BSCRC16.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -namespace creation -{ -struct BSCRC16 -{ - static uint16_t* GetCRCTable(); -}; -} // namespace creation diff --git a/Code/client/Games/Fallout4/BSCore/BSCRC32.cpp b/Code/client/Games/Fallout4/BSCore/BSCRC32.cpp deleted file mode 100644 index 9e9979aa8..000000000 --- a/Code/client/Games/Fallout4/BSCore/BSCRC32.cpp +++ /dev/null @@ -1,19 +0,0 @@ - -#include -#include "BSCore/BSCRC32.h" - -namespace creation -{ -void BSCRC32::GenerateCRC(uint32_t& aiCRC, uint32_t auiData, uint32_t auiDefaultvalue) -{ -#if defined(DEBUG) - // CryptoPP cant handle a default value. - if (auiDefaultvalue != 0) - __debugbreak(); -#endif - - CryptoPP::CRC32 crc; - crc.Update(reinterpret_cast(&auiData), sizeof(uint32_t)); - crc.TruncatedFinal(reinterpret_cast(&aiCRC), sizeof(uint32_t)); -} -} // namespace creation diff --git a/Code/client/Games/Fallout4/BSCore/BSCRC32.h b/Code/client/Games/Fallout4/BSCore/BSCRC32.h deleted file mode 100644 index 3cfee4252..000000000 --- a/Code/client/Games/Fallout4/BSCore/BSCRC32.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -namespace creation -{ -struct BSCRC32 -{ - void GenerateCRC(uint32_t& aiCRC, uint32_t auiData, uint32_t auiDefaultvalue); -}; -} // namespace creation diff --git a/Code/client/Games/Fallout4/BSCore/BSTHashMap.h b/Code/client/Games/Fallout4/BSCore/BSTHashMap.h deleted file mode 100644 index 69c3bfa3a..000000000 --- a/Code/client/Games/Fallout4/BSCore/BSTHashMap.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "BSCore/BSTScatterTable.h" - -namespace creation -{ -// Verified to be same on FT as ST - -// Taken off libskyrim, see himika -// https://github.com/himika/libSkyrim - -template struct BSTHashMapTraits -{ - typedef Table table_type; -}; - -template class BSTHashMapBase : public Traits, public Traits::table_type -{ -}; - -template class Table = BSTDefaultScatterTable> class BSTHashMap : public BSTHashMapBase>> -{ -}; - -// static_assert(sizeof(BSTHashMap) == 0x30); -} // namespace creation diff --git a/Code/client/Games/Fallout4/BSCore/BSTScatterTable.h b/Code/client/Games/Fallout4/BSCore/BSTScatterTable.h deleted file mode 100644 index 41d3cb132..000000000 --- a/Code/client/Games/Fallout4/BSCore/BSTScatterTable.h +++ /dev/null @@ -1,919 +0,0 @@ -#pragma once - -#include "BSCore/BSCRC32.h" - -namespace creation -{ -// Taken off libskyrim, see himika -// https://github.com/himika/libSkyrim - -// 00 -template struct BSTScatterTableDefaultHashPolicy -{ - typedef uint32_t hash_type; - - inline static hash_type get_hash(const Key& key) - { - uint32_t crc = 0; - BSCRC32::GenerateCRC(crc, key, 0); - return crc; - } - - inline static bool is_key_equal(const Key& a, const Key& b) { return a == b; } -}; - -template struct BSTScatterTableDefaultKVStorage -{ - typedef Key key_type; - typedef Value value_type; - - Key key; - Value value; -}; - -template class Storage = BSTScatterTableDefaultKVStorage> struct BSTScatterTableEntry : public Storage -{ -private: - typedef Storage _base_t; - -public: - BSTScatterTableEntry() - : next(nullptr) - { - } - ~BSTScatterTableEntry() { next = nullptr; } - - bool empty() const { return next == nullptr; } - - // @members - // Key key; - // Value value; - BSTScatterTableEntry* next; -}; - -// 00 -template struct BSTScatterTableHeapAllocator -{ - -public: - typedef Entry entry_type; - typedef typename entry_type::key_type key_type; - typedef typename entry_type::value_type value_type; - -protected: - static inline entry_type* Allocate(size_t num) - { - /*entry_type* entries = (entry_type*)Heap_Allocate(sizeof(entry_type) * num); - if (entries) { - entry_type* p = entries; - while (num) { - p->next = nullptr; - ++p; --num; - } - } - return entries;*/ - - return nullptr; - } - - static inline void Free(entry_type* p) - { - // Heap_Free(p); - } - - static inline size_t GetRelevantSize(size_t num) - { - if (num > 0) - num = 1 << _msb(num - 1); - return num; - } - -private: - static inline size_t _msb(unsigned int x) - { - union - { - unsigned int as_uint32_t; - float as_float; - } data; - data.as_float = (float)x + 0.5f; - - return (data.as_uint32_t >> 23) - 126; - } -}; - -// 00 -template class Storage, class HashPolicy, class Allocator, size_t INITIAL_TABLE_SIZE> struct BSTScatterTableTraits -{ - typedef uint32_t size_type; - typedef Key key_type; - typedef Value value_type; - typedef Storage storage_type; - typedef HashPolicy hash_policy; - typedef Allocator allocator_type; - - typedef typename allocator_type::entry_type entry_type; - typedef typename hash_policy::hash_type hash_type; - - const static size_type initial_table_size = INITIAL_TABLE_SIZE; -}; - -// 15 -template -class BSTScatterTableKernel : public Traits, // 00 - protected Traits::hash_policy // 01 -{ -public: - typedef typename Traits::size_type size_type; - typedef typename Traits::key_type key_type; - typedef typename Traits::value_type value_type; - typedef typename Traits::storage_type storage_type; - typedef typename Traits::hash_policy hash_policy; - typedef typename Traits::allocator_type allocator_type; - typedef typename Traits::entry_type entry_type; - typedef typename Traits::hash_type hash_type; - - using hash_policy::get_hash; - using hash_policy::is_key_equal; - - class hasher - { - public: - hasher() {} - - hash_type operator()(const key_type& key) const { return hash_policy::get_hash(key); } - }; - - class key_equal - { - public: - key_equal() {} - - bool operator()(const key_type& a, const key_type& b) const { return hash_policy::is_key_equal(a, b); } - }; - - bool empty() const { return size() == 0; } - - size_type max_size() const { return m_size; } - - size_type size() const { return m_size - m_freeCount; } - - size_type free_count() const { return m_freeCount; } - -protected: - BSTScatterTableKernel() - : m_size(0) - , m_freeCount(0) - , m_freeOffset(0) - { - m_eolPtr = (entry_type*)&sentinel; - } - - inline entry_type* _entry_at(entry_type* entries, hash_type hash) const { return entries + (hash & (m_size - 1)); } - - // 005A6190 - static void _entry_new(entry_type* p, entry_type* next, const key_type& key, const value_type& value) - { - if (p) - { - new (&p->key) key_type(key); - new (&p->value) value_type(value); - p->next = next; - } - } - - static inline void _entry_move(entry_type* to, entry_type* from) { memcpy_s(to, sizeof(*to), from, sizeof(*from)); } - - void _clear(entry_type* entries) - { - if (entries && m_size) - { - const entry_type* tail = entries + m_size; - for (entry_type* p = entries; p < tail; ++p) - { - if (!p->empty()) - { - p->~entry_type(); - } - } - m_freeCount = m_freeOffset = m_size; - } - } - - // 004FD070 - entry_type* _get_free_entry(entry_type* entries) - { - if (m_freeCount == 0) - return nullptr; - - entry_type* p = nullptr; - while (true) - { - m_freeOffset = (m_freeOffset - 1) & (max_size() - 1); - p = entries + m_freeOffset; - if (p->empty()) - break; - } - - m_freeCount--; - - return p; - } - - entry_type* _find(const entry_type* entries, hash_type hash, const key_type& key) const - { - if (!entries) - return nullptr; - - entry_type* p = _entry_at(const_cast(entries), hash); - - if (p->empty()) - return nullptr; - - while (!is_key_equal(p->key, key)) - { - p = p->next; - if (p == m_eolPtr) - { - p = nullptr; - break; - } - } - - return p; - } - - // 005B1840 - bool _insert(entry_type* entries, hash_type hash, const key_type& key, const value_type& value, uint16_t& unk) - { - if (!entries) - return false; - - entry_type* targetEntry = _entry_at(entries, hash); - if (targetEntry->empty()) - { - // target entry is free - new (&targetEntry->key) key_type(key); - new (&targetEntry->value) key_type(value); - targetEntry->next = m_eolPtr; - --m_freeCount; - return true; - } - - entry_type* p = targetEntry; - do - { - if (is_key_equal(p->key, key)) - { - // already exists - p->value = value; - return true; - } - p = p->next; - } while (p != m_eolPtr); - - entry_type* freeEntry = _get_free_entry(entries); - if (!freeEntry) - return false; - - p = _entry_at(entries, get_hash(targetEntry->key)); - if (p == targetEntry) - { - // hash collision - // insert new entry after target entry - _entry_new(freeEntry, targetEntry->next, key, value); - targetEntry->next = freeEntry; - return true; - } - - // bucket overlap - while (p->next != targetEntry) - p = p->next; - - _entry_move(freeEntry, targetEntry); - - p->next = freeEntry; - _entry_new(targetEntry, m_eolPtr, key, value); - return true; - } - - entry_type* _insert(entry_type* entries, hash_type hash, const key_type& key) - { - if (!entries) - return nullptr; - - entry_type* targetEntry = _entry_at(entries, hash); - if (targetEntry->empty()) - { - // target entry is free - --m_freeCount; - targetEntry->next = m_eolPtr; - new (&targetEntry->key) key_type(key); - return targetEntry; - } - - entry_type* p = targetEntry; - do - { - if (is_key_equal(p->key, key)) - { - // already exists - p->value.~value_type(); - return p; - } - p = p->next; - } while (p != m_eolPtr); - - entry_type* freeEntry = _get_free_entry(entries); - if (!freeEntry) - return nullptr; - - p = _entry_at(entries, get_hash(targetEntry->key)); - if (p == targetEntry) - { - // hash collision - // insert new entry after target entry - freeEntry->next = targetEntry->next; - targetEntry->next = freeEntry; - p = freeEntry; - } - else - { - // bucket overlap - while (p->next != targetEntry) - p = p->next; - p->next = freeEntry; - - _entry_move(freeEntry, targetEntry); - - targetEntry->next = m_eolPtr; - p = targetEntry; - } - - new (&p->key) key_type(key); - return p; - } - - // 008BF800 - bool _insert_move(entry_type* entries, hash_type hash, entry_type* kv) - { - if (!entries) - return false; - - entry_type* targetEntry = _entry_at(entries, hash); - if (targetEntry->empty()) - { - // target entry is free - _entry_move(targetEntry, kv); - targetEntry->next = m_eolPtr; - --m_freeCount; - return true; - } - - entry_type* freeEntry = _get_free_entry(entries); - - entry_type* p = _entry_at(entries, get_hash(targetEntry->key)); - if (p == targetEntry) - { - // hash collision - _entry_move(freeEntry, kv); - freeEntry->next = targetEntry->next; - targetEntry->next = freeEntry; - return true; - } - - // bucket overlap - while (p->next != targetEntry) - p = p->next; - - _entry_move(freeEntry, targetEntry); - p->next = freeEntry; - _entry_move(targetEntry, kv); - targetEntry->next = m_eolPtr; - - return true; - } - - bool _erase(entry_type* entries, hash_type hash, const key_type& key) - { - if (!entries) - return false; - - entry_type* targetEntry = _entry_at(entries, hash); - if (targetEntry->empty()) - { - return false; - } - - if (is_key_equal(targetEntry->key, key)) - { - entry_type* nextEntry = targetEntry->next; - targetEntry->~entry_type(); - ++m_freeCount; - - if (nextEntry != m_eolPtr) - { - _entry_move(targetEntry, nextEntry); - nextEntry->next = nullptr; - } - return true; - } - - entry_type* prevEntry = targetEntry; - entry_type* curEntry = targetEntry->next; - while (true) - { - if (curEntry == m_eolPtr) - return false; // not found - if (is_key_equal(curEntry->key, key)) - break; // found - - prevEntry = curEntry; - curEntry = curEntry->next; - } - entry_type* nextEntry = curEntry->next; - - curEntry->~entry_type(); - ++m_freeCount; - - if (nextEntry != m_eolPtr) - { - _entry_move(curEntry, nextEntry); - nextEntry->next = nullptr; - } - else - { - prevEntry->next = m_eolPtr; - } - - return true; - } - - // @members - // Traits pad00; // 00 -public: - uint32_t m_size; // 04 - uint32_t m_freeCount; // 08 - uint32_t m_freeOffset; // 0C - entry_type* m_eolPtr; // 10 - - static uint32_t sentinel; // DEADBEEF -}; - -template uint32_t BSTScatterTableKernel::sentinel = 0x0EFBEADDE; // DEADBEEF - -// 1>class BSTScatterTableBase, struct BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8> > size(28) : 1> +-- - 1> 0 | +-- - (base class BSTScatterTableKernel, struct -// BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8> >) -// 1> 0 | | +-- - (base class BSTScatterTableTraits, struct BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8>) 1> | | +-- - 1> 1 | | +-- - (base class BSTScatterTableDefaultHashPolicy) 1> | | +-- - 1> | | (size = 3) 1> 4 | | m_size 1> 8 | | -// m_freeCount 1>0C | | m_freeOffset 1>10 | | m_eolPtr 1> | +-- - 1>19 | +-- - (base class BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >) 1> | +-- - 1> | (size -// = 7) 1>20 | m_entries 1> +-- - - -template -class BSTScatterTableBase : public BSTScatterTableKernel, // 00 - protected Traits::allocator_type // 18 -{ -public: - typedef typename creation::BSTScatterTableKernel::hasher hasher; - typedef typename creation::BSTScatterTableKernel::key_equal key_equal; - - typedef BSTScatterTableKernel Kernel; - - typedef typename Kernel::size_type size_type; - typedef typename Kernel::key_type key_type; - typedef typename Kernel::value_type value_type; - typedef typename Kernel::storage_type storage_type; - typedef typename Kernel::hash_policy hash_policy; - typedef typename Kernel::allocator_type allocator_type; - typedef typename Kernel::entry_type entry_type; - typedef typename Kernel::hash_type hash_type; - - // compile hints for GCC - using Kernel::m_eolPtr; - using Kernel::m_freeCount; - using Kernel::m_freeOffset; - using Kernel::m_size; - using Kernel::max_size; - using Kernel::size; - - class const_iterator - { - public: - typedef const_iterator _iter; - typedef const storage_type* pointer; - typedef const storage_type& reference; - - const_iterator(const BSTScatterTableBase* a_table, entry_type* a_entry) - : m_table(a_table) - , m_entry(a_entry) - { - if (a_entry) - { - const entry_type* tail = m_table->_entry_tail(); - while (m_entry < tail && m_entry->empty()) - { - m_entry += 1; - } - } - else - { - m_entry = const_cast(m_table->_entry_tail()); - } - } - - operator pointer() const { return static_cast(m_entry); } - reference operator*() const { return *(pointer) * this; } - pointer operator->() const { return (pointer) * this; } - - _iter& operator++() - { - const entry_type* tail = m_table->_entry_tail(); - do - { - m_entry += 1; - } while (m_entry < tail && m_entry->empty()); - - return *this; - } - _iter operator++(int) - { - _iter tmp = *this; - ++*this; - return tmp; - } - - _iter& operator--() - { - const entry_type* head = m_table->_entry_head(); - do - { - m_entry -= 1; - } while (m_entry >= head && m_entry->empty()); - - return *this; - } - _iter operator--(int) - { - _iter tmp = *this; - --*this; - return tmp; - } - - bool operator==(const _iter& rhs) const { return (m_entry == rhs.m_entry); } - bool operator!=(const _iter& rhs) const { return (!(*this == rhs)); } - - protected: - const BSTScatterTableBase* m_table; - entry_type* m_entry; - }; - - class iterator : public const_iterator - { - public: - typedef iterator _iter; - typedef storage_type* pointer; - typedef storage_type& reference; - - // compiler hits for GCC - using const_iterator::m_entry; - - iterator(const BSTScatterTableBase* a_table, entry_type* a_entry) - : const_iterator(a_table, a_entry) - { - } - - operator pointer() { return static_cast(m_entry); } - reference operator*() { return *(pointer) * this; } - pointer operator->() { return (pointer) * this; } - }; - - iterator begin() { return iterator(this, _entry_head()); } - const_iterator begin() const { return const_iterator(this, _entry_head()); } - const_iterator cbegin() const { return const_iterator(this, _entry_head()); } - - iterator end() { return iterator(this, _entry_head() + m_size); } - const_iterator end() const { return const_iterator(this, _entry_head() + m_size); } - const_iterator cend() const { return const_iterator(this, _entry_head() + m_size); } - - hasher hash_function() const { return hasher(); } - - key_equal key_eq() const { return key_equal(); } - - inline void clear() { this->_clear(m_entries); } - -protected: - BSTScatterTableBase() - : Kernel() - , m_entries(nullptr) - { - } - - ~BSTScatterTableBase() - { - if (m_entries) - { - clear(); - this->Free(m_entries); - } - } - - inline entry_type* _entry_head() const { return const_cast(m_entries); } - inline entry_type* _entry_last() const { return _entry_head() + (max_size() - 1); } - inline entry_type* _entry_tail() const { return _entry_head() + max_size(); } - - inline entry_type* _get_free_entry() { return BSTScatterTableKernel::_get_free_entry(m_entries); } - - // 008BF970 - void _grow_table() - { - size_type oldSize = m_size; - entry_type* oldEntries = m_entries; - - m_size = (oldSize) ? (oldSize * 2) : this->initial_table_size; - m_entries = (entry_type*)allocator_type::Allocate(m_size); - m_freeCount = m_size; - m_freeOffset = m_size; - - if (m_entries && m_size) - { - // init entries - entry_type* p = m_entries; - for (size_type i = m_size; i; --i) - { - p->next = nullptr; - ++p; - }; - } - - // move from old entries to new one - if (oldEntries) - { - entry_type* from = oldEntries; - for (size_type i = oldSize; i; --i) - { - if (!from->empty()) - { - hash_type hash = hash_policy::get_hash(from->key); - _insert_move(m_entries, hash, from); - } - ++from; - } - - Heap_Free(oldEntries); - } - } - - void _assign(const BSTScatterTableBase& rhs) - { - if (!this->empty()) - { - clear(); - Free(m_entries); - m_entries = nullptr; - } - - if (rhs.empty()) - return; - - m_entries = allocator_type::Allocate(rhs.m_size); - if (m_entries) - { - m_size = rhs.m_size; - m_freeCount = rhs.m_freeCount; - m_freeOffset = rhs.m_freeOffset; - - entry_type* to = m_entries; - entry_type* from = rhs.m_entries; - size_t count = m_size; - while (--count) - { - if (!from->empty()) - { - new (&to->key) key_type(from->key); - new (&to->value) value_type(from->value); - to->next = (from->next == rhs.m_eolPtr) ? m_eolPtr : (m_entries + (from - rhs.m_entries)); - } - ++to; - ++from; - } - } - } - - void _assign(BSTScatterTableBase&& rhs) - { - if (!this->empty()) - { - clear(); - Free(m_entries); - m_entries = nullptr; - } - - m_size = rhs.m_size; - m_freeCount = rhs.m_freeCount; - m_freeOffset = rhs.m_freeOffset; - m_eolPtr = rhs.m_eolPtr; - m_entries = rhs.m_entries; - - rhs.m_size = 0; - rhs.m_freeCount = 0; - rhs.m_freeOffset = 0; - rhs.m_entries = nullptr; - } - - // @members - // Traits pad00; 00 - // uint32_t m_size; 04 - // uint32_t m_freeCount; 08 - // uint32_t m_freeOffset; 0C - // entry_type * m_eolPtr; 10 - // allocator_type pad14; // 18 -public: - entry_type* m_entries; // 20 -}; - -// 1>class BSTScatterTable, struct BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, 8> size(28) : -// 1> +-- - -// 1> 0 | +-- - (base class BSTScatterTableBase, struct BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8> >) 1> 0 | | +-- - (base class BSTScatterTableKernel, struct -// BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8> >) 1> 0 | | | +-- - -// (base class BSTScatterTableTraits, struct BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8>) 1> | | | +-- - 1> 1 | | | +-- - (base class BSTScatterTableDefaultHashPolicy) 1> | | | +-- - 1> | | | (size = 3) 1> 4 | | | m_size -// 1> 8 | | | m_freeCount -// 1>0C | | | m_freeOffset -// 1>10 | | | m_eolPtr -// 1> | | +-- - -// 1>19 | | +-- - (base class BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >) -// 1> | | +-- - -// 1> | | (size = 7) -// 1>20 | | m_entries -// 1> | +-- - -// 1> +-- - -template class Storage, template class Policy, template class Allocator, size_t INITIAL_TABLE_SIZE> -class BSTScatterTable : public BSTScatterTableBase, Allocator>, INITIAL_TABLE_SIZE>> -{ -public: - typedef BSTScatterTableBase, Allocator>, INITIAL_TABLE_SIZE>> Base; - - typedef typename Base::size_type size_type; - typedef typename Base::key_type key_type; - typedef typename Base::value_type value_type; - typedef typename Base::storage_type storage_type; - typedef typename Base::hash_policy hash_policy; - typedef typename Base::allocator_type allocator_type; - typedef typename Base::entry_type entry_type; - typedef typename Base::hash_type hash_type; - - // compiler hints for GCC - using Base::clear; - using Base::empty; - using Base::free_count; - using Base::hash_function; - using Base::initial_table_size; - using Base::key_eq; - using Base::m_entries; - using Base::m_eolPtr; - using Base::m_freeCount; - using Base::m_freeOffset; - using Base::m_size; - using Base::max_size; - using Base::size; - using typename Base::const_iterator; - using typename Base::iterator; - - BSTScatterTable() - : Base() - { - } - BSTScatterTable(const BSTScatterTable& rhs) - : Base() - { - _assign(rhs); - } - BSTScatterTable(BSTScatterTable&& rhs) { _assign(rhs); } - - BSTScatterTable& operator=(const BSTScatterTable& rhs) - { - _assign(rhs); - return *this; - } - BSTScatterTable& operator=(BSTScatterTable&& rhs) - { - _assign(rhs); - return *this; - } - - const_iterator find(const key_type& key) const - { - entry_type* entry = _find(m_entries, get_hash(key), key); - return entry ? const_iterator(this, entry) : this->cend(); - } - iterator find(const key_type& key) - { - entry_type* entry = _find(m_entries, get_hash(key), key); - return entry ? iterator(this, entry) : this->end(); - } - - size_type count(const key_type& key) const { return _find(m_entries, get_hash(key), key) ? 1 : 0; } - - bool insert(const key_type& key, const value_type& lvalue) - { - hash_type hash = get_hash(key); - entry_type* p = nullptr; - - while (!(p = _insert(m_entries, hash, key))) - { - this->_grow_table(); - if (!m_entries || !m_freeCount) - return false; - } - - new (&p->value) value_type(lvalue); - return true; - } - bool insert(const key_type& key, value_type&& rvalue) - { - hash_type hash = get_hash(key); - entry_type* p = nullptr; - - while (!(p = _insert(m_entries, hash, key))) - { - this->_grow_table(); - if (!m_entries || !m_freeCount) - return false; - } - - new (&p->value) value_type(rvalue); - return true; - } - // original implementation - bool insert(const key_type& key, const value_type& value, uint16_t& unk) - { - hash_type hash = get_hash(key); - while (!insert_original(m_entries, hash, key, value, unk)) - { - this->_grow_table(); - } - return true; - } - - inline size_type erase(const key_type& key) { return _erase(m_entries, get_hash(key), key) ? 1 : 0; } - - bool GetAt(key_type key, value_type& value) const - { - entry_type* entry = _find(m_entries, get_hash(key), key); - if (entry) - { - value = entry->value; - return true; - } - return false; - } - - inline bool SetAt(key_type key, const value_type& lvalue) { return insert(key, lvalue); } - - inline bool SetAt(key_type key, value_type&& rvalue) { return insert(key, rvalue); } - - inline bool RemoveAt(key_type key) { return erase(key) != 0; } - - inline void RemoveAll() { clear(); } - - // @members - // BSTScatterTableTraits pad00; // 00 - // size_type m_size; // 04 - // size_type m_freeCount; // 08 - // size_type m_freeOffset; // 0C - // entry_type * m_eolPtr; // 10 - // allocator_type pad14; // 18 - // entry_type * m_entries; // 20 -}; - -// 1>class BSTDefaultScatterTable > size(28) : -// 1> +-- - -// 1> 0 | +-- - (base class BSTScatterTable, struct BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, 8>) -// 1> 0 | | +-- - (base class BSTScatterTableBase, struct BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8> >) 1> 0 | | | +-- - (base class BSTScatterTableKernel, struct -// BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8> >) -// 1> 0 | | | | +-- - (base class BSTScatterTableTraits, struct BSTScatterTableDefaultKVStorage, struct BSTScatterTableDefaultHashPolicy, struct BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >, 8>) 1> | | | | +-- - 1> 1 | | | | +-- - (base class BSTScatterTableDefaultHashPolicy) 1> | | | | +-- - 1> | | | | (size = 3) -// 1> 4 | | | | m_size -// 1> 8 | | | | m_freeCount -// 1>0C | | | | m_freeOffset -// 1>10 | | | | m_eolPtr -// 1> | | | +-- - -// 1>19 | | | +-- - (base class BSTScatterTableHeapAllocator, struct BSTScatterTableDefaultKVStorage> >) -// 1> | | | +-- - -// 1> | | | (size = 7) -// 1>20 | | | m_entries -// 1> | | +-- - -// 1> | +-- - -// 1> +-- - -// 1> -template struct BSTDefaultScatterTable : public BSTScatterTable -{ -}; - -using Test = BSTDefaultScatterTable; - -// static_assert(sizeof(Test) == 0x28); -} // namespace creation diff --git a/Code/client/Games/Fallout4/BSFixedString.cpp b/Code/client/Games/Fallout4/BSFixedString.cpp deleted file mode 100644 index ee36d07aa..000000000 --- a/Code/client/Games/Fallout4/BSFixedString.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include - -#include - -BSFixedString::BSFixedString(const char* acpData) -{ - TP_THIS_FUNCTION(TConstructor, void, BSFixedString, const char*); - - POINTER_FALLOUT4(TConstructor, s_constructor, 640274); - - TiltedPhoques::ThisCall(s_constructor, this, acpData); -} - -BSFixedString::BSFixedString(BSFixedString&& aRhs) noexcept -{ - data = aRhs.data; - aRhs.data = nullptr; -} - -BSFixedString& BSFixedString::operator=(BSFixedString&& aRhs) noexcept -{ - Release(); - - data = aRhs.data; - aRhs.data = nullptr; - - return *this; -} - -void BSFixedString::Release() noexcept -{ - TP_THIS_FUNCTION(TConstructor, void, BSFixedString); - - POINTER_FALLOUT4(TConstructor, s_release, 1204431); - - TiltedPhoques::ThisCall(s_release, this); -} - -void BSFixedString::Set(const char* acpStr) noexcept -{ - TP_THIS_FUNCTION(TSet, void, BSFixedString, const char* acpStr); - - POINTER_FALLOUT4(TSet, s_set, 1064964); - - TiltedPhoques::ThisCall(s_set, this, acpStr); -} - -BSFixedString::~BSFixedString() -{ - // Release(); -} diff --git a/Code/client/Games/Fallout4/BSGraphics/BSGraphicsRenderer.cpp b/Code/client/Games/Fallout4/BSGraphics/BSGraphicsRenderer.cpp deleted file mode 100644 index cb3950790..000000000 --- a/Code/client/Games/Fallout4/BSGraphics/BSGraphicsRenderer.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "BSGraphicsRenderer.h" - -#include "Services/InputService.h" -#include "Systems/RenderSystemD3D11.h" - -#include "World.h" - -// shared resource by launcher -extern HICON g_SharedWindowIcon; - -namespace BSGraphics -{ -namespace -{ -static RenderSystemD3D11* g_sRs = nullptr; -static WNDPROC RealWndProc = nullptr; -static RendererWindow* g_RenderWindow = nullptr; - -static constexpr char kTogetherWindowName[]{"Fallout Together"}; -} // namespace - -RendererWindow* GetMainWindow() -{ - return g_RenderWindow; -} - -bool RendererWindow::IsForeground() -{ - return GetForegroundWindow() == hWnd; -} - -void (*Renderer_Init)(Renderer*, BSGraphics::RendererInitOSData*, const BSGraphics::ApplicationWindowProperties*, BSGraphics::RendererInitReturn*) = nullptr; - -// WNDPROC seems to be part of the renderer -LRESULT CALLBACK Hook_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (InputService::WndProc(hwnd, uMsg, wParam, lParam) != 0) - return 0; - - return RealWndProc(hwnd, uMsg, wParam, lParam); -} - -void Hook_Renderer_Init(BSGraphics::Renderer* self, BSGraphics::RendererInitOSData* aOSData, const BSGraphics::ApplicationWindowProperties* aFBData, BSGraphics::RendererInitReturn* aOut) -{ - // we feed this a shared icon as the resource directory of our former launcher data is already overwritten with the - // game. - aOSData->hIcon = g_SharedWindowIcon; - - // Append our window name. - aOSData->pClassName = kTogetherWindowName; - - RealWndProc = aOSData->pWndProc; - aOSData->pWndProc = Hook_WndProc; - - Renderer_Init(self, aOSData, aFBData, aOut); - - g_sRs = &World::Get().ctx().at(); - // This how the game does it too - g_RenderWindow = &self->Data.RenderWindowA[0]; - - g_sRs->OnDeviceCreation(self->Data.RenderWindowA[0].pSwapChain); -} - -void (*StopTimer)(int) = nullptr; - -// Insert us at the End -void Hook_StopTimer(int type) -{ - if (g_sRs) - g_sRs->OnRender(); - - StopTimer(type); -} - -static TiltedPhoques::Initializer s_viewportHooks( - []() - { - const VersionDbPtr initWindowLoc(193855); - // patch dwStyle in BSGraphics::InitWindows - TiltedPhoques::Put(mem::pointer(initWindowLoc.GetPtr()) + 0xD7 + 1, WS_OVERLAPPEDWINDOW); - - const VersionDbPtr timerLoc(700870); - const VersionDbPtr renderInit(564406); - - TiltedPhoques::SwapCall(mem::pointer(timerLoc.GetPtr()) + 0xE, StopTimer, &Hook_StopTimer); - - Renderer_Init = static_cast(renderInit.GetPtr()); - - // Once we find a proper way to locate it for different versions, go back to swapcall - // TiltedPhoques::SwapCall(mem::pointer(initLoc.GetPtr()) + 0xD1A, Renderer_Init, &Hook_Renderer_Init); - TP_HOOK_IMMEDIATE(&Renderer_Init, &Hook_Renderer_Init); - }); - -} // namespace BSGraphics diff --git a/Code/client/Games/Fallout4/BSGraphics/BSGraphicsRenderer.h b/Code/client/Games/Fallout4/BSGraphics/BSGraphicsRenderer.h deleted file mode 100644 index 54f4ae8d6..000000000 --- a/Code/client/Games/Fallout4/BSGraphics/BSGraphicsRenderer.h +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once - -#include - -namespace BSGraphics -{ - -struct BSCriticalSection -{ - _RTL_CRITICAL_SECTION CriticalSection; -}; - -static_assert(sizeof(BSCriticalSection) == 0x28); - -struct RenderTarget -{ - ID3D11Texture2D* pTexture; - ID3D11Texture2D* pCopyTexture; - ID3D11RenderTargetView* pRTView; - ID3D11ShaderResourceView* pSRView; - ID3D11ShaderResourceView* pCopySRView; - ID3D11UnorderedAccessView* pUAView; -}; - -static_assert(sizeof(RenderTarget) == 0x30); - -struct RendererWindow -{ - HWND__* hWnd; - int iWindowX; - int iWindowY; - int uiWindowWidth; - int uiWindowHeight; - IDXGISwapChain* pSwapChain; - RenderTarget SwapChainRenderTarget; - - bool IsForeground(); -}; - -static_assert(sizeof(RendererWindow) == 0x50); - -struct DepthStencilTarget -{ - ID3D11Texture2D* pTexture; - ID3D11DepthStencilView* pDSView[4]; - ID3D11DepthStencilView* pDSViewReadOnlyDepth[4]; - ID3D11DepthStencilView* pDSViewReadOnlyStencil[4]; - ID3D11DepthStencilView* pDSViewReadOnlyDepthStencil[4]; - ID3D11ShaderResourceView* pSRViewDepth; - ID3D11ShaderResourceView* pSRViewStencil; -}; - -static_assert(sizeof(DepthStencilTarget) == 0x98); - -struct CubeMapRenderTarget -{ - ID3D11Texture2D* pTexture; - ID3D11RenderTargetView* pRTView[6]; - ID3D11ShaderResourceView* pSRView; -}; - -static_assert(sizeof(CubeMapRenderTarget) == 0x40); - -struct __declspec(align(8)) RendererData -{ - void* pShadowState; - BSD3DResourceCreator* D3DResourceCreator; - uint32_t uiAdapter; - DXGI_RATIONAL DesiredRefreshRate; - DXGI_RATIONAL ActualRefreshRate; - DXGI_MODE_SCALING ScaleMode; - DXGI_MODE_SCANLINE_ORDER ScanlineMode; - int bFullScreen; - bool bAppFullScreen; - bool bBorderlessWindow; - bool bVSync; - bool bInitialized; - bool bRequestWindowSizeChange; - unsigned int uiNewWidth; - unsigned int uiNewHeight; - unsigned int uiPresentInterval; - ID3D11Device* pDevice; - ID3D11DeviceContext* pContext; - RendererWindow RenderWindowA[32]; - RenderTarget pRenderTargetsA[101]; - DepthStencilTarget pDepthStencilTargetsA[13]; - CubeMapRenderTarget pCubeMapRenderTargetsA[2]; - BSCriticalSection RendererLock; - const char* pClassName; - HINSTANCE__* hInstance; - bool bNVAPIEnabled; -}; - -static_assert(sizeof(RendererData) == 0x25C0); - -struct Renderer -{ - bool bSkipNextPresent; - void(__fastcall* ResetRenderTargets)(); - RendererData Data; -}; - -static_assert(sizeof(Renderer) == 0x25D0); - -struct RendererInitOSData -{ - HWND__* hWnd; - HINSTANCE__* hInstance; - __int64(__fastcall* pWndProc)(HWND__*, unsigned int, unsigned __int64, __int64); - HICON__* hIcon; - const char* pClassName; - unsigned int uiAdapter; - int bCreateSwapChainRenderTarget; -}; - -static_assert(sizeof(RendererInitOSData) == 0x30); - -struct ApplicationWindowProperties -{ - unsigned int uiWidth; - unsigned int uiHeight; - int iX; - int iY; - unsigned int uiRefreshRate; - bool bFullScreen; - bool bBorderlessWindow; - bool bVSync; - unsigned int uiPresentInterval; -}; - -static_assert(sizeof(ApplicationWindowProperties) == 0x1C); - -struct RendererInitReturn -{ - HWND__* hwnd; -}; - -static_assert(sizeof(RendererInitReturn) == 0x8); - -RendererWindow* GetMainWindow(); - -} // namespace BSGraphics diff --git a/Code/client/Games/Fallout4/BSInput/BSInputDeviceManager.cpp b/Code/client/Games/Fallout4/BSInput/BSInputDeviceManager.cpp deleted file mode 100644 index 1ed4bfa27..000000000 --- a/Code/client/Games/Fallout4/BSInput/BSInputDeviceManager.cpp +++ /dev/null @@ -1,43 +0,0 @@ - -#include - -struct BSInputDeviceManager; - -void (*BSInputDeviceManager_PollInputDevices)(BSInputDeviceManager*, float) = nullptr; - -void Hook_BSInputDeviceManager_PollInputDevices(BSInputDeviceManager* inputDeviceMgr, float afDelta) -{ - if (!BSGraphics::GetMainWindow()->IsForeground()) - return; - - BSInputDeviceManager_PollInputDevices(inputDeviceMgr, afDelta); -} - -BOOL ClipCursor_H(const RECT*) -{ - RECT realRect{}; - GetWindowRect(BSGraphics::GetMainWindow()->hWnd, &realRect); - return ClipCursor(&realRect); -} - -static TiltedPhoques::Initializer s_initInputDeviceManager( - []() - { - const VersionDbPtr pollInputDevices(1328120); - - BSInputDeviceManager_PollInputDevices = static_cast(pollInputDevices.GetPtr()); - - TP_HOOK_IMMEDIATE(&BSInputDeviceManager_PollInputDevices, &Hook_BSInputDeviceManager_PollInputDevices); - - // TODO: move to a proper place. - const VersionDbPtr updateGameCursor(847267); - // disable the game being able to force the OS cursor - TiltedPhoques::Put(updateGameCursor.Get() + 0xB1, 0xEB); - - // no game scaled window bounds. - TiltedPhoques::Put(updateGameCursor.Get() + 0xE1, 0xE990); - - // proper coords. - TiltedPhoques::PutCall(updateGameCursor.Get() + 0x27A, ClipCursor_H); - TiltedPhoques::Put(updateGameCursor.Get() + 0x27A + 5, 0x90); - }); diff --git a/Code/client/Games/Fallout4/Components/BGSAttachParentArray.h b/Code/client/Games/Fallout4/Components/BGSAttachParentArray.h deleted file mode 100644 index 771aa1d16..000000000 --- a/Code/client/Games/Fallout4/Components/BGSAttachParentArray.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -struct BGSAttachParentArray : BaseFormComponent -{ - virtual ~BGSAttachParentArray(); - - void* arr; - uint32_t count; - uint32_t pad; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSAttackDataForm.h b/Code/client/Games/Fallout4/Components/BGSAttackDataForm.h deleted file mode 100644 index a9b18a6c8..000000000 --- a/Code/client/Games/Fallout4/Components/BGSAttackDataForm.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -struct BGSAttackDataMap : NiRefObject -{ - virtual ~BGSAttackDataMap(); -}; - -struct BGSAttackDataForm : BaseFormComponent -{ - virtual ~BGSAttackDataForm(); - - BGSAttackDataMap* attackDataMap; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSCharacterTint.h b/Code/client/Games/Fallout4/Components/BGSCharacterTint.h deleted file mode 100644 index 9601bd303..000000000 --- a/Code/client/Games/Fallout4/Components/BGSCharacterTint.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -struct BGSCharacterTint -{ - struct Entry - { - virtual ~Entry(); - virtual void sub_1(); - virtual void sub_2(); - virtual void sub_3(); - virtual void sub_4(); - virtual void sub_5(); - virtual void sub_6(); - - void* unk8; - uint16_t unk10; // 10 - type maybe ? copied from ctor - uint8_t unk12; // 12 - set to 0 in ctor - }; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSDestructibleObjectForm.h b/Code/client/Games/Fallout4/Components/BGSDestructibleObjectForm.h deleted file mode 100644 index 6f0c60a81..000000000 --- a/Code/client/Games/Fallout4/Components/BGSDestructibleObjectForm.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -struct TESForm; - -struct BGSDestructibleObjectForm : BaseFormComponent -{ - virtual ~BGSDestructibleObjectForm(); - - TESForm* form; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSForcedLocRefType.h b/Code/client/Games/Fallout4/Components/BGSForcedLocRefType.h deleted file mode 100644 index 3b46d5d02..000000000 --- a/Code/client/Games/Fallout4/Components/BGSForcedLocRefType.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -struct ActorValueInfo; - -struct BGSForcedLocRefType : BaseFormComponent -{ - virtual ~BGSForcedLocRefType(); - - ActorValueInfo** values; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSKeywordForm.h b/Code/client/Games/Fallout4/Components/BGSKeywordForm.h deleted file mode 100644 index da213d0eb..000000000 --- a/Code/client/Games/Fallout4/Components/BGSKeywordForm.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -struct BGSKeyword; - -struct BGSKeywordForm : BaseFormComponent -{ - virtual ~BGSKeywordForm(); - - void* vtbl2; // 8 - BGSKeyword** keywords; // 10 - uint32_t count; // 18 - uint32_t pad; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSModelMaterialSwap.h b/Code/client/Games/Fallout4/Components/BGSModelMaterialSwap.h deleted file mode 100644 index fc6e0f46c..000000000 --- a/Code/client/Games/Fallout4/Components/BGSModelMaterialSwap.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -struct BGSModelMaterialSwap : TESModel -{ - virtual ~BGSModelMaterialSwap(); - - uint8_t pad8[0x20 - 0x8]; -}; - -static_assert(sizeof(BGSModelMaterialSwap) == 0x20); diff --git a/Code/client/Games/Fallout4/Components/BGSNativeTerminalForm.h b/Code/client/Games/Fallout4/Components/BGSNativeTerminalForm.h deleted file mode 100644 index 2b71af5e6..000000000 --- a/Code/client/Games/Fallout4/Components/BGSNativeTerminalForm.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -struct BGSNativeTerminalForm : BaseFormComponent -{ - virtual ~BGSNativeTerminalForm(); - - void* unk8; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSOverridePackCollection.h b/Code/client/Games/Fallout4/Components/BGSOverridePackCollection.h deleted file mode 100644 index 36624322e..000000000 --- a/Code/client/Games/Fallout4/Components/BGSOverridePackCollection.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -struct BGSOverridePackCollection : BaseFormComponent -{ - virtual ~BGSOverridePackCollection(); - - void* packs[5]; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSPerkRankArray.h b/Code/client/Games/Fallout4/Components/BGSPerkRankArray.h deleted file mode 100644 index dab482739..000000000 --- a/Code/client/Games/Fallout4/Components/BGSPerkRankArray.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -struct TESForm; - -struct BGSPerkRankArray : BaseFormComponent -{ - virtual ~BGSPerkRankArray(); - - TESForm** perks; // 8 - uint32_t count; // 10 - uint32_t pad; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSPropertySheet.h b/Code/client/Games/Fallout4/Components/BGSPropertySheet.h deleted file mode 100644 index d0662744c..000000000 --- a/Code/client/Games/Fallout4/Components/BGSPropertySheet.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -struct BGSPropertySheet : BaseFormComponent -{ - virtual ~BGSPropertySheet(); - - void* unk; -}; diff --git a/Code/client/Games/Fallout4/Components/BGSSkinForm.h b/Code/client/Games/Fallout4/Components/BGSSkinForm.h deleted file mode 100644 index b3b3c03d9..000000000 --- a/Code/client/Games/Fallout4/Components/BGSSkinForm.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -struct TESForm; - -struct BGSSkinForm : BaseFormComponent -{ - virtual ~BGSSkinForm(); - - TESForm* form; -}; diff --git a/Code/client/Games/Fallout4/Components/BaseFormComponent.h b/Code/client/Games/Fallout4/Components/BaseFormComponent.h deleted file mode 100644 index 3c08e0ce2..000000000 --- a/Code/client/Games/Fallout4/Components/BaseFormComponent.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -struct BaseFormComponent -{ - virtual ~BaseFormComponent(); - - virtual void Init(); - virtual void ReleaseRefs(); - virtual void CopyFromBase(BaseFormComponent* apBase); - virtual void sub_4(); - virtual void sub_5(); - virtual void sub_6(); -}; diff --git a/Code/client/Games/Fallout4/Components/TESAIForm.h b/Code/client/Games/Fallout4/Components/TESAIForm.h deleted file mode 100644 index 066617084..000000000 --- a/Code/client/Games/Fallout4/Components/TESAIForm.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -struct TESAIForm : BaseFormComponent -{ - uint8_t unk8[0x28 - 0x8]; -}; - -static_assert(sizeof(TESAIForm) == 0x28); diff --git a/Code/client/Games/Fallout4/Components/TESActorBaseData.h b/Code/client/Games/Fallout4/Components/TESActorBaseData.h deleted file mode 100644 index 6a32c1a43..000000000 --- a/Code/client/Games/Fallout4/Components/TESActorBaseData.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include - -struct BGSVoiceType; - -struct TESActorBaseData : BaseFormComponent -{ - virtual ~TESActorBaseData(); - virtual void sub_7(); - virtual void sub_8(); - virtual void sub_9(); - - struct alignas(sizeof(void*)) FactionInfo - { - struct TESFaction* faction; - int8_t rank; - }; - - enum BaseFlags - { - IS_ESSENTIAL = 1 << 1, - }; - - // TODO: ft - // idk if this is correct - bool IsEssential() const noexcept { return flags & BaseFlags::IS_ESSENTIAL; } - void SetEssential(bool aSet) noexcept - { - if (aSet) - flags |= BaseFlags::IS_ESSENTIAL; - else - flags &= ~BaseFlags::IS_ESSENTIAL; - } - - uint64_t flags; - uint8_t unk10[0x28 - 0x10]; - BGSVoiceType* voiceType; - TESForm* owner; - uint8_t unk30[0x50 - 0x38]; - GameArray factions; -}; - -static_assert(sizeof(TESActorBaseData) == 0x68); -static_assert(offsetof(TESActorBaseData, owner) == 0x30); -static_assert(offsetof(TESActorBaseData, factions) == 0x50); diff --git a/Code/client/Games/Fallout4/Components/TESContainer.h b/Code/client/Games/Fallout4/Components/TESContainer.h deleted file mode 100644 index c29073468..000000000 --- a/Code/client/Games/Fallout4/Components/TESContainer.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -struct TESForm; - -struct TESContainer : BaseFormComponent -{ - struct Entry - { - uint32_t count; - TESForm* form; - void* data; - }; - - Entry** entries; - uint32_t count; -}; - -static_assert(sizeof(TESContainer) == 0x18); diff --git a/Code/client/Games/Fallout4/Components/TESFullName.h b/Code/client/Games/Fallout4/Components/TESFullName.h deleted file mode 100644 index 09c5ac3cd..000000000 --- a/Code/client/Games/Fallout4/Components/TESFullName.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -struct TESFullName : BaseFormComponent -{ - virtual ~TESFullName(); - - virtual void sub_7(); - virtual void sub_8(); - - BSFixedString value; -}; diff --git a/Code/client/Games/Fallout4/Components/TESLeveledList.h b/Code/client/Games/Fallout4/Components/TESLeveledList.h deleted file mode 100644 index e5804800b..000000000 --- a/Code/client/Games/Fallout4/Components/TESLeveledList.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include - -struct TESForm; - -struct TESLeveledList : BaseFormComponent -{ - virtual ~TESLeveledList(); - - struct Entry - { - TESForm* form; - void* unkPtr; - uint16_t minLevel; - uint16_t maxLevel; - uint8_t unk14; // Specific to fallout 4 - }; - - struct Content - { - uint64_t length; // it's set to the size of the allocated array for some reason - Entry entries[0]; - }; - - uint8_t pad8[0x18 - 0x8]; - Content* content; - uint8_t pad20[0x28 - 0x20]; - bool hasData; - uint8_t count; -}; - -static_assert(sizeof(TESLeveledList::Entry) == 0x18); -static_assert(offsetof(TESLeveledList::Entry, unk14) == 0x14); -static_assert(offsetof(TESLeveledList, content) == 0x18); -static_assert(offsetof(TESLeveledList, count) == 0x29); -static_assert(offsetof(TESLeveledList, hasData) == 0x28); -static_assert(sizeof(TESLeveledList) == 0x30); diff --git a/Code/client/Games/Fallout4/Components/TESModel.h b/Code/client/Games/Fallout4/Components/TESModel.h deleted file mode 100644 index 1a85fa531..000000000 --- a/Code/client/Games/Fallout4/Components/TESModel.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -struct TESModel : BaseFormComponent -{ - virtual ~TESModel(); - - BSFixedString cModel; - void* pTexturesA; - void* pMaterialsA; - uint32_t* pAddonsA; - uint8_t uiNumTextures; - uint8_t uiNumTexturesSRGB; - uint8_t uiNumAddons; - uint8_t NumMaterials; - uint8_t cFlags; -}; - -static_assert(sizeof(TESModel) == 0x30); diff --git a/Code/client/Games/Fallout4/Components/TESRaceForm.h b/Code/client/Games/Fallout4/Components/TESRaceForm.h deleted file mode 100644 index 54a6720fe..000000000 --- a/Code/client/Games/Fallout4/Components/TESRaceForm.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -struct TESRace; - -struct TESRaceForm : BaseFormComponent -{ - virtual ~TESRaceForm(); - - TESRace* race; -}; diff --git a/Code/client/Games/Fallout4/Components/TESSpellList.cpp b/Code/client/Games/Fallout4/Components/TESSpellList.cpp deleted file mode 100644 index f4457e417..000000000 --- a/Code/client/Games/Fallout4/Components/TESSpellList.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -#include -#include - -void TESSpellList::Initialize() -{ - if (lists != nullptr) - return; - - lists = Memory::New(); -} diff --git a/Code/client/Games/Fallout4/Components/TESSpellList.h b/Code/client/Games/Fallout4/Components/TESSpellList.h deleted file mode 100644 index 09f0dd0d5..000000000 --- a/Code/client/Games/Fallout4/Components/TESSpellList.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -struct TESForm; -struct TESSpellList : BaseFormComponent -{ - struct Lists - { - void** spells; - TESForm** unk4; - void** shouts; - uint32_t spellCount; - uint32_t unk4Count; - uint32_t shoultCount; - }; - - Lists* lists; - - void Initialize(); -}; - -static_assert(sizeof(TESSpellList) == 0x10); diff --git a/Code/client/Games/Fallout4/DefaultObjectManager.cpp b/Code/client/Games/Fallout4/DefaultObjectManager.cpp deleted file mode 100644 index 006f7eaf8..000000000 --- a/Code/client/Games/Fallout4/DefaultObjectManager.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "DefaultObjectManager.h" - -DefaultObjectManager& DefaultObjectManager::Get() -{ - using TGetDefaultObjectManager = DefaultObjectManager&(); - POINTER_FALLOUT4(TGetDefaultObjectManager, GetDefaultObjectManager, 484975); - return GetDefaultObjectManager(); -} diff --git a/Code/client/Games/Fallout4/DefaultObjectManager.h b/Code/client/Games/Fallout4/DefaultObjectManager.h deleted file mode 100644 index 2d1ecbc18..000000000 --- a/Code/client/Games/Fallout4/DefaultObjectManager.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -struct DefaultObjectManager -{ - static DefaultObjectManager& Get(); -}; diff --git a/Code/client/Games/Fallout4/Effects/ActiveEffect.h b/Code/client/Games/Fallout4/Effects/ActiveEffect.h deleted file mode 100644 index 0670c717b..000000000 --- a/Code/client/Games/Fallout4/Effects/ActiveEffect.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -struct ActiveEffect -{ - virtual void sub_0(); - virtual void sub_1(); - virtual void sub_2(); - virtual void sub_3(); - virtual void sub_4(); - virtual void sub_5(); - virtual void sub_6(); - virtual void sub_7(); - virtual void sub_8(); - virtual void sub_9(); - virtual void sub_A(); - virtual void sub_B(); - virtual void sub_C(); - virtual void sub_D(); - virtual void sub_E(); - virtual void sub_F(); - virtual void sub_10(); - virtual void sub_11(); - virtual void sub_12(); - virtual void sub_13(); - virtual void sub_14(); - virtual void sub_15(); - virtual void sub_16(); - virtual void sub_17(); - virtual void sub_18(); - - char pad_0008[112]; - float effectValue; - char pad_007C[4]; -}; -static_assert(sizeof(ActiveEffect) == 0x80); diff --git a/Code/client/Games/Fallout4/Effects/ValueModifierEffect.h b/Code/client/Games/Fallout4/Effects/ValueModifierEffect.h deleted file mode 100644 index c0f5db077..000000000 --- a/Code/client/Games/Fallout4/Effects/ValueModifierEffect.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -struct Actor; -struct ActorValueInfo; - -struct ValueModifierEffect : public ActiveEffect -{ - virtual void sub_19(); - virtual void sub_1A(); - virtual void sub_1B(); - virtual void sub_1C(); - virtual void sub_1D(); - virtual void sub_1E(); - virtual void sub_1F(); - virtual void ApplyActorEffect(Actor* actor, float effectValue, unsigned int unk1); - - char pad_0080[16]; - uint32_t actorValueIndex; - char pad_0094[4]; - ActorValueInfo* actorValueInfo; -}; -static_assert(sizeof(ValueModifierEffect) == 0xA0); diff --git a/Code/client/Games/Fallout4/EquipManager.cpp b/Code/client/Games/Fallout4/EquipManager.cpp deleted file mode 100644 index f6e923f55..000000000 --- a/Code/client/Games/Fallout4/EquipManager.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include - -#include -#include -#include -#include - -#include - -#include - -struct BGSEquipSlot; - -struct ObjectEquipParams -{ - uint32_t uiStackID; - uint32_t uiNumber; - const BGSEquipSlot* pEquipSlot; - const BGSEquipSlot* pSlotBeingReplaced; - bool bQueueEquip; - bool bForceEquip; - bool bPlayEquipSounds; - bool bApplyNow; - bool bLocked; - bool bExtraWasDeleted; -}; - -TP_THIS_FUNCTION(TEquip, void*, EquipManager, Actor* apActor, BGSObjectInstance* apItem, ObjectEquipParams& arParams); -TP_THIS_FUNCTION(TUnEquip, void*, EquipManager, Actor* apActor, BGSObjectInstance* apItem, ObjectEquipParams& arParams); - -TEquip* RealEquip = nullptr; -TUnEquip* RealUnEquip = nullptr; - -EquipManager* EquipManager::Get() noexcept -{ - POINTER_FALLOUT4(EquipManager*, s_singleton, 1174341); - - return *s_singleton.Get(); -} - -bool EquipManager::EquipObject(Actor* apActor, BGSObjectInstance& arObject, uint32_t auiStackID, uint32_t auiNumber, const BGSEquipSlot* apSlot, bool abQueueEquip, bool abForceEquip, bool abPlaySounds, bool abApplyNow, bool abLocked) -{ - spdlog::warn("EquipObject {:X}", arObject.pObject->formID); - - TP_THIS_FUNCTION(TEquipObject, bool, EquipManager, Actor* apActor, BGSObjectInstance& arObject, uint32_t auiStackID, uint32_t auiNumber, const BGSEquipSlot* apSlot, bool abQueueEquip, bool abForceEquip, bool abPlaySounds, bool abApplyNow, bool abLocked); - POINTER_FALLOUT4(TEquipObject, equipObject, 988030); - - ScopedEquipOverride _; - - return TiltedPhoques::ThisCall(equipObject, this, apActor, arObject, auiStackID, auiNumber, apSlot, abQueueEquip, abForceEquip, abPlaySounds, abApplyNow, abLocked); -} - -bool EquipManager::UnequipObject(Actor* apActor, BGSObjectInstance& arObject, uint32_t auiNumber, const BGSEquipSlot* apSlot, uint32_t auiStackID, bool abQueueEquip, bool abForceEquip, bool abPlaySounds, bool abApplyNow, const BGSEquipSlot* apSlotBeingReplaced) -{ - // TODO: the real unequip happens in some kind of loop over slots. - // Maybe in fallout 4, multiple items can be on many slots? - // If so, just call the papyrus function instead, Actor::UnequipItem(). - // Maybe the equipped slot index should be sent even? (see BGSInventoryItem enum) - - TP_THIS_FUNCTION(TUnequipObject, bool, EquipManager, Actor* apActor, BGSObjectInstance& arObject, uint32_t auiNumber, const BGSEquipSlot* apSlot, uint32_t auiStackID, bool abQueueEquip, bool abForceEquip, bool abPlaySounds, bool abApplyNow, const BGSEquipSlot* apSlotBeingReplaced); - POINTER_FALLOUT4(TUnequipObject, unequipObject, 1292494); - - ScopedEquipOverride _; - - return TiltedPhoques::ThisCall(unequipObject, this, apActor, arObject, auiNumber, apSlot, auiStackID, abQueueEquip, abForceEquip, abPlaySounds, abApplyNow, apSlotBeingReplaced); -} - -void* TP_MAKE_THISCALL(EquipHook, EquipManager, Actor* apActor, BGSObjectInstance* apItem, ObjectEquipParams& arParams) -{ - if (!apActor) - return nullptr; - - const auto pExtension = apActor->GetExtension(); - if (pExtension->IsRemote() && !ScopedEquipOverride::IsOverriden()) - { - spdlog::info("Actor[{:X}]::Equip(), item form id: {:X}", apActor->formID, apItem->pObject->formID); - return nullptr; - } - - if (pExtension->IsLocal()) - { - EquipmentChangeEvent evt{}; - evt.ActorId = apActor->formID; - evt.Count = arParams.uiNumber; - evt.ItemId = apItem->pObject->formID; - // TODO: equip slot stuff - // evt.EquipSlotId - - World::Get().GetRunner().Trigger(evt); - } - - ScopedUnequipOverride _; - - return TiltedPhoques::ThisCall(RealEquip, apThis, apActor, apItem, arParams); -} - -void* TP_MAKE_THISCALL(UnEquipHook, EquipManager, Actor* apActor, BGSObjectInstance* apItem, ObjectEquipParams& arParams) -{ - if (!apActor) - return nullptr; - - const auto pExtension = apActor->GetExtension(); - if (pExtension->IsRemote() && !ScopedEquipOverride::IsOverriden()) - return nullptr; - - if (pExtension->IsLocal()) - { - EquipmentChangeEvent evt{}; - evt.ActorId = apActor->formID; - evt.Count = arParams.uiNumber; - evt.ItemId = apItem->pObject->formID; - evt.Unequip = true; - // TODO: equip slot stuff - // evt.EquipSlotId - - World::Get().GetRunner().Trigger(evt); - } - - return TiltedPhoques::ThisCall(RealUnEquip, apThis, apActor, apItem, arParams); -} - -static TiltedPhoques::Initializer s_equipmentHooks( - []() - { - POINTER_FALLOUT4(TEquip, s_equipFunc, 1474879); - POINTER_FALLOUT4(TUnEquip, s_unequipFunc, 1265293); - - RealUnEquip = s_unequipFunc.Get(); - RealEquip = s_equipFunc.Get(); - - TP_HOOK(&RealUnEquip, UnEquipHook); - TP_HOOK(&RealEquip, EquipHook); - }); diff --git a/Code/client/Games/Fallout4/EquipManager.h b/Code/client/Games/Fallout4/EquipManager.h deleted file mode 100644 index 09cce1924..000000000 --- a/Code/client/Games/Fallout4/EquipManager.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -struct TESForm; -struct ExtraDataList; -struct Actor; -struct BGSObjectInstance; -struct BGSEquipSlot; - -struct EquipManager -{ - static EquipManager* Get() noexcept; - - bool EquipObject(Actor* apActor, BGSObjectInstance& arObject, uint32_t auiStackID, uint32_t auiNumber, const BGSEquipSlot* apSlot, bool abQueueEquip, bool abForceEquip, bool abPlaySounds, bool abApplyNow, bool abLocked); - bool UnequipObject(Actor* apActor, BGSObjectInstance& arObject, uint32_t auiNumber, const BGSEquipSlot* apSlot, uint32_t auiStackID, bool abQueueEquip, bool abForceEquip, bool abPlaySounds, bool abApplyNow, const BGSEquipSlot* apSlotBeingReplaced); -}; diff --git a/Code/client/Games/Fallout4/Events.h b/Code/client/Games/Fallout4/Events.h deleted file mode 100644 index c0f7b945a..000000000 --- a/Code/client/Games/Fallout4/Events.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -struct BSMovementDataChangedEvent -{ -}; - -struct BSTransformDeltaEvent -{ -}; - -struct BSSubGraphActivationUpdate -{ -}; - -struct bhkCharacterMoveFinishEvent -{ -}; - -struct bhkNonSupportContactEvent -{ -}; - -struct bhkCharacterStateChangeEvent -{ -}; diff --git a/Code/client/Games/Fallout4/Events/EventDispacther.cpp b/Code/client/Games/Fallout4/Events/EventDispacther.cpp deleted file mode 100644 index 936f2a044..000000000 --- a/Code/client/Games/Fallout4/Events/EventDispacther.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include - -#include - -namespace details -{ -void InternalRegisterSink(void* apEventDispatcher, void* apSink) noexcept -{ - TP_THIS_FUNCTION(TRegisterSink, void, void, void* apSink); - - // GameVM ctor RegisterSinks - POINTER_FALLOUT4(TRegisterSink, s_registerSink, 57457); - - TiltedPhoques::ThisCall(s_registerSink, apEventDispatcher, apSink); -} - -void InternalUnRegisterSink(void* apEventDispatcher, void* apSink) noexcept -{ - TP_THIS_FUNCTION(TUnRegisterSink, void, void, void* apSink); - - // GameVM dtor UnRegisterSinks - POINTER_FALLOUT4(TUnRegisterSink, s_unregisterSink, 1089538); - - TiltedPhoques::ThisCall(s_unregisterSink, apEventDispatcher, apSink); -} - -void InternalPushEvent(void* apEventDispatcher, void* apEvent) noexcept -{ - TP_THIS_FUNCTION(TPushEvent, void, void, void* apSink); - - // "Failed to setup moving reference because it has no parent cell or no 3D" last function's content before the call - POINTER_FALLOUT4(TPushEvent, s_pushEvent, 646456); - - TiltedPhoques::ThisCall(s_pushEvent, apEventDispatcher, apEvent); -} -} // namespace details diff --git a/Code/client/Games/Fallout4/Events/EventDispatcher.h b/Code/client/Games/Fallout4/Events/EventDispatcher.h deleted file mode 100644 index 621688ce6..000000000 --- a/Code/client/Games/Fallout4/Events/EventDispatcher.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -#include - -template struct BSTEventSink; - -// Very nasty work around to avoid template code duplication -namespace details -{ -void InternalRegisterSink(void* apEventDispatcher, void* apSink) noexcept; -void InternalUnRegisterSink(void* apEventDispatcher, void* apSink) noexcept; -void InternalPushEvent(void* apEventDispatcher, void* apEvent) noexcept; -} // namespace details - -template struct EventDispatcher -{ - void RegisterSink(BSTEventSink* apSink) noexcept { details::InternalRegisterSink(reinterpret_cast(this), reinterpret_cast(apSink)); } - - void UnRegisterSink(BSTEventSink* apSink) noexcept { details::InternalUnRegisterSink(reinterpret_cast(this), reinterpret_cast(apSink)); } - - void PushEvent(const T* apEvent) noexcept { details::InternalPushEvent(reinterpret_cast(this), reinterpret_cast(apEvent)); } - - uint8_t pad0[0x58]; -}; - -// Sadly fallout4 doesn't have a clean manager like skyrim - -struct TESQuestStartStopEvent -{ - uint32_t formId; -}; - -struct TESQuestStageItemDoneEvent -{ - uint32_t formId; - uint16_t stageId; - bool unk; -}; - -struct TESQuestStageEvent -{ - void* callback; - uint32_t formId; - uint16_t stageId; - bool bUnk; -}; - -struct TESActivateEvent -{ - TESObjectREFR* object; -}; - -struct TESLoadGameEvent -{ -}; - -struct BGSInventoryListEvent -{ - enum Type : int16_t - { - AddStack = 0x0, - ChangedStack = 0x1, - AddNewItem = 0x2, - RemoveItem = 0x3, - Clear = 0x4, - UpdateWeight = 0x5, - }; - - struct Event - { - Type ChangeType; - BSPointerHandle hOwner; - TESBoundObject* pObjAffected; - uint32_t uiCount; - uint32_t uiStackId; - }; -}; - -// TODO: idk why, but it can't find POINTER_FALLOUT4 -#define POINTER_FALLOUT4(className, variableName, ...) static VersionDbPtr variableName(__VA_ARGS__) - -#define DECLARE_DISPATCHER(name, id) \ - inline EventDispatcher* GetEventDispatcher_##name() \ - { \ - using TGetDispatcher = EventDispatcher*(); \ - POINTER_FALLOUT4(TGetDispatcher, s_getEventDispatcher, id); \ - return s_getEventDispatcher.Get()(); \ - }; - -DECLARE_DISPATCHER(TESQuestStartStopEvent, 1404316); -DECLARE_DISPATCHER(TESQuestStageItemDoneEvent, 181652); -DECLARE_DISPATCHER(TESQuestStageEvent, 540906); -DECLARE_DISPATCHER(TESActivateEvent, 166231); -DECLARE_DISPATCHER(TESLoadGameEvent, 823571); diff --git a/Code/client/Games/Fallout4/ExtraData/ExtraData.h b/Code/client/Games/Fallout4/ExtraData/ExtraData.h deleted file mode 100644 index 002b05109..000000000 --- a/Code/client/Games/Fallout4/ExtraData/ExtraData.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -struct TESObjectREFR; -struct TESForm; - -enum class ExtraDataType : uint8_t -{ - None = 0, - LeveledCreature = 0x2D, - Faction = 0x5B, - Soul = 0x9C, -}; - -struct BSExtraData -{ - inline static constexpr auto eExtraData = ExtraDataType::None; - - virtual ~BSExtraData() = 0; - // TODO: this is different for fallout 4 it seems - virtual ExtraDataType GetType() const noexcept = 0; - - BSExtraData* next{}; - uint16_t usFlags; - ExtraDataType type; -}; - -static_assert(offsetof(BSExtraData, type) == 0x12); -static_assert(sizeof(BSExtraData) == 0x18); diff --git a/Code/client/Games/Fallout4/ExtraData/ExtraDataList.cpp b/Code/client/Games/Fallout4/ExtraData/ExtraDataList.cpp deleted file mode 100644 index f03bc2564..000000000 --- a/Code/client/Games/Fallout4/ExtraData/ExtraDataList.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "ExtraDataList.h" - -ExtraDataList* ExtraDataList::New() noexcept -{ - ExtraDataList* pExtraDataList = Memory::Allocate(); - - pExtraDataList->ExtraData.pHead = nullptr; - pExtraDataList->ExtraData.ppTail = nullptr; - pExtraDataList->ExtraData.pFlags = static_cast(Memory::Allocate(0x1B)); - memset(pExtraDataList->ExtraData.pFlags, 0, 0x1B); - - pExtraDataList->ExtraRWLock.m_counter = pExtraDataList->ExtraRWLock.m_tid = 0; - - return pExtraDataList; -} - -bool ExtraDataList::Contains(ExtraDataType aType) const -{ - BSScopedLock _(ExtraRWLock); - - if (ExtraData.pFlags) - { - const uint32_t value = static_cast(aType); - const uint32_t index = value >> 3; - - if (index >= 0x1B) - return false; - - const uint8_t element = ExtraData.pFlags[index]; - - return (element >> (value % 8)) & 1; - } - - return false; -} - -BSExtraData* ExtraDataList::GetByType(ExtraDataType aType) const -{ - BSScopedLock _(ExtraRWLock); - - if (!Contains(aType)) - return nullptr; - - BSExtraData* pEntry = ExtraData.pHead; - while (pEntry != nullptr && pEntry->type != aType) - { - pEntry = pEntry->next; - } - - return pEntry; -} - -bool ExtraDataList::Add(ExtraDataType aType, BSExtraData* apNewData) -{ - if (Contains(aType)) - return false; - - BSScopedLock _(ExtraRWLock); - - BSExtraData* pNext = ExtraData.pHead; - ExtraData.pHead = apNewData; - apNewData->next = pNext; - SetType(aType, false); - - return true; -} - -uint32_t ExtraDataList::GetCount() const -{ - uint32_t count = 0; - - BSExtraData* pNext = ExtraData.pHead; - while (pNext) - { - count++; - pNext = pNext->next; - } - - return count; -} - -void ExtraDataList::SetType(ExtraDataType aType, bool aClear) -{ - uint32_t index = static_cast(aType) >> 3; - uint8_t bitmask = 1 << (static_cast(aType) % 8); - uint8_t& flag = ExtraData.pFlags[index]; - if (aClear) - flag &= ~bitmask; - else - flag |= bitmask; -} diff --git a/Code/client/Games/Fallout4/ExtraData/ExtraDataList.h b/Code/client/Games/Fallout4/ExtraData/ExtraDataList.h deleted file mode 100644 index 4a0a93aad..000000000 --- a/Code/client/Games/Fallout4/ExtraData/ExtraDataList.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "ExtraData.h" - -struct BaseExtraList -{ - BSExtraData* pHead; - BSExtraData** ppTail; - uint8_t* pFlags; // pFlags is 0x1B large -}; - -struct ExtraDataList : BSIntrusiveRefCounted -{ - static ExtraDataList* New() noexcept; - - bool Contains(ExtraDataType aType) const; - void Set(ExtraDataType aType, bool aSet); - - bool Add(ExtraDataType aType, BSExtraData* apNewData); - bool Remove(ExtraDataType aType, BSExtraData* apNewData); - - uint32_t GetCount() const; - - void SetType(ExtraDataType aType, bool aClear); - BSExtraData* GetByType(ExtraDataType type) const; - - BaseExtraList ExtraData; - mutable BSRecursiveLock ExtraRWLock; // is BSReadWriteLock -}; diff --git a/Code/client/Games/Fallout4/ExtraData/ExtraFactionChanges.h b/Code/client/Games/Fallout4/ExtraData/ExtraFactionChanges.h deleted file mode 100644 index fcb5cfe26..000000000 --- a/Code/client/Games/Fallout4/ExtraData/ExtraFactionChanges.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "ExtraData.h" - -struct TESFaction; - -struct ExtraFactionChanges : BSExtraData -{ - virtual ~ExtraFactionChanges(); - - struct Entry - { - TESFaction* faction; - int8_t rank; - }; - - bool bRemoveCrimeFaction; - GameArray entries; -}; - -static_assert(sizeof(ExtraFactionChanges::Entry) == 0x10); -static_assert(offsetof(ExtraFactionChanges, entries) == 0x20); diff --git a/Code/client/Games/Fallout4/ExtraData/ExtraLeveledCreature.h b/Code/client/Games/Fallout4/ExtraData/ExtraLeveledCreature.h deleted file mode 100644 index 28e84902f..000000000 --- a/Code/client/Games/Fallout4/ExtraData/ExtraLeveledCreature.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "ExtraData.h" - -struct TESNPC; - -struct ExtraLeveledCreature : BSExtraData -{ - virtual ~ExtraLeveledCreature(); - - uint8_t unk20[0x68]; // This buffer is copied like a pod -}; - -static_assert(sizeof(ExtraLeveledCreature) == 0x88); -static_assert(offsetof(ExtraLeveledCreature, unk20) == 0x20); diff --git a/Code/client/Games/Fallout4/ExtraData/ExtraSoul.h b/Code/client/Games/Fallout4/ExtraData/ExtraSoul.h deleted file mode 100644 index a6145df54..000000000 --- a/Code/client/Games/Fallout4/ExtraData/ExtraSoul.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "ExtraData.h" - -enum class SOUL_LEVEL -{ - SOUL_NONE = 0x0, - SOUL_PETTY = 0x1, - SOUL_LESSER = 0x2, - SOUL_COMMON = 0x3, - SOUL_GREATER = 0x4, - SOUL_GRAND = 0x5, - SOUL_LEVEL_COUNT = 0x6, -}; - -struct ExtraSoul : BSExtraData -{ - inline static constexpr auto eExtraData = ExtraDataType::Soul; - - SOUL_LEVEL cSoul{}; -}; - -static_assert(sizeof(ExtraSoul) == 0x20); diff --git a/Code/client/Games/Fallout4/FormManager.cpp b/Code/client/Games/Fallout4/FormManager.cpp deleted file mode 100644 index 56d28319c..000000000 --- a/Code/client/Games/Fallout4/FormManager.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -#include - -FormManager* FormManager::Get() -{ - POINTER_FALLOUT4(FormManager*, s_instance, 711559); - return *(s_instance.Get()); -} diff --git a/Code/client/Games/Fallout4/FormManager.h b/Code/client/Games/Fallout4/FormManager.h deleted file mode 100644 index 8cb0ea2bb..000000000 --- a/Code/client/Games/Fallout4/FormManager.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -struct TESQuest; - -struct FormManager -{ - static FormManager* Get(); - - char pad0[2024]; - GameArray quests; -}; - -static_assert(offsetof(FormManager, quests) == 2024); diff --git a/Code/client/Games/Fallout4/Forms/ActorValueInfo.cpp b/Code/client/Games/Fallout4/Forms/ActorValueInfo.cpp deleted file mode 100644 index 74ac7a374..000000000 --- a/Code/client/Games/Fallout4/Forms/ActorValueInfo.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include - -#include - -ActorValueInfo* ActorValueInfo::Resolve(uint32_t aId) noexcept -{ - using TGetActorValueInfoArray = ActorValueInfo**(); - POINTER_FALLOUT4(TGetActorValueInfoArray, GetActorValueInfoArray, 405391); - - return GetActorValueInfoArray()[aId]; -} diff --git a/Code/client/Games/Fallout4/Forms/ActorValueInfo.h b/Code/client/Games/Fallout4/Forms/ActorValueInfo.h deleted file mode 100644 index da586e00c..000000000 --- a/Code/client/Games/Fallout4/Forms/ActorValueInfo.h +++ /dev/null @@ -1,152 +0,0 @@ -#pragma once - -#include -#include - -struct ActorValueInfo : TESForm -{ - enum - { - kAbsorbChance = 0, - kActionPoints = 1, - kAggression = 2, - kAgility = 3, - kAimStability = 4, - kAlchemy = 5, - kAnimationMult = 6, - kArmorPerks = 7, - kAssistance = 8, - kAttackDamageMult = 9, - kBlindness = 10, - kBlock = 11, - kBloodyMess = 12, - kBowSpeedBonus = 13, - kBowStaggerBonus = 14, - kBrainCondition = 15, - kCarryWeight = 16, - kCharisma = 17, - kCombatHealthRegenMult = 18, - kConfidence = 19, - kCritChance = 20, - kDamageResist = 21, - kDeafness = 22, - kEndurance = 24, - kEnduranceCondition = 25, - kExperience = 26, - kHealth = 27, - kHealRateMult = 28, - kIdleChatterTimeMin = 29, - kIdleChatterTimeMax = 30, - kIgnoreCrippledLimbs = 31, - kIntelligence = 32, - kInvisibility = 33, - kKARMA = 34, - kLeftAttackCondition = 35, - kLeftItemCharge = 36, - kLeftMobilityCondition = 37, - kLeftWeaponSpeedMult = 38, - kLockpicking = 39, - kLuck = 40, - kMass = 41, - kMeleeDamage = 42, - kMorality = 43, - kMovementNoiseMult = 44, - kNightEye = 45, - kPerception = 46, - kPerceptionCondition = 47, - kPoisonResist = 49, - kPowerArmorBattery = 50, - kPowerArmorHeadCondition = 51, - kPowerArmorTorsoCondition = 52, - kPowerArmorLeftArmCondition = 53, - kPowerArmorRightArmCondition = 54, - kPowerArmorLeftLegCondition = 55, - kPowerArmorRightLegCondition = 56, - kRadHealthMax = 57, - kRads = 58, - kFatigueAPMax = 59, - kFatigue = 60, - kReflectDamage = 61, - kConditionRate = 62, - kRightAttackCondition = 63, - kRightItemCharge = 64, - kRightMobilityCondition = 65, - kRotationSpeedCondition = 66, - kShieldPerks = 67, - kShoutRecoveryMult = 68, - kSneak = 69, - kSpeedMult = 71, - kUnusedStamina = 72, - kStrength = 73, - kSuspicious = 74, - kTelekinesis = 75, - kUnarmedDamage = 76, - kVANSPerk = 77, - kWardPower = 78, - kWaitingForPlayer = 79, - kWaterBreathing = 80, - kWaterWalking = 81, - kWeaponSpeedMult = 82, - kWeapReloadSpeedMult = 83, - kHealRate = 84, - kActionPointsRate = 85, - kActionPointsRateMult = 86, - kRadsRate = 87, - kRadsRateMult = 88, - kFatigueRate = 89, - kFatigueRateMult = 90, - kConditionRateMult = 91, - kFireResist = 92, - kElectricResist = 93, - kFrostResist = 94, - kMagicResist = 95, - kRadResistIngestion = 96, - kRadResistExposure = 97, - kEnergy = 98, - kEnergyResist = 99, - kParalysis = 100, - kAttackConditionAlt1 = 101, - kAttackConditionAlt2 = 102, - kAttackConditionAlt3 = 103, - kPowerGenerated = 104, - kPowerRadiation = 105, - kPowerRequired = 106, - kFood = 107, - kWater = 108, - kSafety = 109, - kBed = 110, - kHappiness = 111, - kArtillery = 112, - kWorkshopItemOverlap = 113, - kWorkshopItemClampDirection = 114, - kWorkshopItemZOffset = 115, - kWorkshopPlayerOwned = 116, - kWorkshopActorWounded = 117, - kWorkshopStackableItem = 118, - kWorkshopSnapPointRadius = 119, - kWorkshopAnythingIsGround = 120, - kWorkshopMaxTriangles = 121, - kWorkshopMaxDraws = 122, - kWorkshopCurrentTriangles = 123, - kWorkshopCurrentDraws = 124, - kWorkshopIgnoreSimpleIntersections = 125, - kWorkshopAllowUnsupportedStacking = 126, - kWorkshopSnapTransmitsPower = 127, - kWorkshopPowerConnection = 128, - kLogicOperation = 129, - kLogicOutput = 130, - kIgnorePlayerWhileFrenzied = 131, - kActorValueCount = 132, - }; - - static ActorValueInfo* Resolve(uint32_t aId) noexcept; - - virtual ~ActorValueInfo(); - - TESFullName name; - uint8_t pad30[0x68 - 0x30]; - char* key; -}; - -static_assert(offsetof(ActorValueInfo, name) == 0x20); -static_assert(offsetof(ActorValueInfo, key) == 0x68); diff --git a/Code/client/Games/Fallout4/Forms/BGSAction.h b/Code/client/Games/Fallout4/Forms/BGSAction.h deleted file mode 100644 index 85e1869ac..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSAction.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct BGSAction : BGSKeyword -{ - uint32_t counter; -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSColorForm.h b/Code/client/Games/Fallout4/Forms/BGSColorForm.h deleted file mode 100644 index 9e9836622..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSColorForm.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct BGSColorForm : TESForm -{ - virtual ~BGSColorForm(); -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSHeadPart.h b/Code/client/Games/Fallout4/Forms/BGSHeadPart.h deleted file mode 100644 index fe08154cd..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSHeadPart.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -// Placeholder, inheritance is wrong -struct BGSHeadPart -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSInventoryItem.h b/Code/client/Games/Fallout4/Forms/BGSInventoryItem.h deleted file mode 100644 index 65ab8b647..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSInventoryItem.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include - -struct BGSInventoryItem -{ - struct Stack : BSIntrusiveRefCounted - { - // Seems that most of these flags aren't used. - // INV_SLOT_INDEX_1 seems to mean not equipped. - enum class Flag : int32_t - { - INV_SLOT_INDEX_1 = 0x0, - INV_SLOT_INDEX_2 = 0x1, - INV_SLOT_INDEX_3 = 0x2, - INV_EQUIP_STATE_LOCKED = 0x3, - INV_SHOULD_EQUIP = 0x4, - INV_TEMPORARY = 0x5, - INV_SLOT_MASK = 0x7, - }; - - virtual ~Stack(); - - Stack* spNextStack; - ExtraDataList* spExtra; - uint32_t uiCount; - Flag usFlags; - - // TODO(cosideci): impl range based loop -#if 0 - struct Iterator - { - Iterator(Stack* apEntry) : m_pEntry(apEntry) {} - Iterator operator++() { m_pEntry = m_pEntry->spNextStack; return *this; } - bool operator!=(const Iterator& acRhs) const { return m_pEntry != acRhs.m_pEntry; } - T* operator*() const { return m_pEntry->data; } - private: - Stack* m_pEntry; - }; - - Iterator begin() - { - return Iterator(&entry); - } - - Iterator end() - { - return Iterator(nullptr); - } -#endif - }; - - TESBoundObject* pObject; - Stack* spStackData; -}; - -static_assert(sizeof(BGSInventoryItem) == 0x10); diff --git a/Code/client/Games/Fallout4/Forms/BGSInventoryList.h b/Code/client/Games/Fallout4/Forms/BGSInventoryList.h deleted file mode 100644 index 5c51e0a4a..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSInventoryList.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include "BGSInventoryItem.h" - -struct BGSInventoryList : EventDispatcher -{ - // TODO: maybe use this? - struct __declspec(align(4)) IsQuestObjectFunctor - { - TESBoundObject* pObj; - uint32_t uiStackID; - bool bResult; - }; - - GameArray DataA; - float fCachedWeight; - BSPointerHandle hOwner; - BSReadWriteLock RWLock; -}; - -static_assert(sizeof(BGSInventoryList) == 0x80); diff --git a/Code/client/Games/Fallout4/Forms/BGSKeyword.h b/Code/client/Games/Fallout4/Forms/BGSKeyword.h deleted file mode 100644 index 265ec5216..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSKeyword.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -#include - -struct BGSKeyword : TESForm -{ - virtual ~BGSKeyword(); - - BSFixedString keyword; -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSNote.h b/Code/client/Games/Fallout4/Forms/BGSNote.h deleted file mode 100644 index 5ad864db3..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSNote.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "TESBoundObject.h" -#include "TESWeightForm.h" -#include "TESValueForm.h" -#include - -struct BGSNote : TESBoundObject, TESWeightForm, TESValueForm, TESModel, TESFullName -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSObjectInstance.cpp b/Code/client/Games/Fallout4/Forms/BGSObjectInstance.cpp deleted file mode 100644 index 8c6e414cd..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSObjectInstance.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "BGSObjectInstance.h" - -BGSObjectInstance::BGSObjectInstance(TESForm* apObject, TBO_InstanceData* apInstanceData) -{ - TP_THIS_FUNCTION(TBGSObjectInstance, void, BGSObjectInstance, TESForm* apObject, TBO_InstanceData* apInstanceData); - POINTER_FALLOUT4(TBGSObjectInstance, bgsObjectInstance, 1095749); - TiltedPhoques::ThisCall(bgsObjectInstance, this, apObject, apInstanceData); -} diff --git a/Code/client/Games/Fallout4/Forms/BGSObjectInstance.h b/Code/client/Games/Fallout4/Forms/BGSObjectInstance.h deleted file mode 100644 index b614e16f0..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSObjectInstance.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -struct TESForm; -struct TBO_InstanceData; - -struct BGSObjectInstance -{ - BGSObjectInstance() = delete; - BGSObjectInstance(TESForm* apObject, TBO_InstanceData* apInstanceData); - - TESForm* pObject; - TBO_InstanceData* spInstanceData; -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSOutfit.h b/Code/client/Games/Fallout4/Forms/BGSOutfit.h deleted file mode 100644 index bdf8fdc91..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSOutfit.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct BGSOutfit : TESForm -{ - virtual ~BGSOutfit(); -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSStoryManagerTree.h b/Code/client/Games/Fallout4/Forms/BGSStoryManagerTree.h deleted file mode 100644 index c01f8dec6..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSStoryManagerTree.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct BGSStoryManagerTreeForm : TESForm -{ - uint64_t unk20; -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSTextureSet.h b/Code/client/Games/Fallout4/Forms/BGSTextureSet.h deleted file mode 100644 index bf031ae6b..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSTextureSet.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct BGSTextureSet : TESBoundObject -{ - virtual ~BGSTextureSet(); -}; diff --git a/Code/client/Games/Fallout4/Forms/BGSVoiceType.h b/Code/client/Games/Fallout4/Forms/BGSVoiceType.h deleted file mode 100644 index 99b5e91e6..000000000 --- a/Code/client/Games/Fallout4/Forms/BGSVoiceType.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct BGSVoiceType : TESForm -{ - virtual ~BGSVoiceType(); -}; diff --git a/Code/client/Games/Fallout4/Forms/SpellItem.h b/Code/client/Games/Fallout4/Forms/SpellItem.h deleted file mode 100644 index d4d1b2bb7..000000000 --- a/Code/client/Games/Fallout4/Forms/SpellItem.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -struct BGSPerk; - -struct SpellItem : MagicItem -{ - uint8_t padMI[0x108 - sizeof(MagicItem)]; - int32_t iCostOverride; - uint32_t iFlags; - MagicSystem::SpellType eSpellType; - float fChargeTime; - MagicSystem::CastingType eCastingType; - MagicSystem::Delivery eDelivery; - float fCastDuration; - float fRange; - BGSPerk* pCastingPerk; -}; - -static_assert(sizeof(SpellItem) == 0x130); diff --git a/Code/client/Games/Fallout4/Forms/TESActorBase.h b/Code/client/Games/Fallout4/Forms/TESActorBase.h deleted file mode 100644 index 3ff2dee38..000000000 --- a/Code/client/Games/Fallout4/Forms/TESActorBase.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -struct TESActorBase : TESBoundAnimObject -{ - virtual void sub_65(); - virtual void sub_66(); - virtual void sub_67(); - virtual void sub_68(); - - TESActorBaseData actorData; // 68 - TESContainer container; // D0 - TESSpellList spellList; // E8 - TESAIForm aiForm; // F8 - TESFullName fullName; // 120 - ActorValueOwner actorValueOwner; // 130 - BGSDestructibleObjectForm destructibleObjectForm; // 138 - BGSSkinForm skinForm; // 148 - BGSKeywordForm keywordForm; // 158 - BGSAttackDataForm attackDataForm; // 178 - BGSPerkRankArray perkRankArray; // 188 - BGSPropertySheet propertySheet; // 1A0 -}; - -static_assert(offsetof(TESActorBase, actorData) == 0x68); -static_assert(offsetof(TESActorBase, container) == 0xD0); -static_assert(offsetof(TESActorBase, spellList) == 0xE8); -static_assert(offsetof(TESActorBase, aiForm) == 0xF8); -static_assert(offsetof(TESActorBase, fullName) == 0x120); -static_assert(offsetof(TESActorBase, actorValueOwner) == 0x130); -static_assert(offsetof(TESActorBase, destructibleObjectForm) == 0x138); -static_assert(offsetof(TESActorBase, skinForm) == 0x148); -static_assert(offsetof(TESActorBase, propertySheet) == 0x1A0); -static_assert(sizeof(TESActorBase) == 0x1B0); diff --git a/Code/client/Games/Fallout4/Forms/TESAmmo.h b/Code/client/Games/Fallout4/Forms/TESAmmo.h deleted file mode 100644 index f22d675c9..000000000 --- a/Code/client/Games/Fallout4/Forms/TESAmmo.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "TESBoundObject.h" - -struct TESAmmo : TESBoundObject, TESFullName -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/TESBoundAnimObject.h b/Code/client/Games/Fallout4/Forms/TESBoundAnimObject.h deleted file mode 100644 index c6a7da91b..000000000 --- a/Code/client/Games/Fallout4/Forms/TESBoundAnimObject.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -struct TESBoundAnimObject : TESBoundObject -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/TESBoundObject.h b/Code/client/Games/Fallout4/Forms/TESBoundObject.h deleted file mode 100644 index dab4c84a5..000000000 --- a/Code/client/Games/Fallout4/Forms/TESBoundObject.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -struct TESBoundObject : TESObject -{ - virtual void sub_54(); - virtual void sub_55(); - virtual void sub_56(); - virtual void sub_57(); - virtual void sub_58(); - virtual void sub_59(); - virtual void sub_5A(); - virtual void sub_5B(); - virtual void sub_5C(); - virtual void sub_5D(); - virtual void sub_5E(); - virtual void sub_5F(); - virtual void sub_60(); - virtual void sub_61(); - virtual void sub_62(); - virtual void sub_63(); - virtual void sub_64(); - - uint8_t pad20[0x68 - 0x20]; -}; - -static_assert(sizeof(TESBoundObject) == 0x68); diff --git a/Code/client/Games/Fallout4/Forms/TESClass.h b/Code/client/Games/Fallout4/Forms/TESClass.h deleted file mode 100644 index 292866d29..000000000 --- a/Code/client/Games/Fallout4/Forms/TESClass.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct TESClass : TESForm -{ - virtual ~TESClass(); -}; diff --git a/Code/client/Games/Fallout4/Forms/TESCombatStyle.h b/Code/client/Games/Fallout4/Forms/TESCombatStyle.h deleted file mode 100644 index cb1ba0d4f..000000000 --- a/Code/client/Games/Fallout4/Forms/TESCombatStyle.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct TESCombatStyle : TESForm -{ - virtual ~TESCombatStyle(); -}; diff --git a/Code/client/Games/Fallout4/Forms/TESFaction.h b/Code/client/Games/Fallout4/Forms/TESFaction.h deleted file mode 100644 index 916c40daa..000000000 --- a/Code/client/Games/Fallout4/Forms/TESFaction.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -struct TESFaction : TESForm -{ - virtual ~TESFaction(); -}; diff --git a/Code/client/Games/Fallout4/Forms/TESForm.h b/Code/client/Games/Fallout4/Forms/TESForm.h deleted file mode 100644 index 80dd193b9..000000000 --- a/Code/client/Games/Fallout4/Forms/TESForm.h +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once - -#include - -enum class FormType : uint8_t -{ - Armor = 29, - Book = 30, - Container = 31, - Door = 32, - Ammo = 44, - Npc = 45, - LeveledCharacter = 46, - Character = 65, - QuestItem = 80, - Count = 0x9F -}; - -struct BGSSaveFormBuffer; -struct BGSLoadFormBuffer; - -struct TESForm : BaseFormComponent -{ - struct ChangeFlags - { - uint32_t flags; - uint64_t unk4; - uint32_t unkC; - }; - - enum FormFlags - { - DISABLED = 1 << 0xB, - }; - - static TESForm* GetById(uint32_t aId); - - virtual void sub_7(); - virtual void sub_8(); - virtual void sub_9(); - virtual void sub_A(); - virtual void sub_B(); - virtual void sub_C(); - virtual bool MarkChanged(uint32_t aChangeFlag); - virtual bool UnsetChanged(uint32_t aChangeFlag); - virtual void sub_F(); - virtual void sub_10(); - virtual bool Save(BGSSaveFormBuffer* apBuffer) const noexcept; - virtual bool Load(BGSLoadFormBuffer* apBuffer); - virtual void sub_13(); - virtual void sub_14(); - virtual void sub_15(); - virtual void sub_16(); - virtual void sub_17(); - virtual void sub_18(); - virtual FormType GetFormType(); - virtual void sub_1A(); - virtual void sub_1B(); - virtual void sub_1C(); - virtual void sub_1D(); - virtual void sub_1E(); - virtual void sub_1F(); - virtual void sub_20(); - virtual void sub_21(); - virtual void sub_22(); - virtual void sub_23(); - virtual void sub_24(); - virtual void sub_25(); - virtual void sub_26(); - virtual void sub_27(); - virtual void sub_28(); - virtual void sub_29(); - virtual void sub_2A(); - virtual void sub_2B(); - virtual void sub_2C(); - virtual void sub_2D(); - virtual void sub_2E(); - virtual void sub_2F(); - virtual void sub_30(); - virtual void sub_31(); - virtual void sub_32(); - virtual void sub_33(); - virtual void sub_34(); - virtual const char* GetName() const noexcept; - virtual void sub_36(); - virtual void sub_37(); - virtual void sub_38(); - virtual void sub_39(); - virtual void sub_3A(); - virtual void sub_3B(); - virtual void sub_3C(); - virtual void sub_3D(); - virtual void sub_3E(); - virtual void sub_3F(); - virtual void sub_40(); - virtual void sub_41(); - virtual void sub_42(); - virtual void sub_43(); - virtual void sub_44(); - virtual void sub_45(); - virtual void sub_46(); - virtual void sub_47(); - - // void CopyFromEx(TESForm* rhs); - void Save(std::string apSaveBuffer) noexcept; - void Save_Reversed(uint32_t aChangeFlags, Buffer::Writer& aWriter); - void SetSkipSaveFlag(bool aSet) noexcept; - uint32_t GetChangeFlags() const noexcept; - - void SetIgnoreFriendlyHit(bool aSet) noexcept - { - // TODO: fallout 4 impl - return; - } - bool IsDisabled() const noexcept { return (flags & DISABLED) != 0; } - bool IsTemporary() const noexcept { return formID >= 0xFF000000; } - - uintptr_t unk8; - uint32_t flags; - uint32_t formID; - uint16_t unk10; - FormType formType; - uint8_t unk1B; - uint8_t tp_flags; // This is actually padding so we can use it for any purpose -}; - -static_assert(sizeof(TESForm) == 0x20); diff --git a/Code/client/Games/Fallout4/Forms/TESGlobal.h b/Code/client/Games/Fallout4/Forms/TESGlobal.h deleted file mode 100644 index ca66386d7..000000000 --- a/Code/client/Games/Fallout4/Forms/TESGlobal.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include - -struct TESGlobal : TESForm -{ - BSFixedString name; - uint8_t unk1C; - uint8_t pad[3 + 4]; - union - { - uint32_t i; - float f; - }; -}; - -static_assert(offsetof(TESGlobal, i) == 0x30); diff --git a/Code/client/Games/Fallout4/Forms/TESIdleForm.h b/Code/client/Games/Fallout4/Forms/TESIdleForm.h deleted file mode 100644 index 9eccf2737..000000000 --- a/Code/client/Games/Fallout4/Forms/TESIdleForm.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -struct TESIdleForm : TESForm -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/TESLevCharacter.h b/Code/client/Games/Fallout4/Forms/TESLevCharacter.h deleted file mode 100644 index 850d3de4f..000000000 --- a/Code/client/Games/Fallout4/Forms/TESLevCharacter.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include -#include - -struct TESLevCharacter : TESBoundAnimObject -{ - // Components - TESLeveledList leveledList; - BGSModelMaterialSwap modelTextureSwap; -}; - -static_assert(offsetof(TESLevCharacter, leveledList) == 0x68); -static_assert(offsetof(TESLevCharacter, modelTextureSwap) == 0x98); -static_assert(sizeof(TESLevCharacter) == 0xD8); diff --git a/Code/client/Games/Fallout4/Forms/TESNPC.cpp b/Code/client/Games/Fallout4/Forms/TESNPC.cpp deleted file mode 100644 index 3e67a5154..000000000 --- a/Code/client/Games/Fallout4/Forms/TESNPC.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include - -#include - -TP_THIS_FUNCTION(TSetLeveledNpc, TESNPC*, TESNPC, TESNPC*); -static TSetLeveledNpc* RealSetLeveledNpc = nullptr; - -TESNPC* TP_MAKE_THISCALL(HookSetLeveledNpc, TESNPC, TESNPC* apSelectedNpc) -{ - spdlog::info("For TESNPC: {}, spawning: {}", apThis->fullName.value.AsAscii(), apSelectedNpc->fullName.value.AsAscii()); - - return TiltedPhoques::ThisCall(RealSetLeveledNpc, apThis, Cast(TESForm::GetById(0x3B547))); -} - -static TiltedPhoques::Initializer s_npcInitHooks( - []() - { - POINTER_FALLOUT4(TSetLeveledNpc, s_SetLeveledNpc, 472573); - - RealSetLeveledNpc = s_SetLeveledNpc.Get(); - - // TP_HOOK(&RealSetLeveledNpc, HookSetLeveledNpc); - }); diff --git a/Code/client/Games/Fallout4/Forms/TESNPC.h b/Code/client/Games/Fallout4/Forms/TESNPC.h deleted file mode 100644 index 2c9ee4be8..000000000 --- a/Code/client/Games/Fallout4/Forms/TESNPC.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -struct BGSTextureSet; -struct BGSColorForm; -struct TESClass; -struct TESCombatStyle; -struct BGSOutfit; -struct TESFaction; -struct BGSHeadPart; - -struct TESNPC : TESActorBase -{ - static constexpr FormType Type = FormType::Npc; - - static TESNPC* Create(const String& acBuffer, uint32_t aChangeFlags) noexcept; - - // TODO: ft, verify whether it also works like this in fallout 4 - TESNPC* GetTemplateBase() const noexcept - { - TESNPC* pTemplate = npcTemplate; - - while (pTemplate && pTemplate->IsTemporary()) - pTemplate = pTemplate->npcTemplate; - - return pTemplate; - } - - struct Head - { - BGSColorForm* hairColor; - void* unk8; - BGSTextureSet* textures; - }; - - TESRaceForm raceForm; - BGSOverridePackCollection overridePackCollection; // 1C0 - TESNPC* npcTemplate; - BGSForcedLocRefType forcedLocRefType; - BGSNativeTerminalForm nativeTerminalForm; - void* menuOpenCloseEventSink; - BGSAttachParentArray attachParentArray; - - uint32_t unk238; // 238 - set to 0 - uint16_t unk23C; // 23C - set to 0 - uint8_t unk23E; // 23E - set to 1 - uint8_t pad23F; // 23F - TESClass* npcClass; // 240 - Head* head; // 248 - set to nullptr - void* unk250; // 250 - TESCombatStyle* combatStyle; // 258 - uint8_t unk260[8]; // 260 - void* unk268; // 268 - void* unk270; // 270 - float smallWeight; // 278 - float muscularWeight; // 27C - float largeWeight; // 280 - float unk284; // 284 - float unk288; // 288 - uint32_t pad28C; // 28C - void* unk290; // 290 - void* unk298; // 298 - void* unk2A0; // 2A0 - set to nullptr - void* unk2A8; // 2A8 - BGSOutfit* outfits[2]; // 2B0 - void* unk2C0; // 2C0 - TESFaction* faction; // 2C8 - BGSHeadPart** headParts; // 2D0 - void* unk2D8; // 2D8 - void* morphRegionData; // 2E0 - uint8_t headPartCount; // 2E8 - uint8_t unk2E9; // 2E9 - uint8_t skinColor[4]; // 2EA - uint16_t pad2EE; // 2EE - uint64_t unk2F0; // 2F0 - not sure about type - void* unk2F8; // 2F8 - GameArray* tints; // 300 - - BGSHeadPart* GetHeadPart(uint32_t aType); - void Serialize(String* apSaveBuffer) const noexcept; - void Deserialize(const String& acBuffer, uint32_t aChangeFlags) noexcept; - void Initialize() noexcept; -}; - -static_assert(offsetof(TESNPC, unk238) == 0x238); -static_assert(offsetof(TESNPC, pad28C) == 0x28C); -static_assert(offsetof(TESNPC, headPartCount) == 0x2E8); -static_assert(offsetof(TESNPC, unk2F8) == 0x2F8); -static_assert(offsetof(TESNPC, tints) == 0x300); -static_assert(sizeof(TESNPC) == 0x308); diff --git a/Code/client/Games/Fallout4/Forms/TESObject.h b/Code/client/Games/Fallout4/Forms/TESObject.h deleted file mode 100644 index 7bc7fcffe..000000000 --- a/Code/client/Games/Fallout4/Forms/TESObject.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -struct TESObject : TESForm -{ - virtual void sub_48(); - virtual void sub_49(); - virtual void sub_4A(); - virtual void sub_4B(); - virtual void sub_4C(); - virtual void sub_4D(); - virtual void sub_4E(); - virtual void sub_4F(); - virtual void sub_50(); - virtual void sub_51(); - virtual void sub_52(); - virtual void sub_53(); -}; diff --git a/Code/client/Games/Fallout4/Forms/TESObjectARMO.h b/Code/client/Games/Fallout4/Forms/TESObjectARMO.h deleted file mode 100644 index adf920a7a..000000000 --- a/Code/client/Games/Fallout4/Forms/TESObjectARMO.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "TESBoundObject.h" -#include - -struct BGSTypedFormValuePair -{ - union SharedVal - { - unsigned int i; - float f; - }; -}; - -enum class STAGGER_MAGNITUDE : int32_t -{ - STAGGER_NONE = 0x0, - STAGGER_SMALL = 0x1, - STAGGER_MEDIUM = 0x2, - STAGGER_LARGE = 0x3, - STAGGER_EXTRA_LARGE = 0x4, - STAGGER_MAGNITUDE_COUNT = 0x5, - STAGGER_MAGNITUDE_MIN = 0x0, - STAGGER_MAGNITUDE_MAX = 0x4, -}; - -struct TESObjectARMO : TESBoundObject, TESFullName -{ - struct InstanceData : TBO_InstanceData - { - GameArray* pEnchantments; - GameArray* pMaterialSwapA; - BGSBlockBashData* pBlockBashData; - BGSKeywordForm* pKeywords; - GameArray>* pDamageTypesA; - GameArray>* pActorValuesA; - float fWeight; - float fColorRemappingIndex; - uint32_t uiValue; - uint32_t uiHealth; - STAGGER_MAGNITUDE eStaggerRating; - uint16_t usRating; - uint16_t usIndex; - }; -}; diff --git a/Code/client/Games/Fallout4/Forms/TESObjectBOOK.h b/Code/client/Games/Fallout4/Forms/TESObjectBOOK.h deleted file mode 100644 index 794a05681..000000000 --- a/Code/client/Games/Fallout4/Forms/TESObjectBOOK.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include -#include - -struct TESObjectBOOK : TESBoundObject, TESFullName -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/TESObjectCELL.cpp b/Code/client/Games/Fallout4/Forms/TESObjectCELL.cpp deleted file mode 100644 index 9b2129630..000000000 --- a/Code/client/Games/Fallout4/Forms/TESObjectCELL.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -Vector TESObjectCELL::GetRefsByFormTypes(const Vector& aFormTypes) noexcept -{ - Vector references{}; - - if (!objects.data) - return references; - - for (TESObjectREFR* pObject : objects) - { - if (!pObject) - continue; - - for (FormType formType : aFormTypes) - { - if (pObject->baseForm->formType == formType) - references.push_back(pObject); - } - } - - return references; -} diff --git a/Code/client/Games/Fallout4/Forms/TESObjectCELL.h b/Code/client/Games/Fallout4/Forms/TESObjectCELL.h deleted file mode 100644 index 1f55f1163..000000000 --- a/Code/client/Games/Fallout4/Forms/TESObjectCELL.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include - -struct TESObjectREFR; -struct TESWorldSpace; - -struct TESObjectCELL : TESForm -{ - Vector GetRefsByFormTypes(const Vector& aFormTypes) noexcept; - void GetCOCPlacementInfo(NiPoint3* aOutPos, NiPoint3* aOutRot, bool aAllowCellLoad) noexcept; - - uint8_t pad20[0x40 - 0x20]; - uint8_t cellFlags[5]; - uint8_t pad45[0x70 - 0x45]; - - GameArray objects; // 70 - - uint8_t pad88[0xC8 - 0x88]; - TESWorldSpace* worldspace; // C8 - - bool IsValid() const { return cellFlags[4] == 8; } -}; - -static_assert(offsetof(TESObjectCELL, cellFlags) == 0x40); -static_assert(offsetof(TESObjectCELL, objects) == 0x70); -static_assert(offsetof(TESObjectCELL, worldspace) == 0xC8); diff --git a/Code/client/Games/Fallout4/Forms/TESObjectMISC.h b/Code/client/Games/Fallout4/Forms/TESObjectMISC.h deleted file mode 100644 index 76bca1592..000000000 --- a/Code/client/Games/Fallout4/Forms/TESObjectMISC.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include -#include - -struct TESObjectMISC : TESBoundObject, TESFullName -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/TESObjectWEAP.h b/Code/client/Games/Fallout4/Forms/TESObjectWEAP.h deleted file mode 100644 index 97bfef5ac..000000000 --- a/Code/client/Games/Fallout4/Forms/TESObjectWEAP.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "TESBoundObject.h" - -struct TESObjectWEAP : TESBoundObject, TESFullName -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/TESPackage.h b/Code/client/Games/Fallout4/Forms/TESPackage.h deleted file mode 100644 index e98e2b88f..000000000 --- a/Code/client/Games/Fallout4/Forms/TESPackage.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "TESForm.h" - -struct TESPackage : TESForm -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/TESQuest.cpp b/Code/client/Games/Fallout4/Forms/TESQuest.cpp deleted file mode 100644 index fc2db20f2..000000000 --- a/Code/client/Games/Fallout4/Forms/TESQuest.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include - -#include - -#include - -void TESQuest::SetActive(bool toggle) -{ - // bethesda implemented a new event dispatcher - // whenever a quest is activated, that's why - // we use the game function instead of reimplementing it. - using TSetActive = void(TESQuest*, bool); - POINTER_FALLOUT4(TSetActive, SetActive, 1567563); - - SetActive(this, toggle); -} - -void TESQuest::SetStopped() -{ - flags &= 0xFFFE; - MarkChanged(2); -} - -bool TESQuest::EnsureQuestStarted(bool& success, bool force) -{ - TP_THIS_FUNCTION(TSetRunning, bool, TESQuest, bool*, bool); - POINTER_FALLOUT4(TSetRunning, SetRunning, 966434); - return SetRunning(this, &success, force); -} - -bool TESQuest::SetStage(uint16_t stage) -{ - using TSetStage = bool(TESQuest*, uint16_t); - POINTER_FALLOUT4(TSetStage, SetStage, 952800); - - return SetStage(this, stage); -} - -void TESQuest::ScriptSetStage(uint16_t stageIndex) -{ - for (auto& stage : stages) - { - if (stage.stageIndex == stageIndex && stage.IsDone()) - return; - } - - using Quest = TESQuest; - PAPYRUS_FUNCTION(void, Quest, SetCurrentStageID, int); - s_pSetCurrentStageID(this, stageIndex); -} diff --git a/Code/client/Games/Fallout4/Forms/TESQuest.h b/Code/client/Games/Fallout4/Forms/TESQuest.h deleted file mode 100644 index c11c00153..000000000 --- a/Code/client/Games/Fallout4/Forms/TESQuest.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -struct TESQuest : BGSStoryManagerTreeForm -{ - enum Flags : uint16_t - { - Disabled, - Enabled = 1 << 0, - Completed = 1 << 1, - StageWait = 1 << 7, - Unk = 2 << 10, // this is very likely a combination - Unk2 = 8 << 10, - }; - - enum class Type : uint8_t - { - None = 0x0, - QTYPE_MAINQUEST = 0x1, - QTYPE_BROTHERHOOD = 0x2, - QTYPE_INSTITUTE = 0x3, - QTYPE_MINUTEMEN = 0x4, - QTYPE_RAILROAD = 0x5, - Miscellaneous = 0x6, - QTYPE_SIDEQUESTS = 0x7, - QTYPE_DLC01 = 0x8, - QTYPE_DLC02 = 0x9, - QTYPE_DLC03 = 0xA, - QTYPE_COUNT = 0xB, - }; - - struct Objective - { - BSFixedString nameRef; - TESQuest* parent; - char pad10[0x8]; // 0x0010 - uint16_t flags; // 0x0018 - char pad1A[0x2]; // 0x001A - uint16_t stageId; // 0x001C - }; - - struct Stage - { - uint32_t pad0; - char pad4[0x4]; // 0x0004 - uint16_t stageIndex; // 0x0008 - char padA[0x6]; // 0x000A - int32_t someArrayCount; // 0x0010 - char pad14[0x6]; // 0x0014 - uint8_t flags; // 0x001A - uint16_t pad1B; // 0x001B - - inline bool IsDone() const { return flags & 1; } - }; - - void* pUnkQuest; // maybe a TESFullname? - char pad30[0xC4]; // 0x0030 - uint16_t flags; // 0x00F4 - uint8_t priority; // 0x00F6 - Type type; // 0x00F7 - int32_t scopedStatus; // 0x00F8 - char padFC[0x4]; // 0x00FC - GameArray stages; // 0x0100 - GameArray objectives; // 0x0118 - char pad130[0x184]; // 0x0130 - uint16_t currentStage; // 0x02B4 - uint16_t pad2B6; // 0x02B6 - BSString idName; // 0x02B8 - char pad2C4[0x2C - 8]; - - void SetActive(bool toggle); - bool SetStage(uint16_t stage); - void SetStopped(); - void ScriptSetStage(uint16_t stage); - - inline bool IsActive() const { return ((flags >> 11) & 1); } - inline bool IsCompleted() const { return ((flags >> 1) & 1); } - inline bool IsStopped() const { return !(flags & Flags::Enabled) && flags >= 0; } - - bool EnsureQuestStarted(bool& succeded, bool force); -}; - -static_assert(sizeof(TESQuest) == 752); -// static_assert(offsetof(TESQuest, fullName) == 0x28); -static_assert(offsetof(TESQuest, objectives) == 0x118); -static_assert(offsetof(TESQuest, currentStage) == 0x2B4); -static_assert(offsetof(TESQuest, flags) == 0xF4); -static_assert(offsetof(TESQuest, idName) == 0x2B8); diff --git a/Code/client/Games/Fallout4/Forms/TESRace.h b/Code/client/Games/Fallout4/Forms/TESRace.h deleted file mode 100644 index b667e35e5..000000000 --- a/Code/client/Games/Fallout4/Forms/TESRace.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -#include - -struct TESRace : TESForm -{ - virtual ~TESRace(); - - TESFullName name; -}; diff --git a/Code/client/Games/Fallout4/Forms/TESTopicInfo.cpp b/Code/client/Games/Fallout4/Forms/TESTopicInfo.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/Code/client/Games/Fallout4/Forms/TESTopicInfo.h b/Code/client/Games/Fallout4/Forms/TESTopicInfo.h deleted file mode 100644 index f68b88319..000000000 --- a/Code/client/Games/Fallout4/Forms/TESTopicInfo.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -struct TESTopicInfo : TESForm -{ - uint8_t pad20[0x42 - 0x20]; - uint8_t ucSubtitlePriority; - uint8_t pad43[0x50 - 0x43]; -}; - -static_assert(sizeof(TESTopicInfo) == 0x50); diff --git a/Code/client/Games/Fallout4/Forms/TESValueForm.h b/Code/client/Games/Fallout4/Forms/TESValueForm.h deleted file mode 100644 index 9a9042616..000000000 --- a/Code/client/Games/Fallout4/Forms/TESValueForm.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -struct TESValueForm : BaseFormComponent -{ - int32_t iValue; -}; diff --git a/Code/client/Games/Fallout4/Forms/TESWeather.h b/Code/client/Games/Fallout4/Forms/TESWeather.h deleted file mode 100644 index 9cc0e3263..000000000 --- a/Code/client/Games/Fallout4/Forms/TESWeather.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -struct TESWeather : TESForm -{ -}; diff --git a/Code/client/Games/Fallout4/Forms/TESWeightForm.h b/Code/client/Games/Fallout4/Forms/TESWeightForm.h deleted file mode 100644 index e9dfd23d8..000000000 --- a/Code/client/Games/Fallout4/Forms/TESWeightForm.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -struct TESWeightForm : BaseFormComponent -{ - float fWeight; -}; diff --git a/Code/client/Games/Fallout4/Forms/TESWorldSpace.h b/Code/client/Games/Fallout4/Forms/TESWorldSpace.h deleted file mode 100644 index 6eb5b5911..000000000 --- a/Code/client/Games/Fallout4/Forms/TESWorldSpace.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -struct TESWorldSpace : TESForm -{ - virtual ~TESWorldSpace(); - - // aX and aY are coordinates, not positions - TESObjectCELL* LoadCell(int32_t aXCoordinate, int32_t aYCoordinate) noexcept; - - TESFullName fullName; -}; diff --git a/Code/client/Games/Fallout4/Havok.h b/Code/client/Games/Fallout4/Havok.h deleted file mode 100644 index 09f2a76bd..000000000 --- a/Code/client/Games/Fallout4/Havok.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -struct bhkCharRigidBodyController -{ - virtual ~bhkCharRigidBodyController(); - - uint8_t unk8[0x300 - 0x8]; - uint32_t flags; -}; diff --git a/Code/client/Games/Fallout4/Havok/BShkbAnimationGraph.h b/Code/client/Games/Fallout4/Havok/BShkbAnimationGraph.h deleted file mode 100644 index 0cb15e5c8..000000000 --- a/Code/client/Games/Fallout4/Havok/BShkbAnimationGraph.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -struct BShkbHkxDB; -struct hkbBehaviorGraph; - -struct BShkbAnimationGraph -{ - virtual ~BShkbAnimationGraph(){}; - - uint8_t pad8[0x370 - 0x8]; - - BShkbHkxDB* hkxDB; // 370 - hkbBehaviorGraph* behaviorGraph; // 378 -}; diff --git a/Code/client/Games/Fallout4/Havok/BShkbHkxDB.h b/Code/client/Games/Fallout4/Havok/BShkbHkxDB.h deleted file mode 100644 index 8b4764f93..000000000 --- a/Code/client/Games/Fallout4/Havok/BShkbHkxDB.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -struct BShkbHkxDB -{ - virtual ~BShkbHkxDB(); - - uint8_t pad8[0x84 - 0x8]; - hkHashTable animationVariables; // 84 -}; - -static_assert(offsetof(BShkbHkxDB, animationVariables) == 0x84); diff --git a/Code/client/Games/Fallout4/Havok/hkHashTable.h b/Code/client/Games/Fallout4/Havok/hkHashTable.h deleted file mode 100644 index f31f9d718..000000000 --- a/Code/client/Games/Fallout4/Havok/hkHashTable.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -#pragma pack(push, 1) // This structure is packed in havok - -struct hkHashTable -{ - struct Entry - { - BSFixedString key; - int32_t value; - uint32_t padC; - Entry* next; - }; - - uint32_t bucketCount; // 0 - uint8_t pad4[0xC - 0x4]; // 4 - void* end; // C - uint8_t pad[0x1C - 0x14]; - Entry* buckets; // 1C -}; - -static_assert(offsetof(hkHashTable, end) == 0xC); -static_assert(offsetof(hkHashTable, buckets) == 0x1C); - -#pragma pack(pop) diff --git a/Code/client/Games/Fallout4/Havok/hkbBehaviorGraph.h b/Code/client/Games/Fallout4/Havok/hkbBehaviorGraph.h deleted file mode 100644 index a6009268c..000000000 --- a/Code/client/Games/Fallout4/Havok/hkbBehaviorGraph.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -struct hkbStateMachine; - -struct hkbBehaviorGraph -{ - virtual ~hkbBehaviorGraph(); - - uint8_t pad8[0xC0 - 0x8]; - hkbStateMachine* stateMachine; - uint8_t padC8[0x110 - 0xC8]; - hkbVariableValueSet* animationVariables; // 110 -}; diff --git a/Code/client/Games/Fallout4/Havok/hkbStateMachine.h b/Code/client/Games/Fallout4/Havok/hkbStateMachine.h deleted file mode 100644 index 2a15e6bc3..000000000 --- a/Code/client/Games/Fallout4/Havok/hkbStateMachine.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -struct hkbStateMachine -{ - virtual ~hkbStateMachine(); - - uint8_t pad8[0x38 - 0x8]; - char* name; -}; - -static_assert(offsetof(hkbStateMachine, name) == 0x38); diff --git a/Code/client/Games/Fallout4/Havok/hkbVariableValueSet.h b/Code/client/Games/Fallout4/Havok/hkbVariableValueSet.h deleted file mode 100644 index 0396a48f9..000000000 --- a/Code/client/Games/Fallout4/Havok/hkbVariableValueSet.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -// TODO: this should be a template -struct hkbVariableValueSet -{ - virtual ~hkbVariableValueSet(); - - uint8_t pad8[0x8]; // 8 - uint32_t* data; // 10 - uint32_t size; // 18 -}; - -static_assert(offsetof(hkbVariableValueSet, data) == 0x10); -static_assert(offsetof(hkbVariableValueSet, size) == 0x18); diff --git a/Code/client/Games/Fallout4/Interface/IMenu.cpp b/Code/client/Games/Fallout4/Interface/IMenu.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/Code/client/Games/Fallout4/Interface/IMenu.h b/Code/client/Games/Fallout4/Interface/IMenu.h deleted file mode 100644 index 960c893db..000000000 --- a/Code/client/Games/Fallout4/Interface/IMenu.h +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once - -class UserEvents -{ -public: - enum INPUT_CONTEXT_ID : int - { - ICI_MAIN_GAMEPLAY = 0x0, - ICI_BASIC_MENU_NAV = 0x1, - ICI_THUMB_NAV = 0x2, - ICI_VIRT_CONTROLLER = 0x3, - ICI_CURSOR = 0x4, - ICI_LTHUMB_CURSOR = 0x5, - ICI_CONSOLE = 0x6, - ICI_DEBUG_TEXT = 0x7, - ICI_BOOK = 0x8, - ICI_DEBUG_OVERLAY = 0x9, - ICI_TFC = 0xA, - ICI_DEBUG_MAP = 0xB, - ICI_LOCKPICK = 0xC, - ICI_VATS = 0xD, - ICI_VATS_PLAYBACK = 0xE, - ICI_MULTI_ACTIVATE = 0xF, - ICI_WORKSHOP = 0x10, - ICI_SCOPE = 0x11, - ICI_SITWAIT = 0x12, - ICI_LOOKSMENU = 0x13, - ICI_WORKSHOP_ADDENDUM = 0x14, - ICI_PAUSEMENU = 0x15, - ICI_LEVELUPMENU = 0x16, - ICI_LEVELUPMENU_PREVNEXT = 0x17, - ICI_MAINMENU = 0x18, - ICI_QUICKCONTAINERMENU = 0x19, - ICI_SPECIALACTIVATEROLLOVER = 0x1A, - ICI_TWOBUTTONROLLOVER = 0x1B, - ICI_QUICKCONTAINERMENU_PERK = 0x1C, - ICI_VERTIBIRD = 0x1D, - ICI_PLAYBINKMENU = 0x1E, - ICI_ROBOT_MOD_ADDENDUM = 0x1F, - ICI_CREATION_CLUB = 0x20, - ICI_COUNT = 0x21, - ICI_NONE = 0x22, - }; -}; - -struct __declspec(align(8)) BSInputEventUser -{ - void* __vftable /*VFT*/; - bool InputEventHandlingEnabled; -}; - -struct __declspec(align(8)) Scaleform_RefCountImplCore -{ - void* __vftable /*VFT*/; - volatile int RefCount; -}; - -struct IMenu : Scaleform_RefCountImplCore, BSInputEventUser -{ - enum UI_MENU_FLAGS : int32_t - { - UIMF_PAUSES_GAME = 0x1, - UIMF_ALWAYS_OPEN = 0x2, - UIMF_USES_CURSOR = 0x4, - UIMF_USES_MENU_CONTEXT = 0x8, - UIMF_MODAL = 0x10, - UIMF_FREEZE_FRAME_BACKGROUND = 0x20, - UIMF_ON_STACK = 0x40, - UIMF_DISABLE_PAUSE_MENU = 0x80, - UIMF_REQUIRES_UPDATE = 0x100, - UIMF_TOPMOST_RENDERED_MENU = 0x200, - UIMF_UPDATE_USES_CURSOR = 0x400, - UIMF_ALLOW_SAVING = 0x800, - UIMF_RENDERS_OFFSCREEN_TARGETS = 0x1000, - UIMF_INVENTORY_ITEM_MENU = 0x2000, - UIMF_DONT_HIDE_CURSOR_WHEN_TOPMOST = 0x4000, - UIMF_CUSTOM_RENDERING = 0x8000, - UIMF_ASSIGN_CURSOR_TO_RENDERER = 0x10000, - UIMF_APPLICATION_MENU = 0x20000, - UIMF_HAS_BUTTON_BAR = 0x40000, - UIMF_IS_TOP_BUTTON_BAR = 0x80000, - UIMF_ADVANCES_UNDER_PAUSE_MENU = 0x100000, - UIMF_RENDERS_UNDER_PAUSE_MENU = 0x200000, - UIMF_USES_BLURRED_BACKGROUND = 0x400000, - UIMF_COMPANION_APP_ALLOWED = 0x800000, - UIMF_FREEZE_FRAME_PAUSE = 0x1000000, - UIMF_SKIP_RENDER_DURING_FREEZE_FRAME_SCREENSHOT = 0x2000000, - UIMF_LARGE_SCALEFORM_RENDER_CACHE_MODE = 0x4000000, - UIMF_USES_MOVEMENT_TO_DIRECTION = 0x8000000, - }; - - void SetFlag(UI_MENU_FLAGS auiFlag) - { - int* val = reinterpret_cast(&uiMenuFlags); - *val |= auiFlag; - } - - void ClearFlag(UI_MENU_FLAGS auiFlag) - { - int* val = reinterpret_cast(&uiMenuFlags); - *val &= ~auiFlag; - } - - bool PausesGame() const { return uiMenuFlags & UIMF_PAUSES_GAME; } - - bool FreezesBackground() const { return uiMenuFlags & UIMF_FREEZE_FRAME_BACKGROUND; } - - bool FreezesFramePause() const { return uiMenuFlags & UIMF_FREEZE_FRAME_PAUSE; } - - // force the game to generate a vt - virtual void m1() = 0; - - char menuObj[0x20 - 8]; // scaleform var. - void* pMovie; - BSFixedString CustomRendererName; - BSFixedString MenuName; - UI_MENU_FLAGS uiMenuFlags; - uint32_t AdvanceWithoutRenderCount; // atomic - bool bPassesTopMenuTest; - bool bMenuCanBeVisible; - bool bHasQuadsForCumstomRenderer; - bool bHasDoneFirstAdvanceMovie; - uint8_t ucDepthPriority; - UserEvents::INPUT_CONTEXT_ID eInputContext; -}; - -static_assert(offsetof(IMenu, IMenu::uiMenuFlags) == 0x58); -static_assert(sizeof(IMenu) == 0x70); diff --git a/Code/client/Games/Fallout4/Interface/UI.cpp b/Code/client/Games/Fallout4/Interface/UI.cpp deleted file mode 100644 index 9e18edf5b..000000000 --- a/Code/client/Games/Fallout4/Interface/UI.cpp +++ /dev/null @@ -1,329 +0,0 @@ -#include "UI.h" -#include "IMenu.h" - -UI* UI::Get() -{ - POINTER_FALLOUT4(UI*, s_instance, 548588); - return *s_instance.Get(); -} - -bool UI::GetMenuOpen(const BSFixedString& acName) const -{ - if (acName.data == nullptr) - return false; - - TP_THIS_FUNCTION(TMenuSystem_IsOpen, bool, const UI, const BSFixedString&); - POINTER_FALLOUT4(TMenuSystem_IsOpen, s_isMenuOpen, 1065115); - return TiltedPhoques::ThisCall(s_isMenuOpen.Get(), this, acName); -} - -IMenu* UI::FindMenuByName(const char* acName) -{ - for (const auto& it : menuMap) - { - if (!strcmp(it.key.AsAscii(), acName)) - return it.value.spMenu; - } - return nullptr; -} - -void UI::PrintMenuMap() -{ - for (const auto& it : menuMap) - { - spdlog::info("{} @ {}", it.key.AsAscii(), fmt::ptr(it.value.spMenu)); - } -} - -void UI::PrintActiveMenus() -{ - auto findName = [&](IMenu* apMenu) -> const char* - { - for (const auto& it : menuMap) - { - if (it.value.spMenu == apMenu) - return it.key.AsAscii(); - } - return nullptr; - }; - - for (IMenu* pMenu : MenuStack) - { - spdlog::info("{}", findName(pMenu)); - } -} - -static void UnfreezeMenu(IMenu* apEntry) -{ - if (apEntry->PausesGame()) - apEntry->ClearFlag(IMenu::UIMF_PAUSES_GAME); - - if (apEntry->FreezesBackground()) - apEntry->ClearFlag(IMenu::UIMF_FREEZE_FRAME_BACKGROUND); - - if (apEntry->FreezesFramePause()) - apEntry->ClearFlag(IMenu::UIMF_FREEZE_FRAME_PAUSE); -} - -/* All known menus: -StreamingInstallMenu @ 0x0 -PipboyOpeningSequenceMenu @ 0x0 -MessageBoxMenu @ 0x0 -CursorMenu @ 0x0 -MainMenu @ 0x0 -TerminalHolotapeMenu @ 0x0 -BarterMenu @ 0x0 -TerminalMenuButtons @ 0x0 -SleepWaitMenu @ 0x0 -PromptMenu @ 0x0 -TutorialMenu @ 0x0 -PowerArmorModMenu @ 0x0 -TerminalMenu @ 0x0 -ExamineConfirmMenu @ 0x0 -TitleSequenceMenu @ 0x0 -SitWaitMenu @ 0x0 -RobotModMenu @ 0x0 -FavoritesMenu @ 0x0 -GenericMenu @ 0x0 -PipboyHolotapeMenu @ 0x0 -LoadingMenu @ 0x0 -PowerArmorHUDMenu @ 0x0 -BookMenu @ 0x0 -Console @ 0x0 -ButtonBarMenu @ 0x20a51ed70 -ConsoleNativeUIMenu @ 0x0 -PlayBinkMenu @ 0x0 -LevelUpMenu @ 0x0 -FaderMenu @ 0x20a0aa4f0 -PauseMenu @ 0x0 -CreditsMenu @ 0x0 -VignetteMenu @ 0x0 -ScopeMenu @ 0x0 -HUDMenu @ 0x20b0b8b40 -MultiActivateMenu @ 0x0 -LooksMenu @ 0x0 -DialogueMenu @ 0x0 -LockpickingMenu @ 0x0 -ExamineMenu @ 0x0 -CreationClubMenu @ 0x0 -Workshop_CaravanMenu @ 0x0 -SPECIALMenu @ 0x0 -ContainerMenu @ 0x0 -VertibirdMenu @ 0x0 -CookingMenu @ 0x0 -PipboyMenu @ 0x0 -VATSMenu @ 0x0 -SafeZoneMenu @ 0x0 -WorkshopMenu @ 0x0 -StreamingInstallMenu @ 0x0 -PipboyOpeningSequenceMenu @ 0x0 -MessageBoxMenu @ 0x0 -CursorMenu @ 0x0 -MainMenu @ 0x0 -TerminalHolotapeMenu @ 0x0 -BarterMenu @ 0x0 -TerminalMenuButtons @ 0x0 -SleepWaitMenu @ 0x0 -PromptMenu @ 0x0 -TutorialMenu @ 0x0 -PowerArmorModMenu @ 0x0 -TerminalMenu @ 0x0 -ExamineConfirmMenu @ 0x0 -TitleSequenceMenu @ 0x0 -SitWaitMenu @ 0x0 -RobotModMenu @ 0x0 -FavoritesMenu @ 0x0 -GenericMenu @ 0x0 -PipboyHolotapeMenu @ 0x0 -LoadingMenu @ 0x0 -PowerArmorHUDMenu @ 0x0 -BookMenu @ 0x0 -Console @ 0x0 -ButtonBarMenu @ 0x20a51ed70 -ConsoleNativeUIMenu @ 0x0 -PlayBinkMenu @ 0x0 -LevelUpMenu @ 0x0 -FaderMenu @ 0x20a0aa4f0 -PauseMenu @ 0x0 -CreditsMenu @ 0x0 -VignetteMenu @ 0x0 -ScopeMenu @ 0x0 -HUDMenu @ 0x20b0b8b40 -MultiActivateMenu @ 0x0 -LooksMenu @ 0x0 -DialogueMenu @ 0x0 -LockpickingMenu @ 0x0 -ExamineMenu @ 0x0 -CreationClubMenu @ 0x0 -Workshop_CaravanMenu @ 0x0 -SPECIALMenu @ 0x0 -ContainerMenu @ 0x0 -VertibirdMenu @ 0x0 -CookingMenu @ 0x0 -PipboyMenu @ 0x0 -VATSMenu @ 0x0 -SafeZoneMenu @ 0x0 -WorkshopMenu @ 0x0 -StreamingInstallMenu @ 0x0 -PipboyOpeningSequenceMenu @ 0x0 -MessageBoxMenu @ 0x0 -CursorMenu @ 0x0 -MainMenu @ 0x0 -TerminalHolotapeMenu @ 0x0 -BarterMenu @ 0x0 -TerminalMenuButtons @ 0x0 -SleepWaitMenu @ 0x0 -PromptMenu @ 0x0 -TutorialMenu @ 0x0 -PowerArmorModMenu @ 0x0 -TerminalMenu @ 0x0 -ExamineConfirmMenu @ 0x0 -TitleSequenceMenu @ 0x0 -SitWaitMenu @ 0x0 -RobotModMenu @ 0x0 -FavoritesMenu @ 0x0 -GenericMenu @ 0x0 -PipboyHolotapeMenu @ 0x0 -LoadingMenu @ 0x0 -PowerArmorHUDMenu @ 0x0 -BookMenu @ 0x0 -Console @ 0x0 -ButtonBarMenu @ 0x20a51ed70 -ConsoleNativeUIMenu @ 0x0 -PlayBinkMenu @ 0x0 -LevelUpMenu @ 0x0 -FaderMenu @ 0x20a0aa4f0 -PauseMenu @ 0x0 -CreditsMenu @ 0x0 -VignetteMenu @ 0x0 -ScopeMenu @ 0x0 -HUDMenu @ 0x20b0b8b40 -MultiActivateMenu @ 0x0 -LooksMenu @ 0x0 -DialogueMenu @ 0x0 -LockpickingMenu @ 0x0 -ExamineMenu @ 0x0 -CreationClubMenu @ 0x0 -Workshop_CaravanMenu @ 0x0 -SPECIALMenu @ 0x0 -ContainerMenu @ 0x0 -VertibirdMenu @ 0x0 -CookingMenu @ 0x0 -PipboyMenu @ 0x0 -VATSMenu @ 0x0 -SafeZoneMenu @ 0x0 -WorkshopMenu @ 0x0 -StreamingInstallMenu @ 0x0 -PipboyOpeningSequenceMenu @ 0x0 -MessageBoxMenu @ 0x0 -CursorMenu @ 0x0 -MainMenu @ 0x0 -TerminalHolotapeMenu @ 0x0 -BarterMenu @ 0x0 -TerminalMenuButtons @ 0x0 -SleepWaitMenu @ 0x0 -PromptMenu @ 0x0 -TutorialMenu @ 0x0 -PowerArmorModMenu @ 0x0 -TerminalMenu @ 0x0 -ExamineConfirmMenu @ 0x0 -TitleSequenceMenu @ 0x0 -SitWaitMenu @ 0x0 -RobotModMenu @ 0x0 -FavoritesMenu @ 0x0 -GenericMenu @ 0x0 -PipboyHolotapeMenu @ 0x0 -LoadingMenu @ 0x0 -PowerArmorHUDMenu @ 0x0 -BookMenu @ 0x0 -Console @ 0x0 -ButtonBarMenu @ 0x20a51ed70 -ConsoleNativeUIMenu @ 0x0 -PlayBinkMenu @ 0x0 -LevelUpMenu @ 0x0 -FaderMenu @ 0x20a0aa4f0 -PauseMenu @ 0x0 -CreditsMenu @ 0x0 -VignetteMenu @ 0x0 -ScopeMenu @ 0x0 -HUDMenu @ 0x20b0b8b40 -MultiActivateMenu @ 0x0 -LooksMenu @ 0x0 -DialogueMenu @ 0x0 -LockpickingMenu @ 0x0 -ExamineMenu @ 0x0 -CreationClubMenu @ 0x0 -Workshop_CaravanMenu @ 0x0 -SPECIALMenu @ 0x0 -ContainerMenu @ 0x0 -VertibirdMenu @ 0x0 -CookingMenu @ 0x0 -PipboyMenu @ 0x0 -VATSMenu @ 0x0 -SafeZoneMenu @ 0x0 -WorkshopMenu @ 0x0 -*/ - -static constexpr const char* kAllowList[] = { - "ConsoleNativeUIMenu", - "Console", - "PauseMenu", - /* "PipboyMenu",*/ "TerminalMenu", - "SleepWaitMenu", - "LockpickingMenu", - "MessageBoxMenu", - "WorkshopMenu"}; - -static void (*UI_AddToMenuStack_Real)(UI*, UI::UIMenuEntry*); - -void UI_AddToMenuStack(UI* apSelf, UI::UIMenuEntry* menuEntry) -{ - if (!menuEntry->spMenu) - return; - - if (!World::Get().GetTransport().IsConnected()) - return UI_AddToMenuStack_Real(apSelf, menuEntry); - - // NOTE(Force): could also compare by RTTI later on... - for (const char* item : kAllowList) - { - if (auto* pMenu = apSelf->FindMenuByName(item)) - { - if (pMenu == menuEntry->spMenu) - UnfreezeMenu(menuEntry->spMenu); - } - } - - UI_AddToMenuStack_Real(apSelf, menuEntry); -} - -static TiltedPhoques::Initializer s_uiHooks( - []() - { - const VersionDbPtr mainMenuCtor(1079381); - TiltedPhoques::Put(mainMenuCtor.Get() + 0x2DC, 0xE990); - - // Remove engagement check, jump directly into main state. - TiltedPhoques::Nop(mainMenuCtor.Get() + 0x279, 14); // 0x1412A01A9 - - // nuke entire isinputallowed stuff - const VersionDbPtr mainMenuLoop(1512372); - TiltedPhoques::Nop(mainMenuLoop.Get() + (0x2D - 5), 0x29); // 0x1412A0E48 - - struct C : TiltedPhoques::CodeGenerator - { - C(uint8_t* loc) - { - mov(r8d, 0); // hide the prompt - jmp_S(loc + 8); - } - } gen(mainMenuLoop.Get() + 0x51); - TiltedPhoques::Jump(mainMenuLoop.Get() + 0x51, gen.getCode()); - TiltedPhoques::Nop(mainMenuLoop.Get() + 0x51 + 5, 3); - - const VersionDbPtr handleInput(1001404); - TiltedPhoques::Nop(handleInput.Get() + 0x56, 10); // 0x1412A1B76 - - const VersionDbPtr processMenus(239711); // 0x142042F08 - TiltedPhoques::SwapCall(processMenus.Get() + 0xAD8, UI_AddToMenuStack_Real, &UI_AddToMenuStack); - }); diff --git a/Code/client/Games/Fallout4/Interface/UI.h b/Code/client/Games/Fallout4/Interface/UI.h deleted file mode 100644 index 57110f3f5..000000000 --- a/Code/client/Games/Fallout4/Interface/UI.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -struct UI -{ - static UI* Get(); - - using TCreate = IMenu*(UIMessage*); - - struct UIMenuEntry - { - IMenu* spMenu; // Actually a scaleform ptr TODO: reverse that stuff. - TCreate* create; - void (*pfStaticUpdate)(); - }; - - IMenu* FindMenuByName(const char* acName); - bool GetMenuOpen(const BSFixedString& acName) const; - - void PrintMenuMap(); - void PrintActiveMenus(); - -public: - uint8_t pad0[0x1A8 - sizeof(GameArray)]; - GameArray MenuStack; // actually stores a smart ptr - creation::BSTHashMap menuMap; - uint8_t pad1D8[0x250 - 0x1D8]; -}; - -static_assert(offsetof(UI, menuMap) == 0x1A8); -static_assert(sizeof(UI) == 0x250); diff --git a/Code/client/Games/Fallout4/LoadingScreen.cpp b/Code/client/Games/Fallout4/LoadingScreen.cpp deleted file mode 100644 index 58a68c31b..000000000 --- a/Code/client/Games/Fallout4/LoadingScreen.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -#include -#include - -struct ScaleFormValue -{ - uint8_t pad0[0x14]; - uint32_t unk14; - uint8_t pad18[0x30 - 0x18]; - BSFixedString data; -}; - -struct ScaleFormContext -{ - uint8_t pad0[0xE8]; - ScaleFormValue* value; - uint8_t padF0[0x270 - 0xF0]; - uint8_t isSet; -}; - -using TRequestLoadingText = void(__fastcall)(ScaleFormContext* apContext); -TRequestLoadingText* RealRequestLoadingText; -void RequestLoadingText(ScaleFormContext* apContext) -{ - TP_EMPTY_HOOK_PLACEHOLDER; - - BSFixedString str("Welcome to Fallout Together | Show some love to the devs!"); - - if (apContext && apContext->value) - apContext->value->data.data = str.data; - - RealRequestLoadingText(apContext); -} - -static TiltedPhoques::Initializer s_loadingScreenHooks( - []() - { - POINTER_FALLOUT4(TRequestLoadingText, s_requestLoadingText, 277977); - - RealRequestLoadingText = s_requestLoadingText.Get(); - - TP_HOOK(&RealRequestLoadingText, RequestLoadingText); - }); diff --git a/Code/client/Games/Fallout4/LoadingScreen.h b/Code/client/Games/Fallout4/LoadingScreen.h deleted file mode 100644 index 6f70f09be..000000000 --- a/Code/client/Games/Fallout4/LoadingScreen.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/Code/client/Games/Fallout4/Magic/ActorMagicCaster.h b/Code/client/Games/Fallout4/Magic/ActorMagicCaster.h deleted file mode 100644 index f09496045..000000000 --- a/Code/client/Games/Fallout4/Magic/ActorMagicCaster.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "MagicCaster.h" - -struct ActorMagicCaster : MagicCaster -{ - uint8_t pad48[0xB8 - 0x48]; - Actor* pCasterActor; - uint8_t padC0[0x100 - 0xC0]; -}; - -static_assert(offsetof(ActorMagicCaster, pad48) == 0x48); -static_assert(sizeof(ActorMagicCaster) == 0x100); diff --git a/Code/client/Games/Fallout4/Magic/EffectItem.h b/Code/client/Games/Fallout4/Magic/EffectItem.h deleted file mode 100644 index 57122f06c..000000000 --- a/Code/client/Games/Fallout4/Magic/EffectItem.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -struct EffectSetting; - -struct EffectItemData -{ - float fMagnitude; - int32_t iArea; - int32_t iDuration; -}; - -struct EffectItem -{ - EffectItemData data; - EffectSetting* pEffectSetting; - float fRawCost; - void* Conditions; -}; diff --git a/Code/client/Games/Fallout4/Magic/EffectSetting.h b/Code/client/Games/Fallout4/Magic/EffectSetting.h deleted file mode 100644 index cb7f81cf9..000000000 --- a/Code/client/Games/Fallout4/Magic/EffectSetting.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -struct EffectSetting : TESForm -{ - uint8_t pad20[0xD0 - 0x20]; - EffectArchetypes::ArchetypeID eArchetype; - uint8_t padD4[0x1B0 - 0xD4]; -}; - -static_assert(sizeof(EffectSetting) == 0x1B0); diff --git a/Code/client/Games/Fallout4/Magic/MagicCaster.h b/Code/client/Games/Fallout4/Magic/MagicCaster.h deleted file mode 100644 index 25e1dde99..000000000 --- a/Code/client/Games/Fallout4/Magic/MagicCaster.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -struct MagicCaster -{ - virtual ~MagicCaster(); - - enum State : int32_t - { - DERIVED_ATTRIBUTE = 0x0, - ATTRIBUTE = 0x1, - SKILL = 0x2, - AI_ATTRIBUTE = 0x3, - RESISTANCE = 0x4, - CONDITION = 0x5, - CHARGE = 0x6, - INT_VALUE = 0x7, - VARIABLE = 0x8, - RESOURCE = 0x9, - TYPE_COUNT = 0xA, - }; - - GameArray hSounds; - int32_t hDesiredTarget; - MagicItem* pCurrentSpell; - MagicCaster::State eState; - float fCastingTimer; - float fCurrentSpellCost; - float fMagnitudeOverride; - float fNextTargetUpdate; - float fProjectileTimer; -}; diff --git a/Code/client/Games/Fallout4/Magic/MagicItem.h b/Code/client/Games/Fallout4/Magic/MagicItem.h deleted file mode 100644 index 335c6b003..000000000 --- a/Code/client/Games/Fallout4/Magic/MagicItem.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include -#include - -struct EffectItem; -struct EffectSetting; - -struct MagicItem : TESBoundObject, TESFullName, BGSKeywordForm -{ - // TODO: ft - EffectItem* GetEffect(const uint32_t aEffectId) noexcept - { - return nullptr; - } - - GameArray listOfEffects; - int32_t iHostileCount; - EffectSetting* pAVEffectSetting; - uint32_t uiPreloadCount; - void* spPreloadedItem; -}; diff --git a/Code/client/Games/Fallout4/Magic/MagicTarget.cpp b/Code/client/Games/Fallout4/Magic/MagicTarget.cpp deleted file mode 100644 index 9d2d22858..000000000 --- a/Code/client/Games/Fallout4/Magic/MagicTarget.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "MagicTarget.h" - -#include -#include -#include -#include -#include "EffectItem.h" -#include "EffectSetting.h" -#include "MagicItem.h" - -#include - -#include - -TP_THIS_FUNCTION(TAddTarget, bool, MagicTarget, MagicTarget::AddTargetData& arData); -TP_THIS_FUNCTION(TCheckAddEffectTargetData, bool, MagicTarget::AddTargetData, void* arArgs, float afResistance); - -static TAddTarget* RealAddTarget = nullptr; -static TCheckAddEffectTargetData* RealCheckAddEffectTargetData = nullptr; - -static thread_local bool s_autoSucceedEffectCheck = false; - -bool MagicTarget::AddTarget(AddTargetData& arData) noexcept -{ - s_autoSucceedEffectCheck = true; - bool result = TiltedPhoques::ThisCall(RealAddTarget, this, arData); - s_autoSucceedEffectCheck = false; - return result; -} - -Actor* MagicTarget::GetTargetAsActor() -{ - TP_THIS_FUNCTION(TGetTargetAsActor, Actor*, MagicTarget); - POINTER_FALLOUT4(TGetTargetAsActor, getTargetAsActor, 129826); - return TiltedPhoques::ThisCall(getTargetAsActor, this); -} - -// TODO: ft (verify) -bool TP_MAKE_THISCALL(HookAddTarget, MagicTarget, MagicTarget::AddTargetData& arData) -{ - Actor* pTargetActor = apThis->GetTargetAsActor(); - if (!pTargetActor) - return TiltedPhoques::ThisCall(RealAddTarget, apThis, arData); - - ActorExtension* pTargetActorEx = pTargetActor->GetExtension(); - - if (!pTargetActorEx) - return TiltedPhoques::ThisCall(RealAddTarget, apThis, arData); - - if (ScopedSpellCastOverride::IsOverriden()) - return TiltedPhoques::ThisCall(RealAddTarget, apThis, arData); - - AddTargetEvent addTargetEvent{}; - addTargetEvent.TargetID = pTargetActor->formID; - addTargetEvent.SpellID = arData.pSpell->formID; - addTargetEvent.EffectID = arData.pEffectItem->pEffectSetting->formID; - addTargetEvent.Magnitude = arData.fMagnitude; - - if (pTargetActorEx->IsLocalPlayer()) - { - bool result = TiltedPhoques::ThisCall(RealAddTarget, apThis, arData); - if (result) - World::Get().GetRunner().Trigger(addTargetEvent); - return result; - } - else if (pTargetActorEx->IsRemotePlayer()) - { - return false; - } - - if (arData.pCaster) - { - ActorExtension* pCasterExtension = arData.pCaster->GetExtension(); - if (pCasterExtension->IsLocalPlayer()) - { - bool result = TiltedPhoques::ThisCall(RealAddTarget, apThis, arData); - if (result) - World::Get().GetRunner().Trigger(addTargetEvent); - return result; - } - else if (pCasterExtension->IsRemotePlayer()) - { - return false; - } - } - - if (pTargetActorEx->IsLocal()) - { - bool result = TiltedPhoques::ThisCall(RealAddTarget, apThis, arData); - if (result) - World::Get().GetRunner().Trigger(addTargetEvent); - return result; - } - else - { - return false; - } -} - -bool TP_MAKE_THISCALL(HookCheckAddEffectTargetData, MagicTarget::AddTargetData, void* arArgs, float afResistance) -{ - if (s_autoSucceedEffectCheck) - return true; - - return TiltedPhoques::ThisCall(RealCheckAddEffectTargetData, apThis, arArgs, afResistance); -} - -static TiltedPhoques::Initializer s_magicTargetHooks( - []() - { - POINTER_FALLOUT4(TAddTarget, addTarget, 385036); - POINTER_FALLOUT4(TCheckAddEffectTargetData, checkAddEffectTargetData, 113034); - - RealAddTarget = addTarget.Get(); - RealCheckAddEffectTargetData = checkAddEffectTargetData.Get(); - - TP_HOOK(&RealAddTarget, HookAddTarget); - TP_HOOK(&RealCheckAddEffectTargetData, HookCheckAddEffectTargetData); - }); diff --git a/Code/client/Games/Fallout4/Magic/MagicTarget.h b/Code/client/Games/Fallout4/Magic/MagicTarget.h deleted file mode 100644 index 724ca147c..000000000 --- a/Code/client/Games/Fallout4/Magic/MagicTarget.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include - -struct Actor; -struct EffectItem; -struct MagicItem; -struct TESBoundObject; - -struct MagicTarget -{ - struct IPostCreationModification; - struct ResultsCollector; - - struct AddTargetData - { - Actor* pCaster; - MagicItem* pSpell; - EffectItem* pEffectItem; - TESBoundObject* pSource; - MagicTarget::IPostCreationModification* pCallback; - MagicTarget::ResultsCollector* pResultsCollector; - NiPoint3 ExplosionLocation; - float fMagnitude; - MagicSystem::CastingSource eCastingSource; - bool bAreaTarget; - bool bDualCast; - }; - - struct SpellDispelData - { - const MagicItem* pSpell; - int32_t hCaster; - GamePtr spActiveEffect; - SpellDispelData* pNext; - }; - - enum Flag : int32_t - { - MTF_UPDATING = 0x1, - MTF_INVISIBLE = 0x2, - }; - - virtual ~MagicTarget(); - - Actor* GetTargetAsActor(); - - bool AddTarget(AddTargetData& arData) noexcept; - // this function actually adds the effect - bool CheckAddEffect(AddTargetData& arData) noexcept; - void DispelAllSpells(bool aNow) noexcept; - - SpellDispelData* pPostUpdateDispelList; - Flag ucFlags; -}; diff --git a/Code/client/Games/Fallout4/Misc/ActorState.h b/Code/client/Games/Fallout4/Misc/ActorState.h deleted file mode 100644 index ceabc534c..000000000 --- a/Code/client/Games/Fallout4/Misc/ActorState.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -struct ActorState -{ - virtual ~ActorState(); - - uint32_t flags1; - uint32_t flags2; - - bool IsWeaponDrawn() const noexcept { return ((flags2 >> 1) & 7) >= 3; } - // TODO: ft, does it need fully drawn check? - bool IsWeaponFullyDrawn() const noexcept { return IsWeaponDrawn(); } - - // TODO: ft (verify) - bool IsBleedingOut() const noexcept { return ((flags1 >> 17) & 0xFu) - 7 <= 1; } - - bool SetWeaponDrawn(bool aDraw) noexcept; -}; diff --git a/Code/client/Games/Fallout4/Misc/ActorValueOwner.h b/Code/client/Games/Fallout4/Misc/ActorValueOwner.h deleted file mode 100644 index a72fbb9a2..000000000 --- a/Code/client/Games/Fallout4/Misc/ActorValueOwner.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -struct ActorValueOwner -{ - enum class ForceMode : uint32_t - { - PERMANENT = 0, - TEMPORARY = 1, - DAMAGE = 2, - COUNT = 3, - }; - - virtual ~ActorValueOwner(); - - // TODO: refactor these names - virtual float GetValue(ActorValueInfo* apInfo) const noexcept; - virtual float GetMaxValue(ActorValueInfo* apInfo) const noexcept; - virtual float GetBaseValue(ActorValueInfo* apInfo) const noexcept; - virtual void sub_04(); - virtual void sub_05(); - virtual void ForceCurrent(ActorValueOwner::ForceMode aMode, ActorValueInfo* apInfo, float aValue) noexcept; - virtual void sub_07(); - virtual void RestoreValue(ActorValueInfo* apInfo, float aAmount) noexcept; - virtual void SetValue(ActorValueInfo* apInfo, float aValue) noexcept; -}; diff --git a/Code/client/Games/Fallout4/Misc/BSFixedString.h b/Code/client/Games/Fallout4/Misc/BSFixedString.h deleted file mode 100644 index e0bd0d0bc..000000000 --- a/Code/client/Games/Fallout4/Misc/BSFixedString.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include - -struct BSFixedString -{ - BSFixedString(const BSFixedString&) = delete; - BSFixedString& operator=(const BSFixedString&) = delete; - - struct Data - { - Data* next; - uint32_t flags; - uint32_t length; - Data* derived; - char data[1]; - - [[nodiscard]] const Data* GetExternData() const noexcept - { - const auto* pIterator = this; - - while (pIterator->flags & 0x4000) - pIterator = pIterator->derived; - - return pIterator; - } - - [[nodiscard]] bool IsAscii() const noexcept { return (GetExternData()->flags & 0x8000) == 0; } - - [[nodiscard]] const char* AsAscii() const { return reinterpret_cast(GetExternData()->data); } - - [[nodiscard]] const wchar_t* AsWide() const { return reinterpret_cast(GetExternData()->data); } - }; - - static_assert(offsetof(Data, data) == 0x18); - - // Be careful using this, the destructor does NOT release the memory, call Release manually if you wish to delete it - explicit BSFixedString(const char* acpData); - BSFixedString(BSFixedString&& aRhs) noexcept; - ~BSFixedString(); - - BSFixedString& operator=(BSFixedString&& aRhs) noexcept; - - void Release() noexcept; - void Set(const char* acpStr) noexcept; - - [[nodiscard]] bool IsAscii() const noexcept { return data->IsAscii(); } - - [[nodiscard]] const char* AsAscii() const { return data ? data->AsAscii() : nullptr; } - - [[nodiscard]] const wchar_t* AsWide() const { return data ? data->AsWide() : nullptr; } - - Data* data; -}; diff --git a/Code/client/Games/Fallout4/Misc/BSScript.cpp b/Code/client/Games/Fallout4/Misc/BSScript.cpp deleted file mode 100644 index e9e56eaa2..000000000 --- a/Code/client/Games/Fallout4/Misc/BSScript.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include - -#include - -BSScript::Variable::Variable() -{ -} - -BSScript::Variable::~Variable() noexcept -{ - Reset(); -} - -void BSScript::Variable::Reset() noexcept -{ - TP_THIS_FUNCTION(TReset, void, BSScript::Variable); - - POINTER_FALLOUT4(TReset, s_reset, 1183889); - - TiltedPhoques::ThisCall(s_reset, this); -} - -void BSScript::Variable::Clear() noexcept -{ - Reset(); - - type = kEmpty; -} - -template <> void BSScript::Variable::Set(int32_t aValue) noexcept -{ - Reset(); - - type = kInteger; - data.i = aValue; -} - -template <> void BSScript::Variable::Set(float aValue) noexcept -{ - Reset(); - - type = kFloat; - data.f = aValue; -} - -template <> void BSScript::Variable::Set(bool aValue) noexcept -{ - Reset(); - - type = kBoolean; - data.b = aValue; -} - -template <> void BSScript::Variable::Set(const char* acpValue) noexcept -{ - Reset(); - - type = kString; - auto pStr = reinterpret_cast(&data.s); - pStr->Set(acpValue); -} - -void BSScript::Statement::SetSize(uint32_t aCount) noexcept -{ - TP_THIS_FUNCTION(TSetSize, void, BSScript::Statement, uint32_t aCount); - - POINTER_FALLOUT4(TSetSize, s_setSize, 1293891); - - TiltedPhoques::ThisCall(s_setSize, this, aCount); -} diff --git a/Code/client/Games/Fallout4/Misc/BSScript.h b/Code/client/Games/Fallout4/Misc/BSScript.h deleted file mode 100644 index 6c25f6d66..000000000 --- a/Code/client/Games/Fallout4/Misc/BSScript.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include - -struct BSScript -{ - struct Variable - { - Variable(); - ~Variable() noexcept; - - void Reset() noexcept; - void Clear() noexcept; - - template void Set(T aValue) noexcept - { - // static_assert(false); - } - - enum Type : uint64_t - { - kEmpty, - kHandle, - kString, - kInteger, - kFloat, - kBoolean - }; - - union Data - { - int32_t i; - const char* s; - float f; - bool b; - }; - - Type type; - Data data; - }; - - struct Statement - { - void SetSize(uint32_t aCount) noexcept; - - uint8_t pad0[8]; - Variable* vars; - }; - - struct IVirtualMachine - { - virtual ~IVirtualMachine() = 0; - - virtual void sub_01(); - virtual void sub_02(); - virtual void sub_03(); - virtual void sub_04(); - virtual void sub_05(); - virtual void sub_06(); - virtual void sub_07(); - virtual void sub_08(); - virtual void sub_09(); - virtual void sub_0A(); - virtual void sub_0B(); - virtual void sub_0C(); - virtual void sub_0D(); - virtual void sub_0E(); - virtual void sub_0F(); - virtual void sub_10(); - virtual void sub_11(); - virtual void sub_12(); - virtual void sub_13(); - virtual void sub_14(); - virtual void sub_15(); - virtual void sub_16(); - virtual void sub_17(); - virtual void sub_18(); - virtual void sub_19(); - virtual void sub_1A(); - virtual void sub_1B(); - virtual void sub_1C(); - virtual void sub_1D(); - virtual void sub_1E(); - virtual void sub_1F(); - virtual void sub_20(); - virtual void sub_21(); - virtual void sub_22(); - virtual void sub_23(); - virtual void sub_24(); - virtual void sub_25(); - virtual void sub_26(); - virtual void sub_27(); - virtual void sub_28(); - virtual void sub_29(); - virtual void sub_2A(); - virtual void sub_2B(); - virtual void sub_2C(); - virtual void SendEvent(uint64_t aId, const BSFixedString& acEventName, std::function& aFunctor) const noexcept; - }; -}; - -template <> void BSScript::Variable::Set(int32_t aValue) noexcept; -template <> void BSScript::Variable::Set(float aValue) noexcept; -template <> void BSScript::Variable::Set(bool aValue) noexcept; -template <> void BSScript::Variable::Set(const char* acpValue) noexcept; diff --git a/Code/client/Games/Fallout4/Misc/BSString.h b/Code/client/Games/Fallout4/Misc/BSString.h deleted file mode 100644 index 9fc1f88bd..000000000 --- a/Code/client/Games/Fallout4/Misc/BSString.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -struct BSString -{ - BSString() - : data{nullptr} - , length{0} - , capacity{0} - { - } - ~BSString(); - - [[nodiscard]] const char* AsAscii() { return data; } - -private: - const char* data; - uint16_t length; - uint16_t capacity; -}; diff --git a/Code/client/Games/Fallout4/Misc/GameVM.cpp b/Code/client/Games/Fallout4/Misc/GameVM.cpp deleted file mode 100644 index 3f52ef53c..000000000 --- a/Code/client/Games/Fallout4/Misc/GameVM.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include - -#include - -GameVM* GameVM::Get() -{ - POINTER_FALLOUT4(GameVM*, s_instance, 996228); - - return *s_instance.Get(); -} diff --git a/Code/client/Games/Fallout4/Misc/GameVM.h b/Code/client/Games/Fallout4/Misc/GameVM.h deleted file mode 100644 index b0a857139..000000000 --- a/Code/client/Games/Fallout4/Misc/GameVM.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -struct GameVM -{ - virtual ~GameVM(); - - static GameVM* Get(); - - uint8_t pad8[0xB0 - 0x8]; - BSScript::IVirtualMachine* virtualMachine; -}; diff --git a/Code/client/Games/Fallout4/Misc/MiddleProcess.h b/Code/client/Games/Fallout4/Misc/MiddleProcess.h deleted file mode 100644 index 55b0159ca..000000000 --- a/Code/client/Games/Fallout4/Misc/MiddleProcess.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -struct bhkCharRigidBodyController; - -struct MiddleProcess -{ - uint8_t unk0[0xC0]; - float direction; // C0 - uint8_t unkC4[0x3D0 - 0xC4]; - bhkCharRigidBodyController* rigidBodyController; -}; - -static_assert(offsetof(MiddleProcess, direction) == 0xC0); -static_assert(offsetof(MiddleProcess, rigidBodyController) == 0x3D0); diff --git a/Code/client/Games/Fallout4/Misc/NEW_REFR_DATA.cpp b/Code/client/Games/Fallout4/Misc/NEW_REFR_DATA.cpp deleted file mode 100644 index b5a2574f5..000000000 --- a/Code/client/Games/Fallout4/Misc/NEW_REFR_DATA.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include - -#include - -NEW_REFR_DATA::NEW_REFR_DATA() -{ - POINTER_FALLOUT4(void*, s_vtbl, 1139813); - // Set the vtable - this->vtbl = s_vtbl.Get(); - - unk40[0] = unk40[1] = unk40[2] = unk40[3] = 0; - unk50[0] = unk50[1] = unk50[2] = unk50[3] = 0; - - unk60 = nullptr; - unk68 = 0x1000000; - randomFlag = 1; -} diff --git a/Code/client/Games/Fallout4/Misc/NEW_REFR_DATA.h b/Code/client/Games/Fallout4/Misc/NEW_REFR_DATA.h deleted file mode 100644 index 8f60d24bf..000000000 --- a/Code/client/Games/Fallout4/Misc/NEW_REFR_DATA.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -struct TESObjectCELL; -struct TESWorldSpace; -struct TESObjectREFR; -struct TESForm; - -struct NEW_REFR_DATA -{ - NEW_REFR_DATA(); - - void** vtbl; // 0 - NiPoint3 postion; // 8 - NiPoint3 rotation; // 14 - TESForm* baseForm; // 20 - TESObjectCELL* parentCell; // 28 - TESWorldSpace* worldspace; // 30 - TESObjectREFR* refrToPlace; // 38 - uint32_t unk40[4]; // 40 - uint32_t unk50[4]; // 50 - void* unk60; // 60 - uint32_t unk68; // 68 set to 0x1000000 - uint16_t randomFlag; // 6C set to 1 -}; - -static_assert(sizeof(NEW_REFR_DATA) == 0x70); -static_assert(offsetof(NEW_REFR_DATA, rotation) == 0x14); -static_assert(offsetof(NEW_REFR_DATA, randomFlag) == 0x6C); diff --git a/Code/client/Games/Fallout4/Misc/NativeFunction.h b/Code/client/Games/Fallout4/Misc/NativeFunction.h deleted file mode 100644 index f9d2bacbc..000000000 --- a/Code/client/Games/Fallout4/Misc/NativeFunction.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -struct NativeFunction -{ - virtual ~NativeFunction() = 0; - - void* pad8; - BSFixedString functionName; - BSFixedString typeName; - uint8_t pad20[0x50 - 0x20]; - void* functionAddress; -}; - -static_assert(offsetof(NativeFunction, functionName) == 0x10); -static_assert(offsetof(NativeFunction, typeName) == 0x18); -static_assert(offsetof(NativeFunction, functionAddress) == 0x50); diff --git a/Code/client/Games/Fallout4/Misc/TBO_InstanceData.h b/Code/client/Games/Fallout4/Misc/TBO_InstanceData.h deleted file mode 100644 index 021a1422e..000000000 --- a/Code/client/Games/Fallout4/Misc/TBO_InstanceData.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -struct TBO_InstanceData : BSIntrusiveRefCounted -{ - virtual ~TBO_InstanceData(); -}; diff --git a/Code/client/Games/Fallout4/Misc/TintMask.h b/Code/client/Games/Fallout4/Misc/TintMask.h deleted file mode 100644 index 6f70f09be..000000000 --- a/Code/client/Games/Fallout4/Misc/TintMask.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/Code/client/Games/Fallout4/Misc/WeatherManager.cpp b/Code/client/Games/Fallout4/Misc/WeatherManager.cpp deleted file mode 100644 index 0a274bc4c..000000000 --- a/Code/client/Games/Fallout4/Misc/WeatherManager.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include - -#include - -WeatherManager* WeatherManager::Get() -{ - POINTER_FALLOUT4(WeatherManager*, s_instance, 7492); - - return *s_instance.Get(); -} diff --git a/Code/client/Games/Fallout4/Misc/WeatherManager.h b/Code/client/Games/Fallout4/Misc/WeatherManager.h deleted file mode 100644 index 0cc734c11..000000000 --- a/Code/client/Games/Fallout4/Misc/WeatherManager.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -struct WeatherManager -{ - static WeatherManager* Get(); - - uint8_t pad0[0x18]; -}; diff --git a/Code/client/Games/Fallout4/PlayerCharacter.cpp b/Code/client/Games/Fallout4/PlayerCharacter.cpp deleted file mode 100644 index 0b5e7e82f..000000000 --- a/Code/client/Games/Fallout4/PlayerCharacter.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "PlayerCharacter.h" - -#include -#include -#include - -int32_t PlayerCharacter::LastUsedCombatSkill = -1; - -void PlayerCharacter::SetDifficulty(const int32_t aDifficulty, bool aForceUpdate, bool aExpectGameDataLoaded) noexcept -{ - if (aDifficulty > 5 || aDifficulty < 0) - return; - - TP_THIS_FUNCTION(TSetDifficulty, void, PlayerCharacter, const int32_t aDifficulty, bool aForceUpdate, bool aExpectGameDataLoaded); - POINTER_FALLOUT4(TSetDifficulty, setDifficulty, 657345); - TiltedPhoques::ThisCall(setDifficulty, this, aDifficulty, aForceUpdate, aExpectGameDataLoaded); -} - -void PlayerCharacter::PayCrimeGoldToAllFactions() noexcept -{ - // TODO: fallout 4 doesn't have "bounties". - // Still, aggro should be removed somehow on respawn. -} - -// TODO: ft (verify) -NiPoint3 PlayerCharacter::RespawnPlayer() noexcept -{ - // Make bleedout state recoverable - SetNoBleedoutRecovery(false); - - DispelAllSpells(); - - // Reset health to max - // TODO(cosideci): there's a cleaner way to do this - ForceActorValue(ActorValueOwner::ForceMode::DAMAGE, ActorValueInfo::kHealth, 1000000); - - TESObjectCELL* pCell = nullptr; - - if (GetWorldSpace()) - { - // TP to Whiterun temple when killed in world space - TES* pTes = TES::Get(); - pCell = ModManager::Get()->GetCellFromCoordinates(pTes->centerGridX, pTes->centerGridY, GetWorldSpace(), false); - } - else - { - // TP to start of cell when killed in an interior - pCell = GetParentCell(); - } - - NiPoint3 pos{}; - NiPoint3 rot{}; - pCell->GetCOCPlacementInfo(&pos, &rot, true); - - MoveTo(pCell, pos); - - // Make bleedout state unrecoverable again for when the player goes down the next time - SetNoBleedoutRecovery(true); - - return pos; -} diff --git a/Code/client/Games/Fallout4/PlayerCharacter.h b/Code/client/Games/Fallout4/PlayerCharacter.h deleted file mode 100644 index 7cf92aa43..000000000 --- a/Code/client/Games/Fallout4/PlayerCharacter.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -struct TESQuest; - -struct PlayerCharacter : Actor -{ - static PlayerCharacter* Get() noexcept; - - static void SetGodMode(bool aSet) noexcept; - - static int32_t LastUsedCombatSkill; - - void SetDifficulty(const int32_t aDifficulty, bool aForceUpdate = true, bool aExpectGameDataLoaded = true) noexcept; - - void PayCrimeGoldToAllFactions() noexcept; - NiPoint3 RespawnPlayer() noexcept; - - struct Objective - { - uint64_t pad0; - TESQuest* quest; - }; - - struct ObjectiveInstance - { - Objective* instance; - uint64_t instanceCount; - }; - - char pad490[0x7D8 - sizeof(Actor)]; - GameArray objectives; - char pad7F0[0x4F0 - 24]; - TESForm* locationForm; // actually a bgslocation - uint8_t pad_CD0[0x140]; -}; - -static_assert(sizeof(PlayerCharacter) == 0xE10); -static_assert(offsetof(PlayerCharacter, objectives) == 0x7D8); -static_assert(offsetof(PlayerCharacter, locationForm) == 0xCC8); diff --git a/Code/client/Games/Fallout4/Projectiles/Projectile.cpp b/Code/client/Games/Fallout4/Projectiles/Projectile.cpp deleted file mode 100644 index 1af0feea5..000000000 --- a/Code/client/Games/Fallout4/Projectiles/Projectile.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "Projectile.h" -#include -#include -#include -#include -#include -#include - -TP_THIS_FUNCTION(TLaunch, BSPointerHandle*, BSPointerHandle, ProjectileLaunchData& arData); - -static TLaunch* RealLaunch = nullptr; - -BSPointerHandle* Projectile::Launch(BSPointerHandle* apResult, ProjectileLaunchData& arData) noexcept -{ - return TiltedPhoques::ThisCall(RealLaunch, apResult, arData); -} - -BSPointerHandle* TP_MAKE_THISCALL(HookLaunch, BSPointerHandle, ProjectileLaunchData& arData) -{ - if (arData.pShooter) - { - Actor* pActor = Cast(arData.pShooter); - if (pActor) - { - ActorExtension* pExtendedActor = pActor->GetExtension(); - if (pExtendedActor->IsRemote()) - { - apThis->handle.iBits = 0; - return apThis; - } - } - } - - ProjectileLaunchedEvent Event{}; - Event.Origin = arData.Origin; - if (arData.pProjectileBase) - Event.ProjectileBaseID = arData.pProjectileBase->formID; - Event.ZAngle = arData.fZAngle; - Event.XAngle = arData.fXAngle; - Event.YAngle = arData.fYAngle; - if (arData.pShooter) - Event.ShooterID = arData.pShooter->formID; - if (arData.pParentCell) - Event.ParentCellID = arData.pParentCell->formID; - if (arData.pFromAmmo) - Event.AmmoID = arData.pFromAmmo->formID; - Event.Area = arData.iArea; - Event.Power = arData.fPower; - Event.Scale = arData.fScale; - Event.AlwaysHit = arData.bAlwaysHit; - Event.ConeOfFireRadiusMult = arData.fConeOfFireRadiusMult; - Event.NoDamageOutsideCombat = arData.bNoDamageOutsideCombat; - Event.AutoAim = arData.bAutoAim; - Event.DeferInitialization = arData.bDeferInitialization; - Event.Tracer = arData.bTracer; - Event.ForceConeOfFire = arData.bForceConeOfFire; - Event.IntentionalMiss = arData.bIntentionalMiss; - Event.Allow3D = arData.bAllow3D; - Event.Penetrates = arData.bPenetrates; - Event.IgnoreNearCollisions = arData.bIgnoreNearCollisions; - - World::Get().GetRunner().Trigger(Event); - - return TiltedPhoques::ThisCall(RealLaunch, apThis, arData); -} - -TP_THIS_FUNCTION(TFire, void, void, TESObjectREFR* apSource, uint32_t aEquipIndex, TESAmmo* apAmmo, AlchemyItem* apPoison); -static TFire* RealFire = nullptr; - -void TP_MAKE_THISCALL(HookFire, void, TESObjectREFR* apSource, uint32_t aEquipIndex, TESAmmo* apAmmo, AlchemyItem* apPoison) -{ - if (apSource) - { - Actor* pActor = Cast(apSource); - if (pActor) - { - ActorExtension* pExtension = pActor->GetExtension(); - if (pExtension) - { - if (pExtension->IsRemote()) - return; - } - } - } - - return TiltedPhoques::ThisCall(RealFire, apThis, apSource, aEquipIndex, apAmmo, apPoison); -} - -static TiltedPhoques::Initializer s_projectileHooks( - []() - { - POINTER_FALLOUT4(TLaunch, s_launch, 1452335); - POINTER_FALLOUT4(TFire, fire, 1056038); - - RealLaunch = s_launch.Get(); - RealFire = fire.Get(); - - TP_HOOK(&RealLaunch, HookLaunch); - TP_HOOK(&RealFire, HookFire); - }); diff --git a/Code/client/Games/Fallout4/Projectiles/Projectile.h b/Code/client/Games/Fallout4/Projectiles/Projectile.h deleted file mode 100644 index 35e93d1cb..000000000 --- a/Code/client/Games/Fallout4/Projectiles/Projectile.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include - -struct BGSProjectile; -struct TESObjectREFR; -struct CombatController; -struct TESForm; -struct TESAmmo; -struct TESObjectCELL; -struct MagicItem; -struct AlchemyItem; - -struct WeaponData -{ - TESForm* pWeapon; - void* pWeaponData; -}; - -struct ProjectileLaunchData -{ - NiPoint3 Origin; - NiPoint3 ContactNormal; - TESForm* pProjectileBase; // is actually BGSProjectile* - TESObjectREFR* pShooter; - CombatController* pShooterCombatController; - // BGSObjectInstanceT FromWeapon; // length: 0x10 - // TESForm* pFromWeapon; - // void* pFromWeaponData; - WeaponData FromWeapon; - TESAmmo* pFromAmmo; - // BGSEquipIndex EquipIndex; - uint32_t EquipIndex; - float fZAngle; - float fXAngle; - float fYAngle; - TESObjectREFR* pHomingTarget; - TESObjectCELL* pParentCell; - MagicItem* pSpell; - MagicSystem::CastingSource eCastingSource; - AlchemyItem* pPoison; - int iArea; - float fPower; - float fScale; - float fConeOfFireRadiusMult; - int32_t eTargetLimb; - bool bAlwaysHit; - bool bNoDamageOutsideCombat; - bool bAutoAim; - bool bUseOrigin; - bool bDeferInitialization; - bool bTracer; - bool bForceConeOfFire; - bool bIntentionalMiss; - bool bAllow3D; - bool bPenetrates; - bool bIgnoreNearCollisions; -}; - -struct Projectile -{ - static BSPointerHandle* Launch(BSPointerHandle* apResult, ProjectileLaunchData& arData) noexcept; -}; diff --git a/Code/client/Games/Fallout4/RTTI.cpp b/Code/client/Games/Fallout4/RTTI.cpp deleted file mode 100644 index dea0d0dfe..000000000 --- a/Code/client/Games/Fallout4/RTTI.cpp +++ /dev/null @@ -1,6487 +0,0 @@ -#include - -const VersionDbPtr internal::DynamicCast(84113); - -namespace internal -{ -template RttiLocator::RttiLocator(uint32_t aId) -{ - m_pRtti = TiltedPhoques::MakeUnique>(aId); -} - -template const void* RttiLocator::Get() -{ - return *m_pRtti; -} -} // namespace internal - -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESForm(1344422); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectCELL(640070); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAIWorldLocation(154658); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAIWorldLocationInteriorCell(1470934); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESWorldSpace(892155); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAIWorldLocationPointRadius(406590); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectREFR(486181); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAIWorldLocationPrimitive(249); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAIWorldLocationRefRadius(1569568); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IPackageDataTypeCheck(38879); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IProcedureTreeExecState(1355093); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IProcedure(1089251); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedureBase(604047); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedureHeadtrack(118497); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedureHeadtrackExecState(198262); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESIdleForm(282867); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedurePlayIdle(1379554); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedurePlayIdleExecState(1459384); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESActionData(1272844); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSActionData(787648); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ActionInput(301918); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ActionOutput(1398678); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_Setting(1190296); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_INISettingCollection(611767); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hkBaseObject(518411); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpCollisionQueryCollector(32650); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpClosestHitCollector(1568867); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GameSettingCollection(1302516); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_Actor(1162829); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IMovementParameters(192348); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MovementParameters(1508544); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedureRange(1242410); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedureRangeExecState(1102422); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedureStayAway(1014360); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProcedureStayAwayExecState(1093968); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IAnimationEventDataForEachFunctor(268566); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiRefObject(616415); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiObject(130883); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiExtraData(1008265); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSRetargetOnDeleteExtraData(523101); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IForEachDynamicIdleInDir(476303); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_DynamicIdleDataSingletonHelper(210552); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSObjectInstanceExtra(1233230); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSExtraData(967063); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraInitActions(481702); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BaseFormComponent(654816); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSKeyword(122537); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAttachParentArray(1219659); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSCraftingUseSound(906801); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSFeaturedItemMessage(641008); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMessage(374732); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSLocationRefType(1471893); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSForcedLocRefType(1205817); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSInstanceNamingRulesForm(939602); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESFullName(1098716); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSModelMaterialSwap(912158); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMaterialSwap(646347); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESModel(160904); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSNativeTerminalForm(1257718); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSTerminal(991343); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSTransform(506243); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPreviewTransform(20432); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPropertySheet(1336870); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSoundTagSet(805339); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSoundTagComponent(319695); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_InitActionI(712337); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hkReferencedObject(1388895); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpAction(1122977); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpUnaryAction(637892); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpShape(171732); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpCompositeShape(1048989); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpHeightFieldShape(783192); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpPhysicsSystemData(516962); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_CellHfCollision(251027); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpCollisionFilter(1520838); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpAllHitsCollector(1254642); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpBSCustomCollisionFilter(17396); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpFlippedGetClosestPointsQueryCollector(190892); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IFormFactory(363213); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IKeywordFormBase(1460350); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SpellItem(1413385); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_AlchemyItem(709360); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MagicItem(223610); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESBoundObject(1101056); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObject(615732); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSKeywordForm(1493399); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESIcon(1007570); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESTexture(302847); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMessageIcon(1399654); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESWeightForm(914442); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSEquipType(428907); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSDestructibleObjectForm(1526157); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPickupPutdownSounds(1260052); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESDescription(993718); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSProjectile(149402); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSExplosion(1246380); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESEffectShader(761027); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSArtObject(275461); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSImpactDataSet(1372095); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSDualCastData(886949); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_EffectSetting(1234913); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESImageSpaceModifier(749686); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectLIGH(922054); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSReferenceEffect(436528); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPerk(171044); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ActorValueInfo(1048268); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMenuDisplayObject(563030); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_EnchantmentItem(376392); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSListForm(1473513); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IngredientItem(1146810); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESValueForm(661753); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedFile(1398904); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IOTask(913724); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSQueuedResourceCollectionBase(209179); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MagicItemTraversalFunctor(400717); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MagicItemFindFunctor(134868); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MagicItemFindKeywordFunctor(1451227); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_FindNonExcludedDeliveryFunctor(1357617); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_FindEqualsFunctor(1218288); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GetCostliestEffectFunctor(732988); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_LongestDurationFunctor(466357); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_LargestAreaFunctor(200786); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GetMagicItemDescriptionFunctor(995361); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ScrollItem(1387503); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESGlobal(137179); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCell3D(1453579); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraHavok(967978); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRegionList(482654); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCellSkyRegion(1579685); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCellImageSpace(1313491); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCellGodRays(1047589); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSeenData(562348); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraNorthRotation(76879); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraDetachTime(1392806); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraProcessMiddleLow(907734); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCellMusicType(641935); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCellAcousticSpace(375722); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCellWaterType(109715); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESKey(633485); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESImageSpace(1511067); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAcousticSpace(1025257); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESWaterForm(540224); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMusicType(54585); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSEncounterZone(1151495); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSLocation(1104899); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESPackage(619688); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESTopicInfo(134122); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESTopic(1231166); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSDialogueBranch(526358); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSoundOutput(40726); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSoundCategory(1137722); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESFaction(652631); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESCombatStyle(167259); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESActorBase(1263990); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSScene(778733); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESQuest(73836); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSGodRays(951326); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCulledBone(592253); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLock(106716); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraTeleport(983950); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraStartingPosition(498691); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraOwnership(232894); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraGlobal(1329494); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRank(844308); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCount(139464); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLeveledItem(1236556); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraOutfitItem(751272); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraHealth(265723); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraTimeLeft(1362238); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCharge(877021); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraScale(391687); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFollower(1488977); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraOriginalReference(1003092); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPoison(737579); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraHeadingTarget(251978); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCreatureAwakeSound(1568402); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraObjectHealth(1302018); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraActorCause(816888); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRadioData(331401); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPatrolRefData(1428062); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraNavMeshPortal(1162323); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraOcclusionPlaneRefData(896323); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPortalRefData(849623); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSceneData(583828); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraBadPosition(98238); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraHeadTrackingWeight(1195230); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFavorCost(929089); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraTextDisplayData(443511); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraHorse(177966); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEnchantment(1274702); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraForcedTarget(789506); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraUniqueID(303805); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFlags(1400615); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraWaterCurrentZoneData(915358); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMissingRefIDs(649568); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRangedDistOverride(383289); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSoundOutputOverride(117314); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEditorID(1433407); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFavorite(948223); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPrimitive(462515); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAmmo(1559962); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCombinedRefs(854974); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPreVisRefs(369550); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraTransitionCellCount(1466614); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraGIDBuffer(1200639); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFromAlias(1546140); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraOpenCloseActivateRef(1060545); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraTeleportName(794844); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCachedScale(309220); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraReferenceHandles(1405938); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLocation(1140056); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraTresPassPackage(655041); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAttachRef(388643); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAttachRefChildren(1485975); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPowerLinks(1219864); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraReflectedRefs(734598); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraReflectorRefs(468043); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraWaterLightRefs(202411); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLitWaterRefs(1518712); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraHasNoRumors(1033001); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraModelSwap(547992); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRadius(62309); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCombatStyle(1159291); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPackageData(674191); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCollisionData(188747); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLargeRefOwnerCells(1505100); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLightData(1238901); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraModRank(753670); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAttachedArrows3D(268071); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAlphaCutoff(1371); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraForcedLandingMarker(1098934); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCellWaterEnvMap(832850); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraKeywords(566989); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMaterialSwap(81493); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraProjectedDecalData(1178373); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraActivateText(912361); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRadioReceiver(426830); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRadioRepeater(161144); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAnimSounds(1477531); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraActorValueStorage(991566); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraObjectBreakable(726214); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraObjectSavedDynamicIdles(459535); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraObjectSavedUnrecoverableSubgraphs(413026); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraIgnoredAttractKeywords(586193); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraInteriorLODWorldspace(539545); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraBoneScaleMap(492556); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFXPickNodes(6774); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEssentialProtected(1104201); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraInvestedGold(838252); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraVoiceType(352712); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NonActorMagicCaster(1183764); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMagicCaster(917653); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MagicCaster(432040); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSVoiceType(289231); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAnimGraphManager(1386100); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraDismemberedLimbs(1120197); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraBiped(854292); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLight(368849); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLeveledCreature(1465950); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMapMarker(1199959); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAction(714868); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraShouldWear(229151); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSeed(1325715); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPackage(621301); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPlayerCrimeList(135771); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRunOncePacks(1452155); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraDistantData(966589); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEnableStateParent(481247); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEnableStateChildren(215460); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLinkedRef(1531686); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLinkedRefChildren(1046171); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLocationRefType(780399); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraActivateRef(514168); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraActivateRefChildren(28394); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRandomTeleportMarker(1344849); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCannotWear(1078995); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLastFinishedSequence(593896); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraGhost(327622); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraItemDropper(1424321); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraDroppedItemList(939120); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSavedAnimation(673450); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSavedHavokData(407037); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRefractionProperty(141114); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSound(1457481); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCreatureMovementSound(971887); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraActivateLoopSound(925303); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFactionChanges(659694); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSayTopicInfoOnceADay(393280); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEncounterZone(127396); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRoomRefData(1443613); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPatrolRefInUseData(958268); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFollowerSwimBreadcrumbs(692610); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAliasInstanceArray(645876); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraDecalGroup(379581); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCanTalkToPlayer(1476829); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSayToTopicInfo(1210771); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraInteraction(944474); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLockList(458850); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSoul(1556187); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPackageStartLocation(851218); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMasterFileCell(585498); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMasterLocation(319252); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPersistentCell(53184); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRagDollData(1369268); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraUsedMarkers(884074); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraReservedMarkers(398664); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAshPileRef(132720); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLeveledItemBase(1229748); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraLevCreaModifier(963572); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraSpawnContainer(698086); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAcousticParent(431333); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEmittanceSource(165783); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMultiBoundData(1482237); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMultiBoundRef(1216139); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraMultiBound(949877); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPortal(464177); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRoom(1561636); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraOcclusionShape(856626); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFriendHits(590867); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraStartingWorldOrCell(105330); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEditorRef3DData(1421279); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraEditorRefMoveData(1155476); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraGuardedRefData(889517); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraIgnoredBySandbox(623637); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPromotedRef(357357); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAnimationSequencer(1454490); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRefrPath(1188421); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraCellGrassData(703489); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraWaterData(436757); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraGroupConstraint(1534038); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraScriptedAnimDependence(1267945); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRaceData(1221532); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraBendableSplineParams(736202); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraInstanceData(469623); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPowerArmor(1567038); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraPowerArmorPreload(1081297); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraInputEnableLayer(815489); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraDirectAtTarget(549594); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraRefWeaponSounds(283326); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraAnimGraphPreload(1067468); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SimpleAnimationGraphManagerHolder(801799); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IAnimationGraphManagerHolder(755274); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ExtraFurnitureEntryData(708858); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESBipedModelForm(88521); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedActor(27694); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedReference(1124861); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedModel(639805); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedCharacter(154413); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedHead(1251284); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSFaceGenPendingHeadData(765932); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_AttachDistant3DTask(499602); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedAnimationObject(233839); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BackgroundProcessThread(1550061); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSTaskThread(1283945); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSThread(798790); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedTree(738511); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedPlayer(252862); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_INIPrefSettingCollection(828462); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TES(1160254); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_AddCellGrassTask(628394); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAddonNode(148176); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectWEAP(1245180); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESEyes(759876); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectACTI(54815); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectSTAT(1151718); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectMISC(666623); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectDOOR(181221); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESNPC(1277914); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSLoadFormBuffer(1011717); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSLoadGameBuffer(526604); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSLoadFormData(40948); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSStoryManagerBranchNode(26965); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSStoryManagerNodeBase(1343436); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSStoryManagerTreeForm(1077571); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAttackDataForm(836141); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSBipedObjectForm(304011); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSBlockBashData(37895); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSDebris(1527285); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSIdleCollection(934682); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiTimeController(655278); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSOverridePackCollection(169817); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPerkRankArray(1486171); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_PerkRankVisitor(1000279); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSkinForm(688109); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectARMO(202610); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESAIForm(1299278); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESActorBaseData(594830); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESAttackDamageForm(109274); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESEnchantableForm(1425244); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESHealthForm(1159505); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESLeveledList(674421); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESProduceForm(188991); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRaceForm(1285598); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESSpellList(800382); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESReactionForm(314839); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESImageSpaceModifiableForm(1411456); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESLevItem(819393); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESModelRDT(1057711); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESContainer(1183993); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSStorage(193667); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSMemStorage(1070792); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSVMLoadTask(492084); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRace(769141); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESLevSpell(17126); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESShout(1114401); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSParticleArrayAttach(1479429); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSHavokGeometryAttach(807377); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSNamedNodeAttach(1059364); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMultiTechniqueAttach(653878); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ITempEffectFactory(878214); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSMultiBoundAABB(911254); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSMultiBoundShape(425627); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSMultiBoundOBB(1522902); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSTempEffect(1429226); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiObjectNET(850737); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiAVObject(365313); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSDecalNode(1462433); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiNode(976766); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedPromoteReferencesTask(225679); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSQueuedGrassModelHandles(1514566); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpConvexShape(231009); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpSphereShape(1327601); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IRaceSubGraphDataFunctor(842456); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_InteractionCombatDataCollectFunctor(968436); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SetPlayerHasTakenStackFunctor(422628); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_RemoveExtraFunctor(376137); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MatchEquippedAndFavoriteDataFunctor(535287); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IsFavoriteFunctor(708346); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SetFavoriteFunctor(222656); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_RemoveFavoriteFunctor(1538890); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SetPoisonFunctor(1272814); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SetEnchantmentFunctor(787610); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_RefMatchFunctor(866686); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_RemoveQuestAliasFunctor(381410); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SetTimeLeftFunctor(115466); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ModTimeLeftFunctor(1431497); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ProcessWeaponStrikeMagicFunctor(1165786); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SetItemOwnershipFunctor(1119033); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SetItemOriginalReferenceFunctor(853082); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSObjectVisibilityManager(480042); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSPortal(340178); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSOcclusionPlane(1218030); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSOcclusionShape(732726); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPrimitiveLine(247014); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPrimitiveBox(1343667); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPrimitive(858439); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPrimitivePlane(373075); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPrimitiveSphere(1470176); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPrimitiveEllipsoid(1204182); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSMultiBoundSphere(937901); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ReferenceEffectController(1409313); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_OwnedController(1143541); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSAttachRefController(1316249); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSCloneReserver(1050314); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiProperty(1302475); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiAlphaProperty(817304); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GridArray(989681); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GridCellArray(192307); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSInputEventUser(1384222); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESCameraState(899060); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_LocalMapCamera(413461); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESCamera(1510826); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSSplatterExtraData(1323832); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpConvexPolytopeShape(1026617); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpCapsuleShape(760984); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IMessageBoxCallback(925041); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpUniqueBodyIdHitCollector(612640); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpAnyHitCollector(566057); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_hknpFlippedShapeCastQueryCollector(299765); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSNiNode(954287); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MovementHandlerAgentAnimationDriven(380948); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MovementHandlerAgent(553993); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MovementAgent(287587); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MovementHandlerAgentGraphDrivenAnimationDriven(778703); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IMovementQueryDesiredDeltas(158756); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_MovementHandlerAgentPlayerControls(65377); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NavMeshObstacleCoverManager(556273); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSPathingStreamRead(1120860); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_PathingStreamMasterFileRead(854943); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QuestPathingRequest(980887); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSPathingRequest(715510); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IPathBuilderFactoryBase(229812); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QuestPathingRequestBuilder(1424978); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionData(235207); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionDataWeather(1331799); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegion(1065864); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionDataGrass(534114); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionDataLandscape(268029); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionDataManager(1341); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionDataMap(1318093); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionDataObjects(1052176); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionDataSound(786417); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionObjectBase(739882); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionGrassObject(473438); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionGrassObjectList(207701); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionList(333712); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionNoiseFunction(1383749); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionObject(1337052); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESLandTexture(1071262); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESRegionObjectList(586160); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAttractionRule(684872); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSColorForm(1361540); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSBaseAlias(503394); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSRefCollectionAlias(17597); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSRefAlias(1334063); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSShaderMaterialExtraData(270391); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSDismembermentLimbExtraData(835199); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSDismembermentExtraData(788794); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSceneAction(867793); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSceneActionConversationBase(382558); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSceneActionPlayerDialogue(635104); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSoundDescriptorForm(761217); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSceneActionStartScene(448134); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSIAudioEffectChain(1186089); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAudioEffectChain(919918); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSISoundDescriptor(1564678); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSoundDescriptor(1298312); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAutoWeaponSoundDef(1032249); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSComponent(1004690); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSCompoundSoundDef(1210732); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSDamageType(1276259); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSDefaultObject(431303); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSInstanceNamingRules(72394); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSoundCategorySnapshot(1281561); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSSoundKeywordMapping(829093); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAddonNodeSoundHandleExtra(50075); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSAimModel(1445940); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSArtObjectCloneTask(601459); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSTextureSet(228418); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSBendableSpline(1324968); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSConstructibleObject(74752); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPreloadable(546564); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSHazard(1097491); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSLensFlare(252827); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSLensFlareRenderData(1349427); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSLensFlareSpriteRenderData(724780); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSLensFlareSprite(678162); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMovableStatic(883339); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSNavmeshableObject(397937); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSOutfit(1094392); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSPackIn(249814); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSCollisionLayer(1505995); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSStaticCollection(348225); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSFadeNode(35453); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESMagicTargetForm(540414); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSOpenCloseForm(274274); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSTalkingActivator(1370874); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESBoundAnimObject(1105086); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSNote(293144); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESFurniture(1170839); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSZoomData(326168); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESAmmo(751462); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESFlora(1340360); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESGrass(1206233); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESLevCharacter(613788); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectANIO(391158); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectARMA(1255044); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectBOOK(687419); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESMagicCasterForm(1112093); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectCONT(846069); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IFadeDoneCallback(1350381); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectTREE(442311); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESSoulGem(773124); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IOSystemTask(1532071); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedPromoteLargeReferencesTask(1570442); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSLightingTemplate(379971); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_QueuedPromoteLocationReferencesTask(133141); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSReferenceGroup(982962); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSParticleShaderEmitter(1015965); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSParticleShaderCubeEmitter(750311); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSParticleShaderSnowEmitter(703872); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSParticleShaderRainEmitter(657064); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSShaderParticleGeometryData(610281); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_CellLoaderTask(157785); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ImageSpaceModifierInstanceForm(1254582); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ImageSpaceModifierInstance(1208116); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ImageSpaceModifierInstanceTemp(1161320); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ImageSpaceModifierInstanceDOF(1114581); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ImageSpaceModifierInstanceRB(1067914); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESWeather(1460268); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESClimate(974614); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiFloatData(1526094); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiColorData(1040436); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESObjectLAND(1531433); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESChildCell(1045874); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_SeenData(113313); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IntSeenData(990549); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSHandleRefObject(782433); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NonActorMagicTarget(296645); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_ActorValueOwner(1426357); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_OwnedCameraEffectController(708555); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_RemoveOutfitItemsFunctor(1464949); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_CalcContainerWeight(1199001); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_InventoryScoringFunctor(932747); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GetBestWeaponFunctor(667043); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GetBestAmmoFunctor(400642); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GetBestArmorFunctor(134791); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_GetBestLightFunctor(1451165); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IAnimationStreamWrite(466289); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IAnimationStreamRead(200718); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_AnimationStreamLoadGame(1470370); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_AnimationStreamSaveGame(1204381); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMaterialType(378624); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESTexture1024(192498); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSReverbParameters(435743); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSCameraPath(1346166); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSCameraShot(860926); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_NiFormArray(375648); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSDefaultObjectManager(60845); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSFootstep(1283873); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSFootstepSet(658935); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSImpactData(1349393); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSMaterialObject(1321957); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMaterialObject(836802); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMenuIcon(902484); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSIMusicTrack(1014766); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMusicPaletteTrack(529587); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMusicTrack(263526); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMusicSilenceTrack(548833); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMusicSingleTrack(1006293); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSMusicTrackFormWrapper(587048); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSIMusicType(839100); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSIReverbType(167423); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSISoundCategory(1563239); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSISoundOutputModel(438296); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BGSStandardSoundDef(18494); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSShaderTextureSet(1573878); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_BSTextureSet(1307580); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_IVisitProcedures(1233600); -template struct internal::RttiLocator; -internal::RttiLocator registerRtti_TESLoadScreen(1019418); -template struct internal::RttiLocator