├── .gitignore ├── .gitattributes ├── swf ├── Test.fla ├── QuestItemList.fla ├── Nordic UI │ └── Compass.fla ├── Vanilla-SkyHUD │ └── Compass.fla ├── utils.as ├── FocusedMarker.as ├── CompassNaigationOverhaul.as2proj ├── Compass.as ├── QuestItem.as └── QuestItemList.as ├── README.md ├── .gitmodules ├── include ├── RE │ ├── G │ │ ├── GFxSprite.h │ │ ├── GRefCountBaseWeakSupport.h │ │ ├── GASString.h │ │ ├── GFxMouseState.h │ │ ├── GFxCharacterHandle.h │ │ ├── GASStringManager.h │ │ ├── GASFunctionObject.h │ │ ├── GFxStaticTextCharacterDef.h │ │ ├── GFxMorphCharacterDef.h │ │ ├── GFxTimelineDef.h │ │ ├── GFxShapeBaseCharacterDef.h │ │ ├── GFxCharacterDef.h │ │ ├── GFxShapeCharacterDef.h │ │ ├── GFxConstShapeCharacterDef.h │ │ ├── GFxLoadProcess.h │ │ ├── GASObject.h │ │ ├── GFxSpriteDef.h │ │ ├── GFxMovieDefImpl.h │ │ ├── GASObjectInterface.h │ │ ├── GFxASCharacter.h │ │ ├── GFxCharacter.h │ │ ├── GFxMovieDef.h │ │ └── GFxMovieDataDef.h │ ├── C │ │ └── Compass.h │ ├── B │ │ ├── BGSInstancedQuestObjective.h │ │ └── BSTimer.h │ ├── N │ │ └── NiPoint3.h │ ├── H │ │ └── HUDMarkerManager.h │ └── T │ │ └── TESQuest.h ├── utils │ ├── type_name.h │ ├── GFxArray.h │ ├── Logger.h │ ├── GFxDisplayObject.h │ ├── GFxObject.h │ ├── Geometry.h │ ├── Setting.h │ ├── GFxLoggers.h │ ├── INISettingCollection.h │ └── Trampoline.h ├── NPCNameProvider.h ├── Test.h ├── Settings.h ├── IUI │ ├── GFxArray.h │ ├── GFxDisplayObject.h │ ├── GFxObject.h │ ├── GFxLoggers.h │ └── API.h ├── Compass.h ├── pch.h ├── QuestItemList.h ├── HUDMarkerManager.h ├── FocusedMarker.h ├── NND_API.h └── Hooks.h ├── source ├── pch.cpp ├── NPCNameProvider.cpp ├── main.cpp ├── utils │ └── INISettingCollection.cpp ├── FocusedMarker.cpp ├── RE │ ├── T │ │ └── TESQuest.cpp │ └── N │ │ └── NiPoint3.cpp ├── Settings.cpp ├── MessageListeners.cpp └── Hooks.cpp ├── cmake ├── x64-windows-skse.cmake ├── ports │ └── commonlibsse-ng │ │ ├── vcpkg.json │ │ └── portfile.cmake └── version.rc.in ├── vcpkg.json ├── vcpkg-configuration.json ├── LICENSE ├── .clang-format ├── CMakeLists.txt └── CMakePresets.json /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vs/ 3 | extern/ 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /swf/Test.fla: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaterFace/CompassNavigationOverhaul/HEAD/swf/Test.fla -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CompassNavigationOverhaul 2 | 3 | https://www.nexusmods.com/skyrimspecialedition/mods/74484 4 | -------------------------------------------------------------------------------- /swf/QuestItemList.fla: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaterFace/CompassNavigationOverhaul/HEAD/swf/QuestItemList.fla -------------------------------------------------------------------------------- /swf/Nordic UI/Compass.fla: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaterFace/CompassNavigationOverhaul/HEAD/swf/Nordic UI/Compass.fla -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "extern/CommonLibSSE"] 2 | path = extern/CommonLibSSE 3 | url = https://github.com/powerof3/CommonLibSSE 4 | -------------------------------------------------------------------------------- /swf/Vanilla-SkyHUD/Compass.fla: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WaterFace/CompassNavigationOverhaul/HEAD/swf/Vanilla-SkyHUD/Compass.fla -------------------------------------------------------------------------------- /swf/utils.as: -------------------------------------------------------------------------------- 1 | function localToLocal(from:MovieClip, to:MovieClip):Object 2 | { 3 | var point:Object = { x:0, y:0 }; 4 | from.localToGlobal(point); 5 | to.globalToLocal(point); 6 | return point; 7 | } 8 | -------------------------------------------------------------------------------- /include/RE/G/GFxSprite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxCharacter.h" 4 | 5 | namespace RE 6 | { 7 | // Sprite in Scaleform 4.1 8 | class GFxSprite : public GFxASCharacter 9 | { 10 | }; 11 | } -------------------------------------------------------------------------------- /source/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: source file corresponding to the pre-compiled header 2 | 3 | #include "pch.h" 4 | 5 | // When you are using pre-compiled headers, this source file is necessary for compilation to succeed. 6 | -------------------------------------------------------------------------------- /cmake/x64-windows-skse.cmake: -------------------------------------------------------------------------------- 1 | set(VCPKG_TARGET_ARCHITECTURE x64) 2 | set(VCPKG_CRT_LINKAGE dynamic) 3 | 4 | if (${PORT} MATCHES "fully-dynamic-game-engine|skse|qt*") 5 | set(VCPKG_LIBRARY_LINKAGE dynamic) 6 | else () 7 | set(VCPKG_LIBRARY_LINKAGE static) 8 | endif () 9 | -------------------------------------------------------------------------------- /include/RE/G/GRefCountBaseWeakSupport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GRefCountWeakSupportImpl.h" 4 | 5 | namespace RE 6 | { 7 | template 8 | class GRefCountBaseWeakSupport : public GRefCountBaseStatImpl 9 | {}; 10 | } -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "compassnavigationoverhaul", 3 | "version-string": "2.2.0", 4 | "description": "", 5 | "homepage": "https://github.com/alexsylex/CompassNavigationOverhaul", 6 | "license": "MIT", 7 | "dependencies": [ 8 | "commonlibsse-ng" 9 | ], 10 | "builtin-baseline": "8d3649ba34aab36914ddd897958599aa0a91b08e" 11 | } -------------------------------------------------------------------------------- /include/RE/G/GASString.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace RE 4 | { 5 | class GASStringManager; 6 | 7 | class GASStringNode 8 | { 9 | public: 10 | 11 | const char* data; 12 | GASStringManager* manager; 13 | GASStringNode* nextAlloc; 14 | std::uint32_t refCount; 15 | std::uint32_t hashFlags; 16 | std::size_t size; 17 | }; 18 | 19 | class GASString 20 | { 21 | GASStringNode* node; 22 | }; 23 | } -------------------------------------------------------------------------------- /vcpkg-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "registries": [ 3 | { 4 | "kind": "git", 5 | "repository": "https://gitlab.com/colorglass/vcpkg-colorglass", 6 | "baseline": "5dffebb79a2c9cdc48bca6bcee3dfcf78eeeb300", 7 | "packages": [ 8 | "commonlibsse", 9 | "commonlibsse-po3-ae", 10 | "commonlibsse-po3-se", 11 | "commonlibvr", 12 | "commonlibsse-ng", 13 | "commonlibsse-ng-ae", 14 | "commonlibsse-ng-se", 15 | "commonlibsse-ng-vr", 16 | "commonlibsse-ng-flatrim" 17 | ] 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /include/RE/G/GFxMouseState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace RE 4 | { 5 | class GFxMouseState 6 | { 7 | public: 8 | 9 | // members 10 | void* unk00; // 00 11 | void* unk08; // 08 12 | void* unk10; // 10 13 | std::uint32_t buttonsState; // 18 14 | std::uint32_t prevButtonsState; // 1C 15 | GPointF position; // 20 16 | std::uint32_t cursorType; // 28 17 | std::uint8_t flags; // 2C 18 | std::uint8_t pad2D; // 2D 19 | std::uint16_t pad2E; // 2E 20 | }; 21 | static_assert(sizeof(GFxMouseState) == 0x30); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /cmake/ports/commonlibsse-ng/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commonlibsse-ng", 3 | "version-string": "4.0.0", 4 | "port-version": 1, 5 | "description": "A reverse engineered resource for developing SKSE plugins, supporting portable plugins that work across AE, SE, and VR.", 6 | "homepage": "https://github.com/alandtse/CommonlibVR", 7 | "license": "MIT", 8 | "supports": "windows & x64", 9 | "dependencies": [ 10 | { 11 | "name": "vcpkg-cmake-config", 12 | "host": true 13 | }, 14 | "directxmath", 15 | "directxtk", 16 | "fmt", 17 | "rapidcsv", 18 | "spdlog", 19 | "xbyak" 20 | ] 21 | } -------------------------------------------------------------------------------- /include/RE/C/Compass.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/H/HUDObject.h" 4 | 5 | namespace RE 6 | { 7 | class Compass : HUDObject 8 | { 9 | ~Compass() override; // 00 10 | 11 | // override (HUDObject) 12 | void Update() override; // 01 13 | void RegisterHUDComponent(FxDelegateArgs& a_params); // 03 14 | 15 | bool SetMarkers() 16 | { 17 | using func_t = decltype(&Compass::SetMarkers); 18 | REL::Relocation func{ RELOCATION_ID(50775, 51670) }; 19 | return func(this); 20 | } 21 | 22 | GFxValue targetDataArray; // 28 23 | }; 24 | static_assert(sizeof(Compass) == 0x40); 25 | } -------------------------------------------------------------------------------- /include/RE/G/GFxCharacterHandle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GNewOverrideBase.h" 4 | #include "RE/G/GFxPlayerStats.h" 5 | #include "RE/G/GASString.h" 6 | 7 | namespace RE 8 | { 9 | class GFxCharacter; 10 | 11 | class GFxCharacterHandle : public GNewOverrideBase 12 | { 13 | public: 14 | 15 | // members 16 | std::int32_t refCount; // 00 17 | std::uint32_t pad04; // 04 18 | GFxCharacter* character; // 08 19 | GASString name; // 10 20 | GASString namePath; // 18 21 | GASString originalName; // 20 22 | }; 23 | static_assert(sizeof(GFxCharacterHandle) == 0x28); 24 | } 25 | -------------------------------------------------------------------------------- /include/utils/type_name.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | consteval auto type_name() -> std::string_view 5 | { 6 | std::string_view funcsig = __FUNCSIG__; 7 | 8 | size_t startpos = funcsig.find(" type_name<") + 1; 9 | size_t endpos = funcsig.rfind(">(void)"); 10 | size_t len = endpos - startpos; 11 | 12 | return funcsig.substr(startpos, len); 13 | } 14 | 15 | template 16 | consteval auto unscoped_type_name() -> std::string_view 17 | { 18 | std::string_view fullTypeName = type_name(); 19 | 20 | size_t scopepos = fullTypeName.rfind("::") + 1; 21 | size_t startpos = (scopepos != fullTypeName.npos) ? scopepos + 1 : 0; 22 | 23 | return fullTypeName.substr(startpos); 24 | } -------------------------------------------------------------------------------- /include/NPCNameProvider.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NND_API.h" 3 | 4 | class NPCNameProvider 5 | { 6 | public: 7 | static NPCNameProvider* GetSingleton() 8 | { 9 | static NPCNameProvider singleton; 10 | return std::addressof(singleton); 11 | } 12 | 13 | const char* GetName(RE::Actor* actor) const; 14 | 15 | void RequestAPI(); 16 | 17 | private: 18 | NND_API::IVNND1* NND = nullptr; 19 | 20 | NPCNameProvider() = default; 21 | NPCNameProvider(const NPCNameProvider&) = delete; 22 | NPCNameProvider(NPCNameProvider&&) = delete; 23 | 24 | ~NPCNameProvider() = default; 25 | 26 | NPCNameProvider& operator=(const NPCNameProvider&) = delete; 27 | NPCNameProvider& operator=(NPCNameProvider&&) = delete; 28 | }; 29 | -------------------------------------------------------------------------------- /source/NPCNameProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "NPCNameProvider.h" 2 | #include "NND_API.h" 3 | 4 | namespace logger = SKSE::log; 5 | 6 | const char* NPCNameProvider::GetName(RE::Actor* actor) const 7 | { 8 | if (NND) { 9 | if (auto name = NND->GetName(actor, NND_API::NameContext::kEnemyHUD); !name.empty()) { 10 | return name.data(); 11 | } 12 | } 13 | 14 | return actor->GetDisplayFullName(); 15 | } 16 | 17 | void NPCNameProvider::RequestAPI() 18 | { 19 | if (!NND) { 20 | NND = static_cast(NND_API::RequestPluginAPI(NND_API::InterfaceVersion::kV1)); 21 | if (NND) { 22 | logger::info("Obtained NND API - {0:x}", reinterpret_cast(NND)); 23 | } else { 24 | logger::warn("Failed to obtain NND API"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /include/RE/B/BGSInstancedQuestObjective.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/B/BSString.h" 4 | #include "RE/Q/QuestObjectiveStates.h" 5 | 6 | namespace RE 7 | { 8 | class BGSQuestObjective; 9 | 10 | class BGSInstancedQuestObjective 11 | { 12 | public: 13 | 14 | [[nodiscard]] BSString GetDisplayTextWithReplacedTags() const 15 | { 16 | using func_t = void (BGSInstancedQuestObjective::*)(BSString&) const; 17 | REL::Relocation func{ RELOCATION_ID(23229, 23684) }; 18 | 19 | BSString retVal; 20 | func(this, retVal); 21 | return retVal; 22 | } 23 | 24 | // members 25 | BGSQuestObjective* objective; // 00 26 | std::uint32_t instanceID; // 08 27 | QUEST_OBJECTIVE_STATE instanceState; // 0C 28 | }; 29 | static_assert(sizeof(BGSInstancedQuestObjective) == 0x10); 30 | } 31 | -------------------------------------------------------------------------------- /include/Test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Test : IUI::GFxDisplayObject 4 | { 5 | public: 6 | static constexpr inline std::string_view path = "_level0.Test"; 7 | 8 | static void InitSingleton(const GFxDisplayObject& a_compassShoutMeterHolder) 9 | { 10 | if (!singleton) 11 | { 12 | static Test singletonInstance{ a_compassShoutMeterHolder }; 13 | singleton = &singletonInstance; 14 | } 15 | } 16 | 17 | static Test* GetSingleton() { return singleton; } 18 | 19 | GFxDisplayObject textField0 = GetMember("TextField0"); 20 | GFxDisplayObject textField1 = GetMember("TextField1"); 21 | GFxDisplayObject textField2 = GetMember("TextField2"); 22 | 23 | private: 24 | 25 | Test(const GFxDisplayObject& a_test) : 26 | GFxDisplayObject{ a_test } 27 | {} 28 | 29 | static inline Test* singleton = nullptr; 30 | }; -------------------------------------------------------------------------------- /include/RE/G/GASStringManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GASString.h" 4 | #include "RE/G/GFxPlayerStats.h" 5 | #include "RE/G/GRefCountBase.h" 6 | #include "RE/G/GStringHash.h" 7 | 8 | namespace RE 9 | { 10 | class GASStringManager : public GRefCountBase 11 | { 12 | public: 13 | ~GASStringManager() override; // 00 14 | 15 | // members 16 | GStringHash unk10; // 10 17 | GMemoryHeap* heap; // 18 18 | std::uint64_t unk20; // 20 19 | void* unk28; // 28 20 | std::uint64_t unk30; // 30 21 | std::uint64_t unk38; // 38 22 | std::uint64_t unk40; // 40 23 | std::uint64_t unk48; // 48 24 | std::uint64_t unk50; // 50 25 | }; 26 | static_assert(sizeof(GASStringManager) == 0x58); 27 | } 28 | -------------------------------------------------------------------------------- /include/RE/G/GASFunctionObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GASObject.h" 4 | 5 | namespace RE 6 | { 7 | class GASFunctionObject : public GASObject 8 | { 9 | public: 10 | ~GASFunctionObject() override; // 02 11 | 12 | // override (GASObject) 13 | ObjectType GetObjectType2() const override; // 02 - { return ObjectType::kFunction; } 14 | GASFunctionRef ToFunction() override; // 0C 15 | 16 | // add 17 | virtual void Unk_09(void); // 09 - pure (GetExecutionContext?) 18 | virtual void Unk_0A(void); // 0A - pure (Execute?) 19 | virtual void Unk_0B(void); // 0B - pure 20 | virtual void Unk_0C(void); // 0C - pure 21 | virtual void Unk_0D(void); // 0D 22 | virtual void Unk_0E(void); // 0E 23 | virtual void Unk_0F(void); // 0F 24 | virtual void Unk_10(void); // 10 - pure 25 | }; 26 | static_assert(sizeof(GASFunctionObject) == 0x68); 27 | } 28 | -------------------------------------------------------------------------------- /cmake/version.rc.in: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 1 VERSIONINFO 4 | FILEVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, 0 5 | PRODUCTVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, 0 6 | FILEFLAGSMASK 0x17L 7 | #ifdef _DEBUG 8 | FILEFLAGS 0x1L 9 | #else 10 | FILEFLAGS 0x0L 11 | #endif 12 | FILEOS 0x4L 13 | FILETYPE 0x1L 14 | FILESUBTYPE 0x0L 15 | BEGIN 16 | BLOCK "StringFileInfo" 17 | BEGIN 18 | BLOCK "040904b0" 19 | BEGIN 20 | VALUE "FileDescription", "@PROJECT_NAME@" 21 | VALUE "FileVersion", "@PROJECT_VERSION@.0" 22 | VALUE "InternalName", "@PROJECT_NAME@" 23 | VALUE "LegalCopyright", "MIT License" 24 | VALUE "ProductName", "@PROJECT_NAME@" 25 | VALUE "ProductVersion", "@PROJECT_VERSION@.0" 26 | END 27 | END 28 | BLOCK "VarFileInfo" 29 | BEGIN 30 | VALUE "Translation", 0x409, 1200 31 | END 32 | END 33 | -------------------------------------------------------------------------------- /include/RE/G/GFxStaticTextCharacterDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxCharacterDef.h" 4 | 5 | namespace RE 6 | { 7 | class GFxStaticTextCharacterDef : public GFxCharacterDef 8 | { 9 | public: 10 | ~GFxStaticTextCharacterDef() override; // 00 11 | 12 | // override (GFxCharacterDef) 13 | bool DefPointTestLocal(const GPointF& a_pt, bool a_arg2, const GFxCharacter* a_character) const override; // 05 14 | GRectF GetBoundsLocal() const override; // 06 15 | GFxCharacter* CreateCharacter(GFxASCharacter* a_parent, GFxResourceID a_resourceID, GFxMovieDefImpl* a_bindingImpl) override; // 09 16 | 17 | // override (GFxResource) 18 | std::uint32_t GetResourceTypeCode() const override; // 02 19 | 20 | // members 21 | GRectF bounds; // 20 22 | std::uint64_t unk30[7]; // 30 23 | }; 24 | static_assert(sizeof(GFxStaticTextCharacterDef) == 0x68); 25 | } 26 | -------------------------------------------------------------------------------- /include/RE/G/GFxMorphCharacterDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxShapeCharacterDef.h" 4 | 5 | namespace RE 6 | { 7 | class GFxMorphCharacterDef : public GFxShapeCharacterDef 8 | { 9 | public: 10 | ~GFxMorphCharacterDef() override; 11 | 12 | // override (GFxCharacterDef) 13 | void Display(GFxDisplayContext& a_displayContext, GFxCharacter* a_character) override; // 04 14 | bool DefPointTestLocal(const GPointF& a_pt, bool a_arg2, const GFxCharacter* a_character) const override; // 05 15 | GRectF GetRectBoundsLocal() const override; // 07 16 | 17 | // override (GFxShapeBaseCharacterDef) 18 | void Unk_0C(void) override; // 0C 19 | void Unk_0D(void) override; // 0D 20 | 21 | // add 22 | virtual void Unk_16(void); // 16 23 | 24 | // members 25 | GFxConstShapeNoStyles* unkF0; // F0 26 | std::uint64_t unkF8[16]; // F8 27 | }; 28 | static_assert(sizeof(GFxMorphCharacterDef) == 0x178); 29 | } 30 | -------------------------------------------------------------------------------- /include/RE/G/GFxTimelineDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxCharacterDef.h" 4 | 5 | namespace RE 6 | { 7 | class GASExecuteTag; 8 | 9 | class GFxTimelineDef : public GFxCharacterDef 10 | { 11 | public: 12 | struct Frame 13 | { 14 | std::uint32_t GetTagCount() const { return size; } 15 | GASExecuteTag* GetTag(std::uint32_t a_index) const { return data[a_index]; } 16 | 17 | GASExecuteTag** data; // 00 18 | std::uint32_t size; // 08 19 | }; 20 | 21 | // add 22 | virtual std::uint32_t GetFrameCount() const = 0; // 0A 23 | virtual const Frame GetPlayList(std::int32_t a_frameNumber) const = 0; // 0B 24 | virtual bool GetInitActions(Frame* a_frame, std::int32_t a_frameNumber) const = 0; // 0C 25 | virtual bool GetLabeledFrame(const char* a_label, std::uint32_t* a_frameNumber, bool a_translateNumbers) = 0; // 0D 26 | }; 27 | static_assert(sizeof(GFxTimelineDef) == 0x20); 28 | } 29 | -------------------------------------------------------------------------------- /include/RE/G/GFxShapeBaseCharacterDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxCharacterDef.h" 4 | 5 | namespace RE 6 | { 7 | class GFxShapeBaseCharacterDef : public GFxCharacterDef 8 | { 9 | public: 10 | ~GFxShapeBaseCharacterDef() override; // 00 11 | 12 | // override (GFxResource) 13 | std::uint32_t GetResourceTypeCode() const override; // 02 14 | 15 | // override (GFxCharacterDef) 16 | void Display(GFxDisplayContext& a_displayContext, GFxCharacter* a_character) override = 0; // 04 17 | GRectF GetBoundsLocal() const override = 0; // 06 18 | GRectF GetRectBoundsLocal() const override = 0; // 07 19 | 20 | // add 21 | virtual void Unk_0A(void) = 0; // 0A 22 | virtual void Unk_0B(void) = 0; // 0B 23 | virtual void Unk_0C(void) = 0; // 0C 24 | virtual void Unk_0D(void) = 0; // 0D 25 | virtual void Unk_0E(void) = 0; // 0E 26 | virtual void Unk_0F(void) = 0; // 0F 27 | virtual void Unk_10(void) = 0; // 10 28 | virtual void Unk_11(void) = 0; // 11 29 | }; 30 | static_assert(sizeof(GFxShapeBaseCharacterDef) == 0x20); 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 alexsylex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /include/RE/G/GFxCharacterDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxResource.h" 4 | #include "RE/G/GFxResourceID.h" 5 | #include "RE/G/GPoint.h" 6 | 7 | namespace RE 8 | { 9 | class GFxCharacter; 10 | class GFxDisplayContext; 11 | 12 | class GFxASCharacter; 13 | class GFxMovieDefImpl; 14 | 15 | 16 | class GFxCharacterDef : public GFxResource 17 | { 18 | public: 19 | // add 20 | virtual void Display(GFxDisplayContext& a_displayContext, GFxCharacter* a_character); // 04 21 | virtual bool DefPointTestLocal(const GPointF& a_pt, bool a_arg2, const GFxCharacter* a_character) const; // 05 - { return false; } 22 | virtual GRectF GetBoundsLocal() const; // 06 23 | virtual GRectF GetRectBoundsLocal() const; // 07 24 | virtual std::uint32_t GetVersion() const; // 08 25 | virtual GFxCharacter* CreateCharacter(GFxASCharacter* a_parent, GFxResourceID a_resourceID, GFxMovieDefImpl* a_bindingImpl); // 09 26 | 27 | // members 28 | GFxResourceID resourceId; // 18 29 | std::uint32_t pad1C; // 1C 30 | }; 31 | static_assert(sizeof(GFxCharacterDef) == 0x20); 32 | } 33 | -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Hooks.h" 2 | #include "Settings.h" 3 | 4 | #include "utils/Logger.h" 5 | 6 | extern const SKSE::LoadInterface* skse; 7 | void SKSEMessageListener(SKSE::MessagingInterface::Message* a_msg); 8 | 9 | SKSEPluginLoad(const SKSE::LoadInterface* a_skse) 10 | { 11 | REL::Module::reset(); 12 | 13 | skse = a_skse; 14 | 15 | std::this_thread::sleep_for(6s); 16 | 17 | const SKSE::PluginDeclaration* plugin = SKSE::PluginDeclaration::GetSingleton(); 18 | 19 | if (!logger::init(plugin->GetName())) 20 | { 21 | return false; 22 | } 23 | 24 | logger::info("Loading {} {}...", plugin->GetName(), plugin->GetVersion()); 25 | 26 | SKSE::Init(a_skse); 27 | 28 | settings::Init(std::string(plugin->GetName()) + ".ini"); 29 | 30 | logger::set_level(settings::debug::logLevel, settings::debug::logLevel); 31 | 32 | if (!SKSE::GetMessagingInterface()->RegisterListener("SKSE", SKSEMessageListener)) 33 | { 34 | return false; 35 | } 36 | 37 | hooks::Install(); 38 | 39 | logger::set_level(logger::level::info, logger::level::info); 40 | logger::info("Succesfully loaded!"); 41 | 42 | logger::set_level(settings::debug::logLevel, settings::debug::logLevel); 43 | 44 | return true; 45 | } 46 | -------------------------------------------------------------------------------- /include/RE/B/BSTimer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace RE 4 | { 5 | class BSTimer 6 | { 7 | public: 8 | 9 | static BSTimer* GetTimeManager() 10 | { 11 | REL::Relocation singleton{ RELOCATION_ID(523657, 410196) }; 12 | return &*singleton; 13 | } 14 | 15 | static float GetCurrentGlobalTimeMult() 16 | { 17 | REL::Relocation value{ RELOCATION_ID(511883, 388443) }; 18 | return *value; 19 | } 20 | 21 | // members 22 | std::uint64_t unk00; // 00 23 | std::uint32_t lastPerformanceCount; // 08 24 | float clamp; // 10 25 | float clampRemainder; // 14 26 | float delta; // 18 27 | float realTimeDelta; // 1C 28 | std::uint32_t durationOfApplicationRunTimeMs; // 20 29 | std::uint32_t unk24; // 24 30 | float unk28; // 28 31 | std::uint32_t unk2C; // 2C 32 | std::uint32_t unk30; // 30 33 | std::uint32_t unk34; // 34 34 | std::uint8_t unk38; // 38 35 | std::uint8_t unk39; // 39 36 | bool useGlobalTimeMultiplierTarget; // 3A 37 | std::uint8_t pad3B; // 3B 38 | std::uint32_t pad3C; // 3C 39 | }; 40 | static_assert(sizeof(BSTimer) == 0x40); 41 | } 42 | -------------------------------------------------------------------------------- /source/utils/INISettingCollection.cpp: -------------------------------------------------------------------------------- 1 | #include "utils/INISettingCollection.h" 2 | 3 | #include "utils/Logger.h" 4 | 5 | namespace utils 6 | { 7 | INISettingCollection::INISettingCollection() noexcept 8 | { 9 | REL::Relocation __vTable(*reinterpret_cast(this)); 10 | 11 | // Use the Skyrim's INISettingCollection virtual functions 12 | static std::uintptr_t* skyrimsVTable = REL::Relocation{ vTableId }.get(); 13 | 14 | // Replace all except the destructor (index 0) 15 | for (int i = 1; i < 10; i++) { 16 | __vTable.write_vfunc(i, skyrimsVTable[i]); 17 | } 18 | } 19 | 20 | bool INISettingCollection::ReadFromFile(std::string_view a_fileName) 21 | { 22 | std::filesystem::path iniPath = std::filesystem::current_path().append("Data\\SKSE\\Plugins").append(a_fileName); 23 | 24 | // Reference: decompiled source code in 1.5.97 25 | if (iniPath.string().c_str()) { 26 | if (iniPath.string().c_str() != subKey) { 27 | strcpy_s(subKey, iniPath.string().c_str()); 28 | } 29 | } else { 30 | subKey[0] = '\0'; 31 | } 32 | 33 | if (_this()->OpenHandle(false)) { 34 | _this()->ReadAllSettings(); 35 | _this()->CloseHandle(); 36 | 37 | return true; 38 | } 39 | 40 | return false; 41 | } 42 | } -------------------------------------------------------------------------------- /include/RE/G/GFxShapeCharacterDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxShapeBaseCharacterDef.h" 4 | #include "RE/G/GFxShapeWithStyles.h" 5 | 6 | namespace RE 7 | { 8 | class GFxShapeCharacterDef : public GFxShapeBaseCharacterDef 9 | { 10 | public: 11 | ~GFxShapeCharacterDef() override; // 00 12 | 13 | // override (GFxCharacterDef) 14 | void Display(GFxDisplayContext& a_displayContext, GFxCharacter* a_character) override; // 04 15 | bool DefPointTestLocal(const GPointF& a_pt, bool a_arg2, const GFxCharacter* a_character) const override; // 05 16 | GRectF GetBoundsLocal() const override; // 06 17 | GRectF GetRectBoundsLocal() const override; // 07 18 | 19 | // override (GFxShapeBaseCharacterDef) 20 | void Unk_0A(void) override; // 0A 21 | void Unk_0B(void) override; // 0B 22 | void Unk_0C(void) override; // 0C 23 | void Unk_0D(void) override; // 0D 24 | void Unk_0E(void) override; // 0E 25 | void Unk_0F(void) override; // 0F 26 | void Unk_10(void) override; // 10 27 | void Unk_11(void) override; // 11 28 | 29 | // add 30 | virtual void Unk_12(void); // 12 31 | virtual void Unk_13(void); // 13 32 | virtual void Unk_14(void); // 14 33 | virtual void Unk_15(void); // 15 34 | 35 | // members 36 | GFxShapeWithStyles shape; // 20 37 | }; 38 | static_assert(sizeof(GFxShapeCharacterDef) == 0xF0); 39 | } 40 | -------------------------------------------------------------------------------- /include/RE/G/GFxConstShapeCharacterDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxConstShapeWithStyles.h" 4 | #include "RE/G/GFxShapeBaseCharacterDef.h" 5 | 6 | namespace RE 7 | { 8 | class GFxConstShapeCharacterDef : public GFxShapeBaseCharacterDef 9 | { 10 | public: 11 | ~GFxConstShapeCharacterDef() override; // 00 12 | 13 | // override (GFxCharacterDef) 14 | void Display(GFxDisplayContext& a_displayContext, GFxCharacter* a_character) override; // 04 15 | bool DefPointTestLocal(const GPointF& a_pt, bool a_arg2, const GFxCharacter* a_character) const override; // 05 16 | GRectF GetBoundsLocal() const override; // 06 17 | GRectF GetRectBoundsLocal() const override; // 07 18 | 19 | // override (GFxShapeBaseCharacterDef) 20 | void Unk_0A(void) override; // 0A 21 | void Unk_0B(void) override; // 0B 22 | void Unk_0C(void) override; // 0C 23 | void Unk_0D(void) override; // 0D 24 | void Unk_0E(void) override; // 0E 25 | void Unk_0F(void) override; // 0F 26 | void Unk_10(void) override; // 10 27 | void Unk_11(void) override; // 11 28 | 29 | // add 30 | virtual void Unk_12(void); // 12 31 | virtual void Unk_13(void); // 13 32 | virtual void Unk_14(void); // 14 33 | virtual void Unk_15(void); // 15 34 | 35 | // members 36 | GFxConstShapeWithStyles shape; // 20 37 | }; 38 | static_assert(sizeof(GFxConstShapeCharacterDef) == 0x98); 39 | } 40 | -------------------------------------------------------------------------------- /include/Settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace SKSE::log 4 | { 5 | using level = spdlog::level::level_enum; 6 | } 7 | namespace logger = SKSE::log; 8 | 9 | namespace settings 10 | { 11 | void Init(const std::string& a_iniFileName); 12 | 13 | // Default values 14 | 15 | namespace debug 16 | { 17 | inline logger::level logLevel = logger::level::err; 18 | } 19 | 20 | namespace display 21 | { 22 | inline bool useMetricUnits = false; 23 | inline bool showUndiscoveredLocationMarkers = true; 24 | inline bool undiscoveredMeansUnknownMarkers = true; 25 | inline bool undiscoveredMeansUnknownInfo = true; 26 | inline bool showEnemyMarkers = true; 27 | inline bool showEnemyNameUnderMarker = true; 28 | inline bool showObjectiveAsTarget = true; 29 | inline bool showOtherObjectivesCount = true; 30 | inline bool showInteriorMarkers = true; 31 | inline float angleToShowMarkerDetails = 10.0F; 32 | inline float angleToKeepMarkerDetailsShown = 35.0F; 33 | inline float focusingDelayToShow = 0.1F; 34 | } 35 | 36 | namespace questlist 37 | { 38 | inline float positionX = 0.008F; 39 | inline float positionY = 0.125F; 40 | inline float maxHeight = 0.5F; 41 | inline bool showInExteriors = true; 42 | inline bool showInInteriors = true; 43 | inline float walkingDelayToShow = 0.0F; 44 | inline float joggingDelayToShow = 1.0F; 45 | inline float sprintingDelayToShow = 1.5F; 46 | inline bool hideInCombat = false; 47 | } 48 | } -------------------------------------------------------------------------------- /include/IUI/GFxArray.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxMovieView.h" 4 | #include "RE/G/GFxValue.h" 5 | 6 | class GFxArray : public RE::GFxValue 7 | { 8 | public: 9 | 10 | static GFxArray GetFrom(RE::GFxMovieView* a_movieView, const std::string_view& a_pathToArray) 11 | { 12 | RE::GFxValue array; 13 | 14 | a_movieView->GetVariable(&array, a_pathToArray.data()); 15 | 16 | assert(array.IsArray()); 17 | 18 | return array; 19 | } 20 | 21 | GFxArray(RE::GFxMovieView* a_movieView) 22 | { 23 | a_movieView->CreateArray(this); 24 | 25 | assert(GetMovieView() == a_movieView); 26 | assert(IsArray()); 27 | } 28 | 29 | GFxArray(const RE::GFxValue& a_value) 30 | { 31 | *static_cast(this) = a_value; 32 | 33 | assert(IsArray()); 34 | } 35 | 36 | RE::GFxMovieView* GetMovieView() 37 | { 38 | return **reinterpret_cast(static_cast(this)); 39 | } 40 | 41 | RE::GFxValue GetElement(std::uint32_t a_index) const 42 | { 43 | RE::GFxValue value; 44 | RE::GFxValue::GetElement(a_index, &value); 45 | return value; 46 | } 47 | 48 | bool SetElement(std::uint32_t a_index, const RE::GFxValue& a_value) 49 | { 50 | return RE::GFxValue::SetElement(a_index, &a_value); 51 | } 52 | 53 | std::int32_t FindElement(const RE::GFxValue& a_value) 54 | { 55 | for (std::uint32_t i = 0; i < GetArraySize(); i++) 56 | { 57 | if (GetElement(i) == a_value) 58 | { 59 | return i; 60 | } 61 | } 62 | 63 | return -1; 64 | } 65 | }; -------------------------------------------------------------------------------- /include/utils/GFxArray.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxMovieView.h" 4 | #include "RE/G/GFxValue.h" 5 | 6 | class GFxArray : public RE::GFxValue 7 | { 8 | public: 9 | 10 | static GFxArray GetFrom(RE::GFxMovieView* a_movieView, const std::string_view& a_pathToArray) 11 | { 12 | RE::GFxValue array; 13 | 14 | a_movieView->GetVariable(&array, a_pathToArray.data()); 15 | 16 | assert(array.IsArray()); 17 | 18 | return array; 19 | } 20 | 21 | GFxArray(RE::GFxMovieView* a_movieView) 22 | { 23 | a_movieView->CreateArray(this); 24 | 25 | assert(GetMovieView() == a_movieView); 26 | assert(IsArray()); 27 | } 28 | 29 | GFxArray(const RE::GFxValue& a_value) 30 | { 31 | *static_cast(this) = a_value; 32 | 33 | assert(IsArray()); 34 | } 35 | 36 | RE::GFxMovieView* GetMovieView() 37 | { 38 | return **reinterpret_cast(static_cast(this)); 39 | } 40 | 41 | RE::GFxValue GetElement(std::uint32_t a_index) const 42 | { 43 | RE::GFxValue value; 44 | RE::GFxValue::GetElement(a_index, &value); 45 | return value; 46 | } 47 | 48 | bool SetElement(std::uint32_t a_index, const RE::GFxValue& a_value) 49 | { 50 | return RE::GFxValue::SetElement(a_index, &a_value); 51 | } 52 | 53 | std::int32_t FindElement(const RE::GFxValue& a_value) 54 | { 55 | for (std::uint32_t i = 0; i < GetArraySize(); i++) 56 | { 57 | if (GetElement(i) == a_value) 58 | { 59 | return i; 60 | } 61 | } 62 | 63 | return -1; 64 | } 65 | }; -------------------------------------------------------------------------------- /source/FocusedMarker.cpp: -------------------------------------------------------------------------------- 1 | #include "FocusedMarker.h" 2 | 3 | #include "RE/H/HUDMarkerManager.h" 4 | 5 | FocusedMarker::QuestData::QuestData(std::uint32_t a_gfxIndex, std::uint32_t a_gfxGotoFrame, RE::TESObjectREFR* a_marker, 6 | const RE::TESQuest* a_quest) : 7 | Data{ a_gfxIndex, a_gfxGotoFrame }, 8 | quest{ a_quest }, isInSameLocation{ gfxGotoFrame == RE::HUDMarker::FrameOffsets::GetSingleton()->quest } 9 | { 10 | // A quest marker can reference to a character or a location 11 | switch (a_marker->GetFormType()) 12 | { 13 | case RE::FormType::Reference: 14 | { 15 | if (auto teleportDoor = a_marker->As()) 16 | { 17 | // If it is a teleport door, we can get the door at the other side 18 | if (auto teleportLinkedDoor = teleportDoor->extraList.GetTeleportLinkedDoor().get()) 19 | { 20 | // First, try interior cell 21 | if (RE::TESObjectCELL* cell = teleportLinkedDoor->GetParentCell()) 22 | { 23 | locationName = cell->GetName(); 24 | } 25 | // Exterior cell 26 | else if (RE::TESWorldSpace* worldSpace = teleportLinkedDoor->GetWorldspace()) 27 | { 28 | locationName = worldSpace->GetName(); 29 | } 30 | } 31 | } 32 | break; 33 | } 34 | case RE::FormType::ActorCharacter: 35 | { 36 | if (auto character = a_marker->As()) 37 | { 38 | characterName = NPCNameProvider::GetSingleton()->GetName(character); 39 | } 40 | break; 41 | } 42 | default: 43 | { 44 | break; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /swf/FocusedMarker.as: -------------------------------------------------------------------------------- 1 | class FocusedMarker extends MovieClip 2 | { 3 | // Instances 4 | var HeightIndicatorInstance:MovieClip; 5 | var Distance:MovieClip; 6 | var Target:MovieClip; 7 | 8 | // References 9 | var Movie:MovieClip; 10 | 11 | // Variables 12 | var Index:Number; 13 | var Objective:String; 14 | var Location:String; 15 | var UseMetricUnits:Boolean; 16 | 17 | public function FocusedMarker() 18 | { 19 | Index = -1; 20 | Distance.TextFieldInstance.autoSize = "center"; 21 | } 22 | 23 | public function SetDistanceAndHeightDifference(a_distance:Number, a_heightDifference:Number):Void 24 | { 25 | if (UseMetricUnits) // Meters 26 | { 27 | Distance.TextFieldInstance.text = String(Math.floor(a_distance * 0.01428)) + " m"; 28 | } 29 | else // Feet 30 | { 31 | Distance.TextFieldInstance.text = String(Math.floor(a_distance * 0.046875)) + " ft "; 32 | } 33 | 34 | Distance.HeightIndicatorInstance._x = Distance.TextFieldInstance._x + Distance.TextFieldInstance._width + 35 | Distance.HeightIndicatorInstance._width / 3; 36 | 37 | if (a_heightDifference > 840) 38 | { 39 | Distance.HeightIndicatorInstance._alpha = Math.max(Movie._alpha, 75); 40 | Distance.HeightIndicatorInstance.gotoAndStop("Above"); 41 | } 42 | else if (a_heightDifference < -840) 43 | { 44 | Distance.HeightIndicatorInstance._alpha = Math.max(Movie._alpha, 75); 45 | Distance.HeightIndicatorInstance.gotoAndStop("Below"); 46 | } 47 | else 48 | { 49 | Distance.HeightIndicatorInstance._alpha = 0; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /include/RE/N/NiPoint3.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace RE 4 | { 5 | class NiPoint3 6 | { 7 | public: 8 | constexpr NiPoint3() noexcept = default; 9 | 10 | constexpr NiPoint3(float a_x, float a_y, float a_z) noexcept : 11 | x(a_x), 12 | y(a_y), 13 | z(a_z){}; 14 | 15 | float& operator[](std::size_t a_idx); 16 | const float& operator[](std::size_t a_idx) const; 17 | bool operator==(const NiPoint3& a_rhs) const; 18 | bool operator!=(const NiPoint3& a_rhs) const; 19 | NiPoint3 operator+(const NiPoint3& a_rhs) const; 20 | NiPoint3 operator-(const NiPoint3& a_rhs) const; 21 | float operator*(const NiPoint3& a_rhs) const; 22 | NiPoint3 operator*(float a_scalar) const; 23 | NiPoint3 operator/(float a_scalar) const; 24 | NiPoint3 operator-() const; 25 | NiPoint3& operator+=(const NiPoint3& a_rhs); 26 | NiPoint3& operator-=(const NiPoint3& a_rhs); 27 | NiPoint3& operator*=(const NiPoint3& a_rhs); 28 | NiPoint3& operator/=(const NiPoint3& a_rhs); 29 | NiPoint3& operator*=(float a_scalar); 30 | NiPoint3& operator/=(float a_scalar); 31 | 32 | [[nodiscard]] NiPoint3 Cross(const NiPoint3& a_pt) const; 33 | [[nodiscard]] float Dot(const NiPoint3& pt) const; 34 | [[nodiscard]] float GetDistance(const NiPoint3& a_pt) const noexcept; 35 | [[nodiscard]] float GetSquaredDistance(const NiPoint3& a_pt) const noexcept; 36 | [[nodiscard]] float Length() const; 37 | [[nodiscard]] float SqrLength() const; 38 | [[nodiscard]] NiPoint3 UnitCross(const NiPoint3& a_pt) const; 39 | float Unitize(); 40 | [[nodiscard]] float GetHorizontalAngleTo(const NiPoint3& a_pt) const; 41 | 42 | // members 43 | float x{ 0.0F }; // 0 44 | float y{ 0.0F }; // 4 45 | float z{ 0.0F }; // 8 46 | }; 47 | static_assert(sizeof(NiPoint3) == 0xC); 48 | } 49 | -------------------------------------------------------------------------------- /include/utils/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PCH.h" 4 | 5 | namespace SKSE::log 6 | { 7 | using level = spdlog::level::level_enum; 8 | 9 | inline void set_level(level a_log_level, level a_flush_level) 10 | { 11 | spdlog::default_logger()->set_level(a_log_level); 12 | spdlog::default_logger()->flush_on(a_flush_level); 13 | } 14 | 15 | inline bool init(const std::string_view& a_log_name) 16 | { 17 | if (!log_directory()) 18 | { 19 | return false; 20 | } 21 | 22 | std::filesystem::path path = *log_directory() / a_log_name; 23 | path += ".log"; 24 | std::shared_ptr log = spdlog::basic_logger_mt("global log", path.string(), true); 25 | 26 | spdlog::set_default_logger(std::move(log)); 27 | 28 | set_level(level::info, level::info); 29 | 30 | spdlog::set_pattern("%D - %H:%M:%S.%f [%^%l%$] %v"); 31 | 32 | return true; 33 | } 34 | 35 | inline void flush() 36 | { 37 | spdlog::default_logger()->flush(); 38 | } 39 | 40 | template 41 | void at_level(spdlog::level::level_enum a_level, fmt::format_string a_fmt, Args&&... args) 42 | { 43 | switch (a_level) { 44 | case level::trace: 45 | trace(a_fmt, std::forward(args)...); 46 | break; 47 | case level::debug: 48 | debug(a_fmt, std::forward(args)...); 49 | break; 50 | case level::info: 51 | info(a_fmt, std::forward(args)...); 52 | break; 53 | case level::warn: 54 | warn(a_fmt, std::forward(args)...); 55 | break; 56 | case level::err: 57 | error(a_fmt, std::forward(args)...); 58 | break; 59 | case level::critical: 60 | critical(a_fmt, std::forward(args)...); 61 | break; 62 | } 63 | } 64 | } 65 | 66 | namespace GFxLogger 67 | { 68 | struct info; 69 | struct error; 70 | 71 | bool RegisterStaticFunctions(RE::GFxMovieView* a_view); 72 | } 73 | 74 | namespace logger = SKSE::log; -------------------------------------------------------------------------------- /cmake/ports/commonlibsse-ng/portfile.cmake: -------------------------------------------------------------------------------- 1 | # Get port from Github 2 | vcpkg_from_github( 3 | OUT_SOURCE_PATH SOURCE_PATH 4 | REPO alandtse/CommonLibVR 5 | REF 2b983f5281bfadd26ee20787390d2513e8ffe38a 6 | SHA512 d8bae2aa1c066def4a194c85dda57b0b7b758f3221c4d6ef7783c0e29fb7cff353085fbd297996762fd06fd191fb0f19646248e1448001f27c0cbf56cfa3a443 7 | HEAD_REF ng 8 | ) 9 | 10 | # Get submodule and copy to extern/ folder (done manually because Vcpkg does not support Git submodules) 11 | vcpkg_from_github( 12 | OUT_SOURCE_PATH SOURCE_PATH_OPENVR 13 | REPO ValveSoftware/openvr 14 | REF ebdea152f8aac77e9a6db29682b81d762159df7e 15 | SHA512 4fb668d933ac5b73eb4e97eb29816176e500a4eaebe2480cd0411c95edfb713d58312036f15db50884a2ef5f4ca44859e108dec2b982af9163cefcfc02531f63 16 | HEAD_REF master 17 | ) 18 | file(COPY "${SOURCE_PATH_OPENVR}/" DESTINATION "${SOURCE_PATH}/extern/openvr") 19 | file(REMOVE_RECURSE "${SOURCE_PATH_OPENVR}/") 20 | 21 | # Configure options to build 22 | vcpkg_configure_cmake( 23 | SOURCE_PATH "${SOURCE_PATH}" 24 | PREFER_NINJA 25 | OPTIONS -DBUILD_TESTS=off -DSKSE_SUPPORT_XBYAK=on 26 | ) 27 | 28 | vcpkg_install_cmake() 29 | vcpkg_cmake_config_fixup(PACKAGE_NAME CommonLibSSE CONFIG_PATH lib/cmake) 30 | vcpkg_copy_pdbs() 31 | 32 | file(INSTALL "${SOURCE_PATH}/extern/openvr/headers/openvr.h" DESTINATION ${CURRENT_PACKAGES_DIR}/include) 33 | file(GLOB CMAKE_CONFIGS "${CURRENT_PACKAGES_DIR}/share/CommonLibSSE/CommonLibSSE/*.cmake") 34 | file(INSTALL ${CMAKE_CONFIGS} DESTINATION "${CURRENT_PACKAGES_DIR}/share/CommonLibSSE") 35 | file(INSTALL "${SOURCE_PATH}/cmake/CommonLibSSE.cmake" DESTINATION "${CURRENT_PACKAGES_DIR}/share/CommonLibSSE") 36 | 37 | file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") 38 | file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/share/CommonLibSSE/CommonLibSSE") 39 | 40 | file( 41 | INSTALL "${SOURCE_PATH}/LICENSE" 42 | DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" 43 | RENAME copyright) -------------------------------------------------------------------------------- /include/utils/GFxDisplayObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GFxObject.h" 4 | 5 | class GFxDisplayObject : public GFxObject 6 | { 7 | public: 8 | 9 | GFxDisplayObject(const RE::GFxValue& a_value) 10 | : GFxObject{ a_value } 11 | { 12 | assert(a_value.IsDisplayObject()); 13 | } 14 | 15 | GFxDisplayObject CreateEmptyMovieClip(const std::string_view& a_name, std::int32_t a_depth) 16 | { 17 | RE::GFxValue mc; 18 | RE::GFxValue::CreateEmptyMovieClip(&mc, a_name.data(), a_depth); 19 | return mc; 20 | } 21 | 22 | GFxDisplayObject CreateEmptyMovieClip(const std::string_view& a_name) 23 | { 24 | return CreateEmptyMovieClip(a_name, GetNextHighestDepth()); 25 | } 26 | 27 | GFxDisplayObject AttachMovie(const std::string_view& a_className, const std::string_view& a_name, std::int32_t a_depth) 28 | { 29 | RE::GFxValue mc; 30 | RE::GFxValue::AttachMovie(&mc, a_className.data(), a_name.data(), a_depth); 31 | return mc; 32 | } 33 | 34 | GFxDisplayObject AttachMovie(const std::string_view& a_className, const std::string_view& a_name) 35 | { 36 | return AttachMovie(a_className, a_name, GetNextHighestDepth()); 37 | } 38 | 39 | std::int32_t GetNextHighestDepth() 40 | { 41 | return static_cast(Invoke("getNextHighestDepth").GetNumber()); 42 | } 43 | 44 | void SwapDepths(std::int32_t a_depth) 45 | { 46 | Invoke("swapDepths", a_depth); 47 | } 48 | 49 | void LoadMovie(const std::string_view& a_swfRelativePath) 50 | { 51 | Invoke("loadMovie", a_swfRelativePath.data()); 52 | } 53 | 54 | void UnloadMovie() 55 | { 56 | Invoke("unloadMovie"); 57 | } 58 | 59 | void RemoveMovieClip() 60 | { 61 | Invoke("removeMovieClip"); 62 | } 63 | 64 | RE::GPointF LocalToGlobal() 65 | { 66 | GFxObject pt(GetMovieView()); 67 | 68 | assert(pt.IsObject()); 69 | 70 | RE::GFxValue x = 0.0; 71 | pt.SetMember("x", x); 72 | 73 | RE::GFxValue y = 0.0; 74 | pt.SetMember("y", y); 75 | 76 | Invoke("localToGlobal", pt); 77 | 78 | x = pt.GetMember("x"); 79 | y = pt.GetMember("y"); 80 | 81 | return { static_cast(x.GetNumber()), static_cast(y.GetNumber()) }; 82 | } 83 | }; -------------------------------------------------------------------------------- /swf/CompassNaigationOverhaul.as2proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /include/RE/G/GFxLoadProcess.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxLoaderTask.h" 4 | #include "RE/G/GFxLogBase.h" 5 | #include "RE/G/GFxMovieDataDef.h" 6 | #include "RE/G/GFxStream.h" 7 | 8 | namespace RE 9 | { 10 | class GASExecuteTag; 11 | class GFxMovieBindProcess; 12 | class GFxSpriteDef; 13 | 14 | class GFxLoadProcess : 15 | public GFxLoaderTask, // 00 16 | public GFxLogBase // 20 17 | { 18 | public: 19 | using LoadTaskData = GFxMovieDataDef::LoadTaskData; 20 | 21 | virtual ~GFxLoadProcess(); // 00 22 | 23 | struct TimelineType 24 | { 25 | enum 26 | { 27 | kMovie, 28 | kSprite, 29 | 30 | kTotal 31 | }; 32 | }; 33 | 34 | // members 35 | std::uint32_t parseFlags; // 028 36 | std::uint32_t pad02C; // 02C 37 | GFxMovieBindProcess* movieBindProcess; // 030 38 | LoadTaskData* loadTaskData; // 038 39 | GFxMovieDataDef* movieData; // 040 40 | GFxStream stream; // 048 41 | std::uint32_t unk2B8; // 2B8 42 | std::uint32_t endOfFile; // 2BC 43 | std::uint64_t pad2C0; // 2C0 44 | GFxMovieHeaderData header; // 2C8 45 | std::uint64_t unk338; // 338 46 | std::uint32_t unk340; // 340 47 | std::uint32_t numImportedMovies; // 344 48 | std::uint64_t unk348; // 348 49 | std::uint32_t importInfoCount; // 350 50 | std::uint32_t pad354; // 354 51 | std::uint32_t unk358; // 358 52 | std::uint32_t pad35C; // 35C 53 | std::uint64_t unk360; // 360 54 | GFxImportNode* importInfo; // 368 55 | std::uint64_t unk370; // 370 56 | std::uint64_t unk378; // 378 57 | std::uint64_t unk380; // 380 58 | std::uint64_t unk388; // 388 59 | std::int32_t timelineType; // 390 60 | std::uint32_t pad394; // 394 61 | GFxSpriteDef* loadingSprite; // 398 62 | GArray loadingFrameData[TimelineType::kTotal]; // 3A0 63 | GArray importActions; // 3D0 64 | GFxStream* streamEx; // 3E8 65 | }; 66 | static_assert(sizeof(GFxLoadProcess) == 0x3F0); 67 | } 68 | -------------------------------------------------------------------------------- /include/RE/H/HUDMarkerManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/E/ExtraMapMarker.h" 4 | #include "RE/G/GFxValue.h" 5 | 6 | namespace RE 7 | { 8 | class HUDMarker 9 | { 10 | public: 11 | 12 | struct FrameOffsets 13 | { 14 | static FrameOffsets* GetSingleton() 15 | { 16 | REL::Relocation singleton{ RELOCATION_ID(519587, 406118) }; 17 | return singleton.get(); 18 | } 19 | 20 | std::uint32_t quest; // 00 21 | std::uint32_t questDoor; // 04 22 | std::uint32_t playerSet; // 08 23 | std::uint32_t enemy; // 0C 24 | std::uint32_t location; // 10 25 | std::uint32_t undiscoveredLocation; // 14 26 | }; 27 | static_assert(sizeof(FrameOffsets) == 0x18); 28 | 29 | struct ScaleformData 30 | { 31 | GFxValue heading; // 00 - angle relative to camera 32 | GFxValue alpha; // 18 33 | GFxValue type; // 30 - Goto and stop frame in flash 34 | GFxValue scale; // 48 35 | }; 36 | static_assert(sizeof(ScaleformData) == 0x60); 37 | 38 | std::uint32_t GetLocationGotoFrame(const MapMarkerData& a_mapMarker) const 39 | { 40 | auto frameOffsets = FrameOffsets::GetSingleton(); 41 | 42 | std::uint32_t locationFrameOffset = (a_mapMarker.flags & MapMarkerData::Flag::kCanTravelTo) ? 43 | frameOffsets->location : frameOffsets->undiscoveredLocation; 44 | 45 | return locationFrameOffset + a_mapMarker.type.underlying() - 1; 46 | } 47 | 48 | bool IsQuestFrame(std::uint32_t a_frame) const 49 | { 50 | auto frameOffsets = FrameOffsets::GetSingleton(); 51 | 52 | return a_frame == frameOffsets->quest || a_frame == frameOffsets->questDoor; 53 | } 54 | }; 55 | 56 | class HUDMarkerManager 57 | { 58 | public: 59 | 60 | static HUDMarkerManager* GetSingleton() 61 | { 62 | REL::Relocation singleton{ RELOCATION_ID(519611, 406154) }; 63 | return singleton.get(); 64 | } 65 | 66 | HUDMarker::ScaleformData scaleformMarkerData[49]; // 0000 67 | NiPoint3 position[48]; // 1260 68 | BSTArray locationRefs; // 14A0 69 | float sqRadiusToAddLocation; // 14B8 70 | std::uint32_t currentMarkerIndex; // 14BC 71 | std::uint32_t unk14C0; // 14C0 - Related to locations 72 | }; 73 | static_assert(sizeof(HUDMarkerManager) == 0x14C8); 74 | } -------------------------------------------------------------------------------- /include/Compass.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IUI/GFxArray.h" 4 | #include "IUI/GFxDisplayObject.h" 5 | 6 | namespace extended 7 | { 8 | class Compass : public IUI::GFxDisplayObject 9 | { 10 | public: 11 | static constexpr inline std::string_view path = "_level0.HUDMovieBaseInstance.CompassShoutMeterHolder.Compass"; 12 | 13 | static void InitSingleton(const GFxDisplayObject& a_originalCompass) 14 | { 15 | if (!singleton) 16 | { 17 | static Compass singletonInstance{ a_originalCompass }; 18 | singleton = &singletonInstance; 19 | } 20 | } 21 | 22 | static Compass* GetSingleton() { return singleton; } 23 | 24 | void SetupMod(const GFxDisplayObject& a_replaceCompass) 25 | { 26 | if (a_replaceCompass.HasMember("Compass")) 27 | { 28 | *static_cast(this) = a_replaceCompass; 29 | 30 | Invoke("Compass"); 31 | } 32 | } 33 | 34 | void SetUnits(bool a_useMetric) 35 | { 36 | Invoke("SetUnits", a_useMetric); 37 | } 38 | 39 | void SetMarkers() 40 | { 41 | Invoke("SetMarkers"); 42 | } 43 | 44 | void SetFocusedMarkerInfo(const std::string_view& a_targetText, float a_distance, 45 | float a_heightDifference, std::uint32_t a_markerIndex) 46 | { 47 | Invoke("SetFocusedMarkerInfo", a_targetText.data(), a_distance, a_heightDifference, 48 | a_markerIndex); 49 | } 50 | 51 | void FocusMarker(std::uint32_t a_focusedMarkerIndex) 52 | { 53 | Invoke("FocusMarker", a_focusedMarkerIndex); 54 | } 55 | 56 | void UnfocusMarker() 57 | { 58 | Invoke("UnfocusMarker"); 59 | } 60 | 61 | void UpdateFocusedMarker(std::uint32_t a_focusedMarkerIndex) 62 | { 63 | Invoke("UpdateFocusedMarker", a_focusedMarkerIndex); 64 | } 65 | 66 | void PostProcessMarkers(const std::unordered_map& a_unknownLocations, std::uint32_t a_markersCount) 67 | { 68 | GFxArray gfxIsUnknownLocations{ GetMovieView() }; 69 | 70 | for (std::uint32_t i = 0; i < a_markersCount; i++) 71 | { 72 | gfxIsUnknownLocations.PushBack(a_unknownLocations.contains(i)); 73 | } 74 | 75 | Invoke("PostProcessMarkers", gfxIsUnknownLocations); 76 | } 77 | 78 | private: 79 | 80 | Compass(const GFxDisplayObject& a_originalCompass) : GFxDisplayObject{ a_originalCompass } 81 | {} 82 | 83 | static inline Compass* singleton = nullptr; 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /include/RE/G/GASObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GASObjectInterface.h" 4 | #include "RE/G/GASRefCountBase.h" 5 | 6 | namespace RE 7 | { 8 | class GASObject : 9 | public GASRefCountBase, // 00 10 | public GASObjectInterface // 20 11 | { 12 | public: 13 | // override (GASRefCountBase) 14 | void Unk_00(void) override; // 00 15 | void Unk_01(void) override; // 01 16 | 17 | ~GASObject() override; // 02 18 | 19 | // override (GASObjectInterface) 20 | char const* GetTextValue(GASEnvironment*) const override; // 01 21 | ObjectType GetObjectType2() const override; // 02 22 | bool SetMember(GASEnvironment*, GASString const&, GASValue const&, GASPropFlags const&) override; // 03 23 | bool GetMember(GASEnvironment*, const GASString&, GASValue*) override; // 04 24 | bool FindMember(GASStringContext*, const GASString&, GASMember*) override; // 05 25 | bool DeleteMember(GASStringContext*, const GASString&) override; // 06 26 | bool SetMemberFlags(GASStringContext*, const GASString&, std::uint8_t) override; // 07 27 | void VisitMembers(GASStringContext*, MemberVisitor*, std::uint32_t, const GASObjectInterface*) const override; // 08 28 | bool HasMember(GASStringContext*, const GASString&, bool) override; // 09 29 | bool SetMemberRaw(GASStringContext*, const GASString&, const GASValue&, const GASPropFlags&) override; // 0A 30 | bool GetMemberRaw(GASStringContext*, const GASString&, GASValue*) override; // 0B 31 | void Set__proto__(GASStringContext* a_stringContext, GASObject* a_object) override; // 0D 32 | bool InstanceOf(GASEnvironment*, const GASObject*, bool) const override; // 12 33 | bool Watch(GASStringContext*, const GASString&, const GASFunctionRef&, const GASValue&) override; // 13 34 | bool Unwatch(GASStringContext*, const GASString&) override; // 14 35 | 36 | // add 37 | virtual void Unk_03(void); // 03 38 | virtual void Unk_04(void); // 04 39 | virtual void Unk_05(void); // 05 40 | virtual void Unk_06(void); // 06 41 | virtual void Unk_07(void); // 07 42 | virtual void Unk_08(void); // 08 43 | 44 | // members 45 | std::uint64_t unk38; // 38 - properties 46 | std::uint64_t unk40; // 40 - __resolve handler 47 | std::uint64_t unk48; // 48 48 | std::uint64_t unk50; // 50 49 | std::uint64_t unk58; // 58 50 | std::uint64_t unk60; // 60 51 | }; 52 | static_assert(sizeof(GASObject) == 0x68); 53 | } 54 | -------------------------------------------------------------------------------- /include/IUI/GFxDisplayObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GFxObject.h" 4 | 5 | #include "RE/G/GFxMovieDataDef.h" 6 | #include "RE/G/GFxSprite.h" 7 | #include "RE/G/GFxSpriteDef.h" 8 | 9 | namespace IUI 10 | { 11 | class GFxDisplayObject : public GFxObject 12 | { 13 | public: 14 | 15 | GFxDisplayObject(const RE::GFxValue& a_value) 16 | : GFxObject{ a_value } 17 | { 18 | assert(a_value.IsDisplayObject()); 19 | } 20 | 21 | GFxDisplayObject CreateEmptyMovieClip(const std::string_view& a_name, std::int32_t a_depth) 22 | { 23 | RE::GFxValue mc; 24 | RE::GFxValue::CreateEmptyMovieClip(&mc, a_name.data(), a_depth); 25 | return mc; 26 | } 27 | 28 | std::int32_t GetNextHighestDepth() 29 | { 30 | return static_cast(Invoke("getNextHighestDepth").GetNumber()); 31 | } 32 | 33 | void SwapDepths(std::int32_t a_depth) 34 | { 35 | Invoke("swapDepths", a_depth); 36 | } 37 | 38 | void LoadMovie(const std::string_view& a_swfRelativePath) 39 | { 40 | Invoke("loadMovie", a_swfRelativePath.data()); 41 | } 42 | 43 | void RemoveMovieClip() 44 | { 45 | Invoke("removeMovieClip"); 46 | } 47 | 48 | std::pair GetDefs() const 49 | { 50 | auto sprite = static_cast(static_cast(_value.obj)->character); 51 | auto movieDef = sprite->GetResourceMovieDef(); 52 | 53 | RE::GFxMovieDataDef::LoadTaskData::ResourceHash& movieResourceSources = movieDef->bindData->dataDef->loadTaskData->resources; 54 | 55 | auto resourceSourceIt = movieResourceSources.Find(sprite->resourceID); 56 | 57 | if (resourceSourceIt != movieResourceSources.end()) 58 | { 59 | RE::GFxResource* resource = resourceSourceIt->second.data.resource; 60 | 61 | if (resource->GetResourceType() == RE::GFxResource::ResourceType::kSpriteDef) 62 | { 63 | auto spriteDef = static_cast(resource); 64 | 65 | return { movieDef, spriteDef }; 66 | } 67 | } 68 | 69 | return { nullptr, nullptr }; 70 | } 71 | 72 | RE::GPointF LocalToGlobal() 73 | { 74 | GFxObject pt(GetMovieView()); 75 | 76 | assert(pt.IsObject()); 77 | 78 | RE::GFxValue x = 0.0; 79 | pt.SetMember("x", x); 80 | 81 | RE::GFxValue y = 0.0; 82 | pt.SetMember("y", y); 83 | 84 | Invoke("localToGlobal", pt); 85 | 86 | x = pt.GetMember("x"); 87 | y = pt.GetMember("y"); 88 | 89 | return { static_cast(x.GetNumber()), static_cast(y.GetNumber()) }; 90 | } 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /include/utils/GFxObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxMovieView.h" 4 | #include "RE/G/GFxValue.h" 5 | 6 | class GFxObject : public RE::GFxValue 7 | { 8 | public: 9 | 10 | static GFxObject GetFrom(RE::GFxMovieView* a_movieView, const std::string_view& a_pathToObject) 11 | { 12 | RE::GFxValue object; 13 | 14 | a_movieView->GetVariable(&object, a_pathToObject.data()); 15 | 16 | assert(object.IsObject()); 17 | 18 | return object; 19 | } 20 | 21 | template 22 | GFxObject(RE::GFxMovieView* a_movieView, Args&&... args) 23 | { 24 | std::array gfxArgs{ std::forward(args)... }; 25 | 26 | a_movieView->CreateObject(this, nullptr, sizeof...(Args) ? &gfxArgs[0] : nullptr, sizeof...(Args)); 27 | 28 | assert(GetMovieView() == a_movieView); 29 | assert(IsObject()); 30 | } 31 | 32 | template 33 | GFxObject(RE::GFxMovieView* a_movieView, const std::string_view& a_className, Args&&... args) 34 | { 35 | std::array gfxArgs{ std::forward(args)... }; 36 | 37 | a_movieView->CreateObject(this, a_className.data(), sizeof...(Args) ? &gfxArgs[0] : nullptr, sizeof...(Args)); 38 | 39 | assert(GetMovieView() == a_movieView); 40 | assert(IsObject()); 41 | } 42 | 43 | GFxObject(const RE::GFxValue& a_value) 44 | { 45 | *static_cast(this) = a_value; 46 | 47 | assert(IsObject()); 48 | } 49 | 50 | RE::GFxMovieView* GetMovieView() 51 | { 52 | return **reinterpret_cast(static_cast(this)); 53 | } 54 | 55 | RE::GFxValue GetMember(const std::string_view& a_memberName) const 56 | { 57 | RE::GFxValue value; 58 | RE::GFxValue::GetMember(a_memberName.data(), &value); 59 | return value; 60 | } 61 | 62 | bool SetMember(const std::string_view& a_memberName, const RE::GFxValue& a_value) 63 | { 64 | return RE::GFxValue::SetMember(a_memberName.data(), a_value); 65 | } 66 | 67 | template 68 | RE::GFxValue Invoke(const std::string_view& a_functionName, Args&&... args) 69 | { 70 | RE::GFxValue result; 71 | Invoke(a_functionName, &result, args...); 72 | GetMovieView()->Advance(0.0F); 73 | return result; 74 | } 75 | 76 | template 77 | bool Invoke(const std::string_view& a_functionName, RE::GFxValue* a_result, Args&&... args) 78 | { 79 | std::array gfxArgs{ std::forward(args)... }; 80 | 81 | return RE::GFxValue::Invoke(a_functionName.data(), a_result, 82 | sizeof...(Args) ? &gfxArgs[0] : nullptr, sizeof...(Args)); 83 | } 84 | }; -------------------------------------------------------------------------------- /include/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | 98 | #include 99 | #include 100 | #include 101 | 102 | #include 103 | #include 104 | #include 105 | 106 | #include 107 | #include 108 | 109 | #define DLLEXPORT __declspec(dllexport) 110 | 111 | using namespace std::literals; 112 | using namespace REL::literals; -------------------------------------------------------------------------------- /include/IUI/GFxObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxMovieView.h" 4 | #include "RE/G/GFxValue.h" 5 | 6 | namespace IUI 7 | { 8 | class GFxObject : public RE::GFxValue 9 | { 10 | protected: 11 | 12 | template 13 | GFxObject(RE::GFxMovieView* a_movieView, const char* a_className, Args&&... args) 14 | { 15 | std::array gfxArgs{ std::forward(args)... }; 16 | 17 | a_movieView->CreateObject(this, a_className, sizeof...(Args) ? &gfxArgs[0] : nullptr, sizeof...(Args)); 18 | 19 | assert(GetMovieView() == a_movieView); 20 | assert(IsObject()); 21 | } 22 | 23 | public: 24 | 25 | static GFxObject GetFrom(RE::GFxMovieView* a_movieView, const std::string_view& a_pathToObject) 26 | { 27 | RE::GFxValue object; 28 | 29 | a_movieView->GetVariable(&object, a_pathToObject.data()); 30 | 31 | assert(object.IsObject()); 32 | 33 | return object; 34 | } 35 | 36 | template 37 | GFxObject(RE::GFxMovieView* a_movieView, Args&&... args) 38 | { 39 | std::array gfxArgs{ std::forward(args)... }; 40 | 41 | a_movieView->CreateObject(this, nullptr, sizeof...(Args) ? &gfxArgs[0] : nullptr, sizeof...(Args)); 42 | 43 | assert(GetMovieView() == a_movieView); 44 | assert(IsObject()); 45 | } 46 | 47 | GFxObject(const RE::GFxValue& a_value) 48 | { 49 | *static_cast(this) = a_value; 50 | 51 | assert(IsObject()); 52 | } 53 | 54 | RE::GFxMovieView* GetMovieView() 55 | { 56 | return **reinterpret_cast(static_cast(this)); 57 | } 58 | 59 | RE::GFxValue GetMember(const std::string_view& a_memberName) const 60 | { 61 | RE::GFxValue value; 62 | RE::GFxValue::GetMember(a_memberName.data(), &value); 63 | return value; 64 | } 65 | 66 | bool SetMember(const std::string_view& a_memberName, const RE::GFxValue& a_value) 67 | { 68 | return RE::GFxValue::SetMember(a_memberName.data(), a_value); 69 | } 70 | 71 | template 72 | RE::GFxValue Invoke(const std::string_view& a_functionName, Args&&... args) 73 | { 74 | RE::GFxValue result; 75 | Invoke(a_functionName, &result, args...); 76 | return result; 77 | } 78 | 79 | template 80 | bool Invoke(const std::string_view& a_functionName, RE::GFxValue* a_result, Args&&... args) 81 | { 82 | std::array gfxArgs{ std::forward(args)... }; 83 | 84 | if (RE::GFxValue::Invoke(a_functionName.data(), a_result, 85 | sizeof...(Args) ? &gfxArgs[0] : nullptr, sizeof...(Args))) 86 | { 87 | return true; 88 | } 89 | else 90 | { 91 | return false; 92 | } 93 | } 94 | }; 95 | } 96 | -------------------------------------------------------------------------------- /include/utils/Geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace util 6 | { 7 | static constexpr float pi = std::numbers::pi_v; 8 | 9 | constexpr void CropAngleRange(float& a_angle) 10 | { 11 | if (a_angle <= 2 * pi) 12 | { 13 | if (a_angle < 0.0F) 14 | { 15 | a_angle = std::fmodf(a_angle, 2 * pi) + 2 * pi; 16 | } 17 | } 18 | else 19 | { 20 | a_angle = std::fmodf(a_angle, 2 * pi); 21 | } 22 | }; 23 | 24 | constexpr float RadiansToDegrees(float a_angle) 25 | { 26 | return a_angle * 180.0F / pi; 27 | } 28 | 29 | inline float GetAngleBetween(const RE::PlayerCamera* a_playerCamera, const RE::TESObjectREFR* a_markerRef) 30 | { 31 | RE::PlayerCharacter* player = RE::PlayerCharacter::GetSingleton(); 32 | RE::NiPoint3 playerPos = player->GetPosition(); 33 | 34 | // Skyrim used this instead, but less precise (don't know why) 35 | //RE::NiPoint3 markerPos = a_markerRef->GetLookingAtLocation(); 36 | 37 | RE::NiPoint3 markerPos = a_markerRef->GetPosition(); 38 | 39 | float playerCameraYawAngle = a_playerCamera->GetRuntimeData2().yaw; 40 | 41 | float compassAngle = playerCameraYawAngle; 42 | 43 | if (RE::TESObjectCELL* parentCell = player->GetParentCell()) 44 | { 45 | compassAngle += parentCell->GetNorthRotation(); 46 | } 47 | 48 | float headingAngle = playerPos.GetHorizontalAngleTo(markerPos); 49 | 50 | CropAngleRange(playerCameraYawAngle); 51 | CropAngleRange(compassAngle); 52 | CropAngleRange(headingAngle); 53 | 54 | float angle = headingAngle - playerCameraYawAngle; 55 | 56 | CropAngleRange(angle); 57 | 58 | return angle; 59 | } 60 | 61 | inline RE::NiPoint3 GetRealPosition(const RE::TESObjectREFR* a_objRef) 62 | { 63 | RE::NiPoint3 position = a_objRef->GetPosition(); 64 | 65 | if (const RE::TESWorldSpace* worldSpace = a_objRef->GetWorldspace()) 66 | { 67 | RE::NiPoint3 worldSpaceOffset{ worldSpace->worldMapOffsetData.mapOffsetX, 68 | worldSpace->worldMapOffsetData.mapOffsetY, 69 | worldSpace->worldMapOffsetData.mapOffsetZ }; 70 | 71 | position += worldSpaceOffset * worldSpace->worldMapOffsetData.mapScale; 72 | } 73 | 74 | return position; 75 | } 76 | 77 | inline float GetDistanceBetween(const RE::PlayerCharacter* a_player, const RE::TESObjectREFR* a_marker) 78 | { 79 | RE::NiPoint3 playerPos = GetRealPosition(a_player); 80 | RE::NiPoint3 markerPos = GetRealPosition(a_marker); 81 | 82 | return playerPos.GetDistance(markerPos); 83 | } 84 | 85 | inline float GetHeightDifferenceBetween(const RE::PlayerCharacter* a_player, const RE::TESObjectREFR* a_marker) 86 | { 87 | RE::NiPoint3 playerPos = GetRealPosition(a_player); 88 | RE::NiPoint3 markerPos = GetRealPosition(a_marker); 89 | 90 | return markerPos.z - playerPos.z; 91 | } 92 | } -------------------------------------------------------------------------------- /include/QuestItemList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IUI/GFxArray.h" 4 | #include "IUI/GFxDisplayObject.h" 5 | 6 | #include "Settings.h" 7 | 8 | class QuestItemList : public IUI::GFxDisplayObject 9 | { 10 | public: 11 | 12 | static constexpr inline std::string_view path = "_level0.HUDMovieBaseInstance.QuestItemList"; 13 | 14 | static void InitSingleton(const GFxDisplayObject& a_questItemList) 15 | { 16 | if (!singleton) 17 | { 18 | static QuestItemList singletonInstance{ a_questItemList }; 19 | singleton = &singletonInstance; 20 | } 21 | } 22 | 23 | static QuestItemList* GetSingleton() { return singleton; } 24 | 25 | bool CanBeDisplayed(RE::TESObjectCELL* a_cell, bool a_isPlayerWeaponDrawn) const 26 | { 27 | if (!a_isPlayerWeaponDrawn || !settings::questlist::hideInCombat) 28 | { 29 | if (a_cell) 30 | { 31 | if ((a_cell->IsInteriorCell() && settings::questlist::showInInteriors) || 32 | (a_cell->IsExteriorCell() && settings::questlist::showInExteriors)) 33 | { 34 | return true; 35 | } 36 | } 37 | } 38 | 39 | return false; 40 | } 41 | 42 | void SetHiddenByForce(bool a_hiddenByForce) { hiddenByForce = a_hiddenByForce; } 43 | 44 | bool IsHiddenByForce() const { return hiddenByForce; } 45 | 46 | void AddToHudElements() 47 | { 48 | Invoke("AddToHudElements"); 49 | } 50 | 51 | void AddQuest(RE::QUEST_DATA::Type a_questType, const std::string& a_questName, bool a_isInSameLocation, 52 | const std::vector& a_questObjectives, int a_questAgeIndex) 53 | { 54 | GFxArray gfxQuestObjectives{ GetMovieView() }; 55 | 56 | for (const std::string& questObjective : a_questObjectives) 57 | { 58 | gfxQuestObjectives.PushBack(questObjective.c_str()); 59 | } 60 | 61 | Invoke("AddQuest", a_questType, a_questName.c_str(), a_isInSameLocation, gfxQuestObjectives, a_questAgeIndex); 62 | } 63 | 64 | void SetQuestSide(const std::string& a_sideName) 65 | { 66 | Invoke("SetQuestSide", a_sideName.c_str()); 67 | } 68 | 69 | void Update() 70 | { 71 | Invoke("Update"); 72 | } 73 | 74 | void ShowQuest() 75 | { 76 | Invoke("ShowQuest"); 77 | } 78 | 79 | void RemoveQuest() 80 | { 81 | Invoke("RemoveQuest"); 82 | } 83 | 84 | void ShowAllQuests() 85 | { 86 | Invoke("ShowAllQuests"); 87 | } 88 | 89 | void RemoveAllQuests() 90 | { 91 | Invoke("RemoveAllQuests"); 92 | } 93 | 94 | private: 95 | 96 | QuestItemList(const GFxDisplayObject& a_questItemList) : 97 | GFxDisplayObject{ a_questItemList } 98 | { 99 | Invoke("QuestItemList", settings::questlist::positionX, settings::questlist::positionY, settings::questlist::maxHeight); 100 | } 101 | 102 | static inline QuestItemList* singleton = nullptr; 103 | 104 | bool hiddenByForce = false; 105 | }; -------------------------------------------------------------------------------- /include/utils/Setting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/S/Setting.h" 4 | 5 | #include 6 | 7 | namespace utils 8 | { 9 | // Deriving from RE::Setting does not compile as the virtual functions are not defined (Unresolved external symbols). 10 | // The best way I could find is to replicate that class layout into mine. 11 | class Setting 12 | { 13 | template 14 | friend RE::Setting* MakeSetting(const char* a_name, T a_data); 15 | 16 | using Type = RE::Setting::Type; 17 | 18 | template 19 | Setting(const char* a_name, T a_data) 20 | requires(std::same_as || 21 | std::same_as || 22 | std::same_as || 23 | std::same_as || 24 | std::same_as) 25 | { 26 | std::size_t nameLen = std::strlen(a_name) + sizeof('\0'); 27 | 28 | if (nameLen < MAX_PATH) { 29 | name = new char[nameLen]; 30 | strcpy_s(name, nameLen, a_name); 31 | 32 | if constexpr (std::is_same_v) { 33 | if (GetType() == Type::kString) { 34 | std::size_t dataLen = std::strlen(a_data) + sizeof('\0'); 35 | if (dataLen < MAX_PATH) { 36 | data.s = new char[dataLen]; 37 | strcpy_s(data.s, dataLen, a_data); 38 | 39 | return; 40 | } 41 | } 42 | } else if constexpr (std::is_same_v) { 43 | if (GetType() == Type::kBool) { 44 | data.b = a_data; 45 | 46 | return; 47 | } 48 | } else if constexpr (std::is_same_v) { 49 | if (GetType() == Type::kSignedInteger) { 50 | data.i = a_data; 51 | 52 | return; 53 | } 54 | } else if constexpr (std::is_same_v) { 55 | if (GetType() == Type::kUnsignedInteger) { 56 | data.u = a_data; 57 | 58 | return; 59 | } 60 | } else if constexpr (std::is_same_v) { 61 | if (GetType() == Type::kFloat) { 62 | data.f = a_data; 63 | 64 | return; 65 | } 66 | } 67 | 68 | delete[] name; 69 | name = nullptr; 70 | } 71 | } 72 | 73 | virtual ~Setting() // 00 74 | { 75 | if (name) { 76 | if (GetType() == Type::kString) { 77 | delete[] data.s; 78 | } 79 | 80 | delete[] name; 81 | } 82 | } 83 | 84 | // For the virtual table auto-generation. 85 | virtual bool Unk_01(void) { return false; } // 01 86 | 87 | Type GetType() const 88 | { 89 | return reinterpret_cast(this)->GetType(); 90 | } 91 | 92 | // members 93 | RE::Setting::Data data{}; // 08 94 | char* name; // 10 95 | }; 96 | static_assert(sizeof(Setting) == sizeof(RE::Setting)); 97 | 98 | template 99 | RE::Setting* MakeSetting(const char* a_name, T a_data) 100 | { 101 | return reinterpret_cast(new Setting{ a_name, a_data }); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /include/utils/GFxLoggers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/Logger.h" 4 | 5 | #include "RE/G/GFxMovieView.h" 6 | #include "RE/G/GFxValue.h" 7 | 8 | constexpr const char* const GFxValueTypeToString(RE::GFxValue::ValueType a_valueType) 9 | { 10 | switch (a_valueType) 11 | { 12 | case RE::GFxValue::ValueType::kNull: return "Null"; 13 | case RE::GFxValue::ValueType::kBoolean: return "Boolean"; 14 | case RE::GFxValue::ValueType::kNumber: return "Number"; 15 | case RE::GFxValue::ValueType::kString: return "String"; 16 | case RE::GFxValue::ValueType::kStringW: return "StringW"; 17 | case RE::GFxValue::ValueType::kArray: return "Array"; 18 | case RE::GFxValue::ValueType::kObject: return "Object"; 19 | case RE::GFxValue::ValueType::kDisplayObject: return "DisplayObject"; 20 | default: return "Undefined"; 21 | } 22 | }; 23 | 24 | template 25 | class GFxMemberLogger : public RE::GFxValue::ObjectVisitor 26 | { 27 | public: 28 | 29 | void LogMembersOf(const RE::GFxValue& a_value) 30 | { 31 | logger::at_level(logLevel, "{}: {}", a_value.ToString(), GFxValueTypeToString(a_value.GetType())); 32 | if (a_value.IsObject()) 33 | { 34 | logger::at_level(logLevel, "{}", "{"); 35 | a_value.VisitMembers(this); 36 | logger::at_level(logLevel, "{}", "}"); 37 | } 38 | logger::flush(); 39 | } 40 | 41 | void LogMembersOf(RE::GFxMovieView* a_view, const char* a_pathToMember) 42 | { 43 | if (a_view) 44 | { 45 | RE::GFxValue value; 46 | if (a_view->GetVariable(&value, a_pathToMember)) 47 | { 48 | LogMembersOf(value); 49 | } 50 | } 51 | } 52 | 53 | protected: 54 | 55 | using ValueType = RE::GFxValue::ValueType; 56 | 57 | void Visit(const char* a_name, const RE::GFxValue& a_value) override 58 | { 59 | std::string_view name = a_name; 60 | if (name != "PlayReverse" && name != "PlayForward") 61 | { 62 | logger::at_level(logLevel, "\tvar {}: {}", a_name, GFxValueTypeToString(a_value.GetType())); 63 | } 64 | } 65 | }; 66 | 67 | template 68 | class GFxArrayLogger : public RE::GFxValue::ArrayVisitor 69 | { 70 | public: 71 | 72 | void LogElementsOf(const RE::GFxValue& a_value) 73 | { 74 | logger::at_level(logLevel, "{}: {}", a_value.ToString(), GFxValueTypeToString(a_value.GetType())); 75 | if (a_value.IsArray()) 76 | { 77 | logger::at_level(logLevel, "{}", "{"); 78 | a_value.VisitElements(this); 79 | logger::at_level(logLevel, "{}", "}"); 80 | } 81 | logger::flush(); 82 | } 83 | void LogElementsOf(RE::GFxMovieView* a_view, const char* a_pathToMember) 84 | { 85 | if (a_view) 86 | { 87 | RE::GFxValue value; 88 | if (a_view->GetVariable(&value, a_pathToMember)) 89 | { 90 | LogElementsOf(value); 91 | } 92 | } 93 | } 94 | 95 | protected: 96 | 97 | using ValueType = RE::GFxValue::ValueType; 98 | 99 | void Visit(std::uint32_t a_idx, const RE::GFxValue& a_value) override 100 | { 101 | logger::at_level(logLevel, "\t[{}] {}: {}", a_idx, a_value.ToString(), GFxValueTypeToString(a_value.GetType())); 102 | } 103 | }; -------------------------------------------------------------------------------- /include/IUI/GFxLoggers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/Logger.h" 4 | 5 | #include "RE/G/GFxMovieView.h" 6 | #include "RE/G/GFxValue.h" 7 | 8 | constexpr const char* const GFxValueTypeToString(RE::GFxValue::ValueType a_valueType) 9 | { 10 | switch (a_valueType) 11 | { 12 | case RE::GFxValue::ValueType::kNull: return "Null"; 13 | case RE::GFxValue::ValueType::kBoolean: return "Boolean"; 14 | case RE::GFxValue::ValueType::kNumber: return "Number"; 15 | case RE::GFxValue::ValueType::kString: return "String"; 16 | case RE::GFxValue::ValueType::kStringW: return "StringW"; 17 | case RE::GFxValue::ValueType::kArray: return "Array"; 18 | case RE::GFxValue::ValueType::kObject: return "Object"; 19 | case RE::GFxValue::ValueType::kDisplayObject: return "DisplayObject"; 20 | default: return "Undefined"; 21 | } 22 | }; 23 | 24 | template 25 | class GFxMemberLogger : public RE::GFxValue::ObjectVisitor 26 | { 27 | public: 28 | 29 | void LogMembersOf(const RE::GFxValue& a_value) 30 | { 31 | logger::at_level(logLevel, "{}: {}", a_value.ToString().c_str(), GFxValueTypeToString(a_value.GetType())); 32 | if (a_value.IsObject()) 33 | { 34 | logger::at_level(logLevel, "{}", "{"); 35 | a_value.VisitMembers(this); 36 | logger::at_level(logLevel, "{}", "}"); 37 | } 38 | logger::flush(); 39 | } 40 | 41 | void LogMembersOf(RE::GFxMovieView* a_view, const char* a_pathToMember) 42 | { 43 | if (a_view) 44 | { 45 | RE::GFxValue value; 46 | if (a_view->GetVariable(&value, a_pathToMember)) 47 | { 48 | LogMembersOf(value); 49 | } 50 | } 51 | } 52 | 53 | protected: 54 | 55 | using ValueType = RE::GFxValue::ValueType; 56 | 57 | void Visit(const char* a_name, const RE::GFxValue& a_value) override 58 | { 59 | std::string_view name = a_name; 60 | if (name != "PlayReverse" && name != "PlayForward") 61 | { 62 | logger::at_level(logLevel, "\tvar {}: {}", a_name, GFxValueTypeToString(a_value.GetType())); 63 | } 64 | } 65 | }; 66 | 67 | template 68 | class GFxArrayLogger : public RE::GFxValue::ArrayVisitor 69 | { 70 | public: 71 | 72 | void LogElementsOf(const RE::GFxValue& a_value) 73 | { 74 | logger::at_level(logLevel, "{}: {}", a_value.ToString(), GFxValueTypeToString(a_value.GetType())); 75 | if (a_value.IsArray()) 76 | { 77 | logger::at_level(logLevel, "{}", "{"); 78 | a_value.VisitElements(this); 79 | logger::at_level(logLevel, "{}", "}"); 80 | } 81 | logger::flush(); 82 | } 83 | void LogElementsOf(RE::GFxMovieView* a_view, const char* a_pathToMember) 84 | { 85 | if (a_view) 86 | { 87 | RE::GFxValue value; 88 | if (a_view->GetVariable(&value, a_pathToMember)) 89 | { 90 | LogElementsOf(value); 91 | } 92 | } 93 | } 94 | 95 | protected: 96 | 97 | using ValueType = RE::GFxValue::ValueType; 98 | 99 | void Visit(std::uint32_t a_idx, const RE::GFxValue& a_value) override 100 | { 101 | logger::at_level(logLevel, "\t[{}] {}: {}", a_idx, a_value.ToString().c_str(), GFxValueTypeToString(a_value.GetType())); 102 | } 103 | }; -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -4 3 | AlignAfterOpenBracket: DontAlign 4 | AlignConsecutiveAssignments: 'false' 5 | AlignConsecutiveDeclarations: 'false' 6 | AlignConsecutiveMacros: 'false' 7 | AlignEscapedNewlines: Left 8 | AlignOperands: 'true' 9 | AlignTrailingComments: 'true' 10 | AllowAllArgumentsOnNextLine: 'false' 11 | AllowAllConstructorInitializersOnNextLine: 'false' 12 | AllowAllParametersOfDeclarationOnNextLine: 'false' 13 | AllowShortBlocksOnASingleLine: Empty 14 | AllowShortCaseLabelsOnASingleLine: 'false' 15 | AllowShortFunctionsOnASingleLine: All 16 | AllowShortIfStatementsOnASingleLine: Never 17 | AllowShortLambdasOnASingleLine: All 18 | AllowShortLoopsOnASingleLine: 'true' 19 | AlwaysBreakAfterReturnType: None 20 | AlwaysBreakBeforeMultilineStrings: 'true' 21 | AlwaysBreakTemplateDeclarations: 'Yes' 22 | BinPackArguments: 'true' 23 | BinPackParameters: 'true' 24 | BraceWrapping: 25 | AfterCaseLabel: 'true' 26 | AfterClass: 'true' 27 | AfterControlStatement: 'false' 28 | AfterEnum: 'true' 29 | AfterExternBlock: 'true' 30 | AfterFunction: 'true' 31 | AfterNamespace: 'true' 32 | AfterStruct: 'true' 33 | AfterUnion: 'true' 34 | BeforeCatch: 'false' 35 | BeforeElse: 'false' 36 | IndentBraces: 'false' 37 | SplitEmptyFunction: 'false' 38 | SplitEmptyNamespace: 'false' 39 | SplitEmptyRecord: 'false' 40 | BreakBeforeBinaryOperators: None 41 | BreakBeforeBraces: Custom 42 | BreakBeforeTernaryOperators: 'false' 43 | BreakConstructorInitializers: AfterColon 44 | BreakInheritanceList: AfterColon 45 | BreakStringLiterals: 'true' 46 | ColumnLimit: 0 47 | CompactNamespaces: 'false' 48 | ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' 49 | ConstructorInitializerIndentWidth: 4 50 | ContinuationIndentWidth: 4 51 | Cpp11BracedListStyle: 'false' 52 | DeriveLineEnding: 'true' 53 | DerivePointerAlignment: 'false' 54 | DisableFormat: 'false' 55 | FixNamespaceComments: 'false' 56 | IncludeBlocks: Preserve 57 | IndentCaseBlocks: 'true' 58 | IndentCaseLabels: 'false' 59 | IndentGotoLabels: 'false' 60 | IndentPPDirectives: None 61 | IndentWidth: 4 62 | IndentWrappedFunctionNames: 'true' 63 | KeepEmptyLinesAtTheStartOfBlocks: 'false' 64 | Language: Cpp 65 | MaxEmptyLinesToKeep: 2 66 | NamespaceIndentation: All 67 | PointerAlignment: Left 68 | ReflowComments : 'false' 69 | SortIncludes: 'true' 70 | SortUsingDeclarations: 'true' 71 | SpaceAfterCStyleCast: 'false' 72 | SpaceAfterLogicalNot: 'false' 73 | SpaceAfterTemplateKeyword: 'true' 74 | SpaceBeforeAssignmentOperators: 'true' 75 | SpaceBeforeCpp11BracedList: 'false' 76 | SpaceBeforeCtorInitializerColon: 'true' 77 | SpaceBeforeInheritanceColon: 'true' 78 | SpaceBeforeParens: ControlStatements 79 | SpaceBeforeRangeBasedForLoopColon: 'true' 80 | SpaceBeforeSquareBrackets: 'false' 81 | SpaceInEmptyBlock: 'false' 82 | SpaceInEmptyParentheses: 'false' 83 | SpacesBeforeTrailingComments: 2 84 | SpacesInAngles: 'false' 85 | SpacesInCStyleCastParentheses: 'false' 86 | SpacesInConditionalStatement: 'false' 87 | SpacesInContainerLiterals: 'true' 88 | SpacesInParentheses: 'false' 89 | SpacesInSquareBrackets: 'false' 90 | Standard: c++17 91 | TabWidth: 4 92 | UseCRLF: 'true' 93 | UseTab: Always 94 | 95 | ... 96 | -------------------------------------------------------------------------------- /include/RE/G/GFxSpriteDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GArrayLH.h" 4 | #include "RE/G/GFxTimelineDef.h" 5 | #include "RE/G/GStringHash.h" 6 | 7 | namespace RE 8 | { 9 | class GFxCharacter; 10 | class GFxMovieDataDef; 11 | class GFxScale9Grid; 12 | 13 | class GFxTimelineIODef : public GFxTimelineDef 14 | { 15 | public: 16 | // add 17 | virtual void SetLoadingPlaylistFrame(const Frame& a_frame) = 0; // 0E 18 | virtual void AddFrameName(const GString& a_name, GFxLog* a_log) = 0; // 0F 19 | }; 20 | static_assert(sizeof(GFxTimelineIODef) == 0x20); 21 | 22 | class GFxSpriteDef : public GFxTimelineIODef 23 | { 24 | public: 25 | ~GFxSpriteDef() override; // 00 26 | 27 | // override (GFxResource) 28 | std::uint32_t GetResourceTypeCode() const override; // 02 29 | 30 | // override (GFxCharacterDef) 31 | bool DefPointTestLocal(const GPointF& a_pt, bool a_testShape, const GFxCharacter* a_character) const override; // 05 32 | std::uint32_t GetVersion() const override; // 08 33 | GFxCharacter* CreateCharacter(GFxASCharacter* a_asCharacter, GFxResourceID a_resourceID, GFxMovieDefImpl* a_movieDefImpl) override; // 09 34 | 35 | // override (GFxTimelineDef) 36 | std::uint32_t GetFrameCount() const override; // 0A 37 | const Frame GetPlayList(std::int32_t a_frameNumber) const override; // 0B 38 | bool GetInitActions(Frame* a_frame, std::int32_t a_frameNumber) const override; // 0C - { return false; } 39 | bool GetLabeledFrame(const char* a_label, std::uint32_t* a_frameNumber, bool a_translateNumbers) override; // 0D 40 | 41 | // override (GFxTimelineIODef) 42 | void SetLoadingPlaylistFrame(const Frame& a_frame) override; // 0E 43 | void AddFrameName(const GString& a_name, GFxLog* a_log) override; // 0F 44 | 45 | // add 46 | virtual float GetWidth() const; // 10 - { return 1.0f; } 47 | virtual float GetHeight() const; // 11 - { return 1.0f; } 48 | virtual float GeFrameRate() const; // 12 49 | virtual GRectF GetFrameRect() const; // 13 50 | virtual std::int32_t GetLoadingFrame(); // 14 51 | virtual std::uint32_t GetSWFFlags(); // 15 52 | virtual std::uint32_t GetTagCount() const; // 16 - { return 0; } 53 | virtual std::uint64_t GetFileBytes() const; // 17 54 | virtual const char* GetFileURL(); // 18 55 | 56 | // members 57 | GFxMovieDataDef* movieData; // 20 58 | GStringHash frameLabels; // 28 59 | std::int32_t frameCount; // 30 60 | std::int32_t frameLoading; // 34 61 | GArrayLH playlist; // 38 62 | GFxScale9Grid* scale9Grid; // 50 63 | std::uint8_t buttonState; // 58 - 0x1 = up, 0x2 = down, 0x4 = over 64 | std::uint8_t pad59; // 59 65 | std::uint16_t pad5A; // 5A 66 | std::uint32_t pad5C; // 5C 67 | }; 68 | static_assert(sizeof(GFxSpriteDef) == 0x60); 69 | } 70 | -------------------------------------------------------------------------------- /include/HUDMarkerManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/H/HUDMarkerManager.h" 4 | 5 | #include "Settings.h" 6 | 7 | #include "FocusedMarker.h" 8 | #include "Compass.h" 9 | #include "QuestItemList.h" 10 | 11 | namespace extended 12 | { 13 | class HUDMarkerManager 14 | { 15 | public: 16 | 17 | static HUDMarkerManager* GetSingleton() 18 | { 19 | static HUDMarkerManager singleton; 20 | 21 | return &singleton; 22 | } 23 | 24 | void ProcessQuestMarker(RE::TESQuest* a_quest, RE::BGSInstancedQuestObjective& a_objective, RE::TESQuestTarget* a_target, 25 | RE::TESObjectREFR* a_marker, std::uint32_t a_markerGotoFrame); 26 | 27 | void ProcessLocationMarker(RE::ExtraMapMarker* a_mapMarker, RE::TESObjectREFR* a_marker, 28 | std::uint32_t a_markerGotoFrame); 29 | 30 | void ProcessEnemyMarker(RE::Character* a_enemy, std::uint32_t a_markerGotoFrame); 31 | 32 | void ProcessPlayerSetMarker(RE::TESObjectREFR* a_marker, std::uint32_t a_markerGotoFrame); 33 | 34 | void SetMarkers(); 35 | 36 | private: 37 | 38 | bool IsTheFocusedMarker(const RE::TESObjectREFR* a_marker) const { return focusedMarker && a_marker == focusedMarker->ref; } 39 | 40 | std::shared_ptr GetFacedMarkerUpdated(const RE::TESObjectREFR* a_marker, float a_angleToPlayerCamera); 41 | 42 | std::shared_ptr 43 | GetMostCenteredMarkerOf(const std::unordered_map>& a_facedMarkers) const; 44 | 45 | bool UpdateFocusedMarker(); 46 | 47 | float GetAngleBetween(const RE::PlayerCamera* a_playerCamera, const RE::TESObjectREFR* a_marker) const; 48 | 49 | bool IsPlayerAllyOfFaction(const RE::TESFaction* a_faction) const; 50 | 51 | bool IsPlayerOpponentOfFaction(const RE::TESFaction* a_faction) const; 52 | 53 | std::string GetSideInQuest(RE::QUEST_DATA::Type a_questType) const; 54 | 55 | Compass* compass = Compass::GetSingleton(); 56 | QuestItemList* questItemList = QuestItemList::GetSingleton(); 57 | 58 | float facingAngle = settings::display::angleToShowMarkerDetails; 59 | float keepFocusedAngle = settings::display::angleToKeepMarkerDetailsShown; 60 | 61 | std::unordered_map> facedMarkers; 62 | std::shared_ptr focusedMarker; 63 | float timeFocusingMarker = 0.0F; 64 | 65 | std::shared_ptr lastMostCenteredMarker = nullptr; 66 | float timeFacingMarker = 0.0F; 67 | 68 | RE::HUDMarkerManager* const hudMarkerManager = RE::HUDMarkerManager::GetSingleton(); 69 | RE::PlayerCharacter* player = RE::PlayerCharacter::GetSingleton(); 70 | RE::PlayerCamera* playerCamera = RE::PlayerCamera::GetSingleton(); 71 | RE::BSTimer* timeManager = RE::BSTimer::GetTimeManager(); 72 | 73 | // Factions to lookup 74 | // Reference: Creation Kit -> Skyrim.esm, Dawnguard.esm 75 | const RE::TESFaction* const imperialLegionFaction = RE::TESForm::LookupByID(0x0002BF9A)->As(); 76 | const RE::TESFaction* const stormCloaksFaction = RE::TESForm::LookupByID(0x00028849)->As(); 77 | const RE::TESFaction* const sonsOfSkyrimFaction = RE::TESForm::LookupByID(0x0002BF9B)->As(); 78 | const RE::TESFaction* const dawnGuardFaction = RE::TESForm::LookupByID(0x02014217)->As(); 79 | const RE::TESFaction* const vampireFaction = RE::TESForm::LookupByID(0x02003376)->As(); 80 | }; 81 | } -------------------------------------------------------------------------------- /include/utils/INISettingCollection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/I/INISettingCollection.h" 4 | 5 | #include "Setting.h" 6 | 7 | namespace utils 8 | { 9 | // Deriving from RE::INISettingCollection does not compile as the virtual functions are not defined (Unresolved external symbols). 10 | // The best way I could find is to replicate that class layout into mine. 11 | class INISettingCollection 12 | { 13 | static constexpr REL::RelocationID vTableId = RELOCATION_ID(230108, 187074); 14 | 15 | public: 16 | static INISettingCollection* GetSingleton() 17 | { 18 | static INISettingCollection singleton; 19 | 20 | return &singleton; 21 | } 22 | 23 | template 24 | void AddSettings(Last a_last) 25 | { 26 | _this()->InsertSetting(a_last); 27 | } 28 | 29 | template 30 | void AddSettings(First a_first, Rest... a_rest) 31 | { 32 | _this()->InsertSetting(a_first); 33 | AddSettings(a_rest...); 34 | } 35 | 36 | template 37 | T GetSetting(const char* a_name) const 38 | { 39 | return const_cast(_this())->GetSetting(a_name); 40 | } 41 | 42 | template <> 43 | bool GetSetting(const char* a_name) const 44 | { 45 | return GetSetting(a_name)->GetBool(); 46 | } 47 | template <> 48 | float GetSetting(const char* a_name) const 49 | { 50 | return GetSetting(a_name)->GetFloat(); 51 | } 52 | template <> 53 | std::int32_t GetSetting(const char* a_name) const 54 | { 55 | return GetSetting(a_name)->GetSInt(); 56 | } 57 | template <> 58 | RE::Color GetSetting(const char* a_name) const 59 | { 60 | return GetSetting(a_name)->GetColor(); 61 | } 62 | template <> 63 | const char* GetSetting(const char* a_name) const 64 | { 65 | return GetSetting(a_name)->GetString(); 66 | } 67 | template <> 68 | std::uint32_t GetSetting(const char* a_name) const 69 | { 70 | return GetSetting(a_name)->GetUInt(); 71 | } 72 | 73 | bool ReadFromFile(std::string_view a_fileName); 74 | 75 | private: 76 | INISettingCollection() noexcept; 77 | 78 | // Virtual table auto-generation. Needed to replace the original class. 79 | virtual ~INISettingCollection() = default; // 00 80 | 81 | virtual void InsertSetting(RE::Setting*) { throw(""); } // 01 82 | virtual void RemoveSetting(RE::Setting*) { throw(""); } // 02 83 | virtual bool WriteSetting(RE::Setting*) { throw(""); } // 03 84 | virtual bool ReadSetting(RE::Setting*) { throw(""); } // 04 85 | virtual bool OpenHandle(bool) { throw(""); } // 05 86 | virtual bool CloseHandle() { throw(""); } // 06 87 | virtual void Unk_07() { throw(""); } // 07 88 | virtual void WriteAllSettings() { throw(""); } // 08 89 | virtual void ReadAllSettings() { throw(""); } // 09 90 | 91 | RE::INISettingCollection* _this() { return reinterpret_cast(this); } 92 | const RE::INISettingCollection* _this() const { return reinterpret_cast(this); } 93 | 94 | // members 95 | char subKey[MAX_PATH]; // 008 96 | std::uint32_t pad10C; // 10C 97 | void* handle; // 110 98 | RE::BSSimpleList settings; // 118 99 | }; 100 | static_assert(sizeof(INISettingCollection) == sizeof(RE::INISettingCollection)); 101 | } 102 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.21) 2 | 3 | ######################################################################################################################## 4 | ## Define project 5 | ######################################################################################################################## 6 | 7 | project( 8 | CompassNavigationOverhaul 9 | VERSION 2.2.0 10 | LANGUAGES CXX 11 | ) 12 | 13 | set(CMAKE_CXX_STANDARD 23) 14 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 15 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) 16 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_DEBUG OFF) 17 | 18 | configure_file( 19 | ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in 20 | ${CMAKE_CURRENT_BINARY_DIR}/version.rc 21 | @ONLY 22 | ) 23 | 24 | file(GLOB_RECURSE headers "include/*.h") 25 | file(GLOB_RECURSE sources "source/*.cpp") 26 | 27 | source_group( 28 | TREE 29 | ${CMAKE_CURRENT_SOURCE_DIR} 30 | FILES 31 | ${headers} 32 | ${sources} 33 | ) 34 | 35 | ######################################################################################################################## 36 | ## Configure target DLL 37 | ######################################################################################################################## 38 | 39 | find_package(CommonLibSSE CONFIG REQUIRED) 40 | find_package(spdlog REQUIRED CONFIG) 41 | find_package(directxtk CONFIG REQUIRED) 42 | 43 | add_commonlibsse_plugin(${PROJECT_NAME} SOURCES ${headers} ${sources}) 44 | add_library("${PROJECT_NAME}::${PROJECT_NAME}" ALIAS "${PROJECT_NAME}") 45 | 46 | target_include_directories( 47 | ${PROJECT_NAME} 48 | PRIVATE 49 | ${CMAKE_CURRENT_SOURCE_DIR}/include 50 | ) 51 | 52 | target_link_libraries( 53 | ${PROJECT_NAME} 54 | PRIVATE 55 | CommonLibSSE::CommonLibSSE 56 | spdlog::spdlog_header_only 57 | Microsoft::DirectXTK 58 | ) 59 | 60 | if (MSVC) 61 | target_link_options( 62 | ${PROJECT_NAME} 63 | PRIVATE 64 | "$<$:/INCREMENTAL;/OPT:NOREF;/OPT:NOICF>" 65 | "$<$:/INCREMENTAL:NO;/OPT:REF;/OPT:ICF>" 66 | ) 67 | endif() 68 | 69 | target_precompile_headers( 70 | ${PROJECT_NAME} 71 | PRIVATE 72 | include/PCH.h 73 | ) 74 | 75 | ######################################################################################################################## 76 | ## Automatic plugin deployment 77 | ######################################################################################################################## 78 | 79 | set(SKYRIM_SE_DIR "C:/Program Files (x86)/Steam/steamapps/common/Skyrim Special Edition") 80 | set(SKYRIM_VR_DIR "C:/Program Files (x86)/Steam/steamapps/common/Skyrim VR") 81 | 82 | if ("$ENV{RUNTIME_DISABLE_FLAGS}" STREQUAL "") 83 | set(COPY_SE YES) 84 | set(COPY_VR YES) 85 | elseif ("$ENV{RUNTIME_DISABLE_FLAGS}" STREQUAL "-UENABLE_SKYRIM_VR") 86 | set(COPY_SE YES) 87 | set(COPY_VR NO) 88 | elseif ("$ENV{RUNTIME_DISABLE_FLAGS}" STREQUAL "-UENABLE_SKYRIM_SE -UENABLE_SKYRIM_AE") 89 | set(COPY_SE NO) 90 | set(COPY_VR YES) 91 | endif() 92 | 93 | if (COPY_SE) 94 | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 95 | COMMAND ${CMAKE_COMMAND} -E copy $ 96 | "${SKYRIM_SE_DIR}/Data/SKSE/Plugins/$" 97 | ) 98 | endif() 99 | if (COPY_VR) 100 | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 101 | COMMAND ${CMAKE_COMMAND} -E copy $ 102 | "${SKYRIM_VR_DIR}/Data/SKSE/Plugins/$" 103 | ) 104 | endif() 105 | -------------------------------------------------------------------------------- /swf/Compass.as: -------------------------------------------------------------------------------- 1 | #include "../utils.as" 2 | 3 | import FocusedMarker; 4 | 5 | // Instances 6 | var CompassFrame:MovieClip; 7 | var CompassTemperatureHolderInstance:MovieClip; 8 | var CompassMask_mc:MovieClip; 9 | var DirectionRect:MovieClip; 10 | var CompassFrameAlt:MovieClip; 11 | 12 | var FocusedMarkerInstance:FocusedMarker; 13 | 14 | // References 15 | var MarkerList:Array = _root.HUDMovieBaseInstance.CompassMarkerList; 16 | 17 | function Compass():Void 18 | { 19 | CompassTemperatureHolderInstance.gotoAndStop("Empty"); 20 | _root.HUDMovieBaseInstance.TemperatureMeter_mc = CompassTemperatureHolderInstance; 21 | 22 | _root.HUDMovieBaseInstance.CompassRect = DirectionRect; 23 | 24 | if (_root.HUDMovieBaseInstance.CompassFrameAlt == undefined) 25 | { 26 | CompassFrameAlt._visible = false; 27 | DirectionRect.CompassDirectionTextAlt._visible = false; 28 | } 29 | else 30 | { 31 | _root.HUDMovieBaseInstance.CompassFrame = CompassFrame; 32 | _root.HUDMovieBaseInstance.CompassFrameAlt = CompassFrameAlt; 33 | _root.HUDMovieBaseInstance.CompassCard = DirectionRect.CompassDirectionText; 34 | _root.HUDMovieBaseInstance.CompassCardAlt = DirectionRect.CompassDirectionTextAlt; 35 | } 36 | } 37 | 38 | function SetUnits(a_useMetric:Boolean):Void 39 | { 40 | FocusedMarkerInstance.UseMetricUnits = a_useMetric; 41 | } 42 | 43 | function SetMarkerInfo(a_target:String, a_distance:Number, a_heightDifference:Number):Void 44 | { 45 | FocusedMarkerInstance.SetDistanceAndHeightDifference(a_distance, a_heightDifference); 46 | FocusedMarkerInstance.Target.TextFieldInstance.text = a_target; 47 | } 48 | 49 | function FocusMarker(a_markerIndex:Number):Void 50 | { 51 | FocusedMarkerInstance.gotoAndPlay("FadeIn"); 52 | UpdateMarker(a_markerIndex); 53 | } 54 | 55 | function UpdateMarker(a_markerIndex:Number):Void 56 | { 57 | FocusedMarkerInstance.Movie = MarkerList[a_markerIndex].movie; 58 | FocusedMarkerInstance.Index = a_markerIndex; 59 | 60 | // Workaround-fix for pop-up out of compass when changing index 61 | var focusedMarker_x:Number = localToLocal(FocusedMarkerInstance.Movie, this).x; 62 | var compassMask_x:Number = localToLocal(CompassMask_mc, this).x; 63 | if (focusedMarker_x >= compassMask_x) 64 | { 65 | FocusedMarkerInstance._x = focusedMarker_x; 66 | } 67 | FocusedMarkerInstance._alpha = Math.max(FocusedMarkerInstance.Movie._alpha, 75); 68 | 69 | if (_root.HUDMovieBaseInstance.EnemyHealth_mc.BracketsInstance._alpha) 70 | { 71 | FocusedMarkerInstance.Target.TextFieldInstance._alpha = 0; 72 | } 73 | else 74 | { 75 | FocusedMarkerInstance.Target.TextFieldInstance._alpha = 100; 76 | } 77 | 78 | // iHUD show/hide functionality 79 | if (DirectionRect._alpha) 80 | { 81 | FocusedMarkerInstance._alpha = 100; 82 | } 83 | else 84 | { 85 | FocusedMarkerInstance._alpha = 0; 86 | } 87 | } 88 | 89 | function UnfocusMarker(a_markerIndex:Number):Void 90 | { 91 | FocusedMarkerInstance.gotoAndPlay("FadeOut"); 92 | FocusedMarkerInstance.Movie = undefined; 93 | FocusedMarkerInstance.Index = -1; 94 | } 95 | 96 | function SetMarkersSize():Void 97 | { 98 | var MarkerList_length:Number = MarkerList.length; 99 | for (var i:Number = 0; i < MarkerList_length; i++) 100 | { 101 | var marker:MovieClip = MarkerList[i].movie; 102 | 103 | if (i == FocusedMarkerInstance.Index) 104 | { 105 | marker._xscale = Math.min(150, marker._xscale * 1.325); 106 | marker._yscale = Math.min(150, marker._yscale * 1.325); 107 | } 108 | else 109 | { 110 | marker._xscale = Math.min(135, marker._xscale); 111 | marker._yscale = Math.min(135, marker._yscale); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /include/FocusedMarker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NPCNameProvider.h" 4 | 5 | #include "utils/Geometry.h" 6 | 7 | #include "Settings.h" 8 | 9 | struct FocusedMarker 10 | { 11 | struct Data 12 | { 13 | Data(std::uint32_t a_gfxIndex, std::uint32_t a_gfxGotoFrame) : 14 | gfxIndex{ a_gfxIndex }, gfxGotoFrame{ a_gfxGotoFrame } 15 | {} 16 | 17 | virtual ~Data() = default; 18 | 19 | std::uint32_t gfxIndex; 20 | std::uint32_t gfxGotoFrame; 21 | }; 22 | 23 | struct QuestData : Data 24 | { 25 | QuestData(std::uint32_t a_gfxIndex, std::uint32_t a_gfxGotoFrame, RE::TESObjectREFR* a_markerRef, 26 | const RE::TESQuest* a_quest); 27 | 28 | std::string GetQuestName(const RE::TESQuest* a_quest) const 29 | { 30 | RE::BSString questFullName = a_quest->GetFullName(); 31 | 32 | ReplaceTagsInQuestText(&questFullName, a_quest, a_quest->currentInstanceID); 33 | 34 | return questFullName.c_str(); 35 | } 36 | 37 | std::string GetTargetText() const 38 | { 39 | if (settings::display::showObjectiveAsTarget) 40 | { 41 | return objectives.empty() ? std::string("") : objectives.front(); 42 | } 43 | else 44 | { 45 | return locationName.empty() ? characterName : locationName; 46 | } 47 | } 48 | 49 | const RE::TESQuest* quest; 50 | 51 | // cache 52 | RE::QUEST_DATA::Type type = quest->GetType(); 53 | std::string name = (type == RE::QUEST_DATA::Type::kMiscellaneous) ? "$MISCELLANEOUS" : GetQuestName(quest); 54 | bool isInSameLocation; 55 | std::string description = quest->GetCurrentDescriptionWithReplacedTags().c_str(); 56 | std::vector objectives; 57 | std::string locationName; 58 | std::string characterName; 59 | int ageIndex = -1; 60 | 61 | // Avoid repeating added objectives for each marker 62 | std::vector addedInstancedObjectives; 63 | }; 64 | 65 | struct LocationData : Data 66 | { 67 | LocationData(std::uint32_t a_gfxIndex, std::uint32_t a_gfxGotoFrame, const RE::MapMarkerData* a_extraData) : 68 | Data{ a_gfxIndex, a_gfxGotoFrame }, extraData{ a_extraData } 69 | {} 70 | 71 | const RE::MapMarkerData* extraData; 72 | 73 | // cache 74 | std::string locationName = extraData->locationName.GetFullName(); 75 | }; 76 | 77 | struct EnemyData : Data 78 | { 79 | EnemyData(std::uint32_t a_gfxIndex, std::uint32_t a_gfxGotoFrame, RE::Character* a_enemy) : 80 | Data{ a_gfxIndex, a_gfxGotoFrame }, enemy{ a_enemy } 81 | {} 82 | 83 | RE::Character* enemy; 84 | 85 | // cache 86 | std::string enemyName = NPCNameProvider::GetSingleton()->GetName(enemy); 87 | }; 88 | 89 | struct PlayerSetData : Data 90 | { 91 | PlayerSetData(std::uint32_t a_gfxIndex, std::uint32_t a_gfxGotoFrame) : 92 | Data{ a_gfxIndex, a_gfxGotoFrame } 93 | {} 94 | 95 | std::string locationName = ""; 96 | }; 97 | 98 | FocusedMarker(const RE::TESObjectREFR* a_markerRef, float a_angleToPlayerCamera) : 99 | ref{ a_markerRef }, angleToPlayerCamera{ a_angleToPlayerCamera } 100 | {} 101 | 102 | void UpdateGeometry(float a_angleToPlayerCamera) 103 | { 104 | angleToPlayerCamera = a_angleToPlayerCamera; 105 | distanceToPlayer = util::GetDistanceBetween(RE::PlayerCharacter::GetSingleton(), ref); 106 | heightDifference = util::GetHeightDifferenceBetween(RE::PlayerCharacter::GetSingleton(), ref); 107 | } 108 | 109 | const RE::TESObjectREFR* ref; 110 | float angleToPlayerCamera; 111 | float distanceToPlayer = util::GetDistanceBetween(RE::PlayerCharacter::GetSingleton(), ref); 112 | float heightDifference = util::GetHeightDifferenceBetween(RE::PlayerCharacter::GetSingleton(), ref); 113 | std::vector> data; 114 | }; -------------------------------------------------------------------------------- /include/NND_API.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #undef GetModuleHandle 5 | 6 | /* 7 | * For modders: Copy this file into your own project if you wish to use this API 8 | */ 9 | namespace NND_API 10 | { 11 | constexpr auto NNDPluginName = "NPCsNamesDistributor"; 12 | 13 | // Available NND interface versions 14 | enum class InterfaceVersion : uint8_t 15 | { 16 | kV1 17 | }; 18 | 19 | enum class NameContext : uint8_t 20 | { 21 | kCrosshair = 1, 22 | kCrosshairMinion, 23 | 24 | kSubtitles, 25 | kDialogue, 26 | 27 | kInventory, 28 | 29 | kBarter, 30 | 31 | kEnemyHUD, 32 | 33 | kOther 34 | }; 35 | 36 | // NND's modder interface 37 | class IVNND1 38 | { 39 | public: 40 | 41 | /// 42 | /// Retrieves a generated name for given actor appropriate in specified context. 43 | /// Note that NND might not have a name for the actor. In this case an empty string will be returned. 44 | /// 45 | /// Actor for which the name should be retrieved. 46 | /// Context in which the name needs to be displayed. Depending on context name might either shortened or formatted differently. 47 | /// A name generated for the actor. If actor does not support generated names an empty string will be returned instead. 48 | virtual std::string_view GetName(RE::ActorHandle actor, NameContext context) noexcept = 0; 49 | 50 | /// 51 | /// Retrieves a generated name for given actor appropriate in specified context. 52 | /// Note that NND might not have a name for the actor. In this case an empty string will be returned. 53 | /// 54 | /// Actor for which the name should be retrieved. 55 | /// Context in which the name needs to be displayed. Depending on context name might either shortened or formatted differently. 56 | /// A name generated for the actor. If actor does not support generated names an empty string will be returned instead. 57 | virtual std::string_view GetName(const RE::Actor* actor, NameContext context) noexcept = 0; 58 | 59 | /// 60 | /// Reveals a real name of the given actor to the player. If player already knows actor's name this method does nothing. 61 | /// This method can be used to programatically introduce an actor to the player. 62 | /// 63 | /// Actor whose name should be revealed. 64 | virtual void RevealName(RE::ActorHandle actor) noexcept = 0; 65 | 66 | /// 67 | /// Reveals a real name of the given actor to the player. If player already knows actor's name this method does nothing. 68 | /// This method can be used to programatically introduce an actor to the player. 69 | /// 70 | /// Actor whose name should be revealed. 71 | virtual void RevealName(RE::Actor* actor) noexcept = 0; 72 | }; 73 | 74 | typedef void* (*_RequestPluginAPI)(const InterfaceVersion interfaceVersion); 75 | 76 | /// 77 | /// Request the NND API interface. 78 | /// Recommended: Send your request during or after SKSEMessagingInterface::kMessage_PostLoad to make sure the dll has already been loaded 79 | /// 80 | /// The interface version to request 81 | /// The pointer to the API singleton, or nullptr if request failed 82 | [[nodiscard]] inline void* RequestPluginAPI(const InterfaceVersion a_interfaceVersion = InterfaceVersion::kV1) 83 | { 84 | const auto pluginHandle = SKSE::WinAPI::GetModuleHandle("NPCsNamesDistributor.dll"); 85 | 86 | if (const _RequestPluginAPI requestAPIFunction = reinterpret_cast<_RequestPluginAPI>(GetProcAddress(pluginHandle, "RequestPluginAPI"))) { 87 | return requestAPIFunction(a_interfaceVersion); 88 | } 89 | return nullptr; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /source/RE/T/TESQuest.cpp: -------------------------------------------------------------------------------- 1 | #include "RE/T/TESQuest.h" 2 | 3 | #include "RE/B/BGSStoryTeller.h" 4 | #include "SKSE/Logger.h" 5 | 6 | namespace RE 7 | { 8 | TESQuestStage::operator bool() const 9 | { 10 | return *reinterpret_cast(this) != 0; 11 | } 12 | 13 | ObjectRefHandle& TESQuest::CreateRefHandleByAliasID(ObjectRefHandle& a_handle, std::uint32_t a_aliasID) 14 | { 15 | using func_t = decltype(&TESQuest::CreateRefHandleByAliasID); 16 | REL::Relocation func{ RELOCATION_ID(24537, 25066) }; 17 | return func(this, a_handle, a_aliasID); 18 | } 19 | 20 | BSString TESQuest::GetCurrentDescriptionWithReplacedTags() const 21 | { 22 | using func_t = void (RE::TESQuest::*)(RE::BSString&, std::uint32_t) const; 23 | REL::Relocation func{ RELOCATION_ID(24549, 25078) }; 24 | 25 | BSString retVal; 26 | func(this, retVal, currentInstanceID); 27 | return retVal; 28 | } 29 | 30 | bool TESQuest::EnsureQuestStarted(bool& a_result, bool a_startNow) 31 | { 32 | using func_t = decltype(&TESQuest::EnsureQuestStarted); 33 | REL::Relocation func{ Offset::TESQuest::EnsureQuestStarted }; 34 | return func(this, a_result, a_startNow); 35 | } 36 | 37 | std::uint16_t TESQuest::GetCurrentStageID() const 38 | { 39 | return currentStage; 40 | } 41 | 42 | bool TESQuest::IsActive() const 43 | { 44 | return data.flags.all(QuestFlag::kActive); 45 | } 46 | 47 | bool TESQuest::IsCompleted() const 48 | { 49 | return data.flags.all(QuestFlag::kCompleted); 50 | } 51 | 52 | bool TESQuest::IsEnabled() const 53 | { 54 | return data.flags.all(QuestFlag::kEnabled); 55 | } 56 | 57 | bool TESQuest::IsRunning() const 58 | { 59 | return !IsStopping() && !promoteTask; 60 | } 61 | 62 | bool TESQuest::IsStarting() const 63 | { 64 | return IsEnabled() && (data.flags == QuestFlag::kStopStart || promoteTask); 65 | } 66 | 67 | bool TESQuest::IsStopped() const 68 | { 69 | return data.flags.none(QuestFlag::kEnabled, QuestFlag::kStageWait); 70 | } 71 | 72 | bool TESQuest::IsStopping() const 73 | { 74 | return !IsEnabled() && data.flags == QuestFlag::kStopStart; 75 | } 76 | 77 | void TESQuest::Reset() 78 | { 79 | using func_t = decltype(&TESQuest::Reset); 80 | REL::Relocation func{ Offset::TESQuest::ResetQuest }; 81 | return func(this); 82 | } 83 | 84 | void TESQuest::ResetAndUpdate() 85 | { 86 | Reset(); 87 | 88 | auto enabled = IsEnabled(); 89 | if (enabled != StartsEnabled()) { 90 | auto storyTeller = BGSStoryTeller::GetSingleton(); 91 | if (storyTeller) { 92 | if (enabled) { 93 | storyTeller->BeginStartUpQuest(this); 94 | } else { 95 | storyTeller->BeginShutDownQuest(this); 96 | } 97 | } 98 | } 99 | } 100 | 101 | void TESQuest::SetEnabled(bool a_set) 102 | { 103 | if (a_set) { 104 | data.flags.set(QuestFlag::kEnabled); 105 | } else { 106 | data.flags.reset(QuestFlag::kEnabled); 107 | } 108 | AddChange(ChangeFlags::kQuestFlags); 109 | } 110 | 111 | bool TESQuest::Start() 112 | { 113 | if (eventID != QuestEvent::kNone) { 114 | SKSE::log::debug("Attempting to start event scoped quest outside of story manager"); 115 | return false; 116 | } 117 | 118 | bool result; 119 | return EnsureQuestStarted(result, true); 120 | } 121 | 122 | bool TESQuest::StartsEnabled() const 123 | { 124 | return data.flags.all(QuestFlag::kStartsEnabled); 125 | } 126 | 127 | void TESQuest::Stop() 128 | { 129 | if (IsEnabled()) { 130 | SetEnabled(false); 131 | } 132 | } 133 | 134 | void ReplaceTagsInQuestText(BSString* a_text, const TESQuest* a_quest, std::uint32_t a_questInstanceId) 135 | { 136 | using func_t = decltype(ReplaceTagsInQuestText); 137 | REL::Relocation func{ RELOCATION_ID(23429, 23897) }; 138 | 139 | func(a_text, a_quest, a_questInstanceId); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /swf/QuestItem.as: -------------------------------------------------------------------------------- 1 | 2 | class QuestItem extends MovieClip 3 | { 4 | // Instances 5 | var Title:MovieClip; 6 | var ObjectiveItemList:Array; 7 | 8 | // References 9 | private var TitleTextField:TextField; 10 | 11 | // Variables 12 | public var isBeingShown:Boolean; 13 | public var ageIndex:Number; 14 | public var mainQuestFrame:Number; 15 | public var magesGuildQuestFrame:Number; 16 | public var thievesGuildQuestFrame:Number; 17 | public var darkBrotherhoodQuestFrame:Number; 18 | public var companionQuestFrame:Number; 19 | public var miscQuestFrame:Number; 20 | public var daedricQuestFrame:Number; 21 | public var favorQuestFrame:Number; 22 | public var civilWarQuestFrame:Number; 23 | public var dlc01QuestFrame:Number; 24 | public var dlc02QuestFrame:Number; 25 | private var bracketOpenLongestNameFrame:Number; 26 | 27 | public function QuestItem() 28 | { 29 | ObjectiveItemList = new Array(); 30 | 31 | TitleTextField = Title.TitleTextField; 32 | TitleTextField.textAutoSize = "shrink"; 33 | 34 | Title.EndPiece.gotoAndStop("Main"); 35 | mainQuestFrame = Title.EndPiece._currentframe; 36 | 37 | Title.EndPiece.gotoAndStop("MagesGuild"); 38 | magesGuildQuestFrame = Title.EndPiece._currentframe; 39 | 40 | Title.EndPiece.gotoAndStop("ThievesGuild"); 41 | thievesGuildQuestFrame = Title.EndPiece._currentframe; 42 | 43 | Title.EndPiece.gotoAndStop("DarkBrotherhood"); 44 | darkBrotherhoodQuestFrame = Title.EndPiece._currentframe; 45 | 46 | Title.EndPiece.gotoAndStop("Companion"); 47 | companionQuestFrame = Title.EndPiece._currentframe; 48 | 49 | Title.EndPiece.gotoAndStop("Misc"); 50 | miscQuestFrame = Title.EndPiece._currentframe; 51 | 52 | Title.EndPiece.gotoAndStop("Daedric"); 53 | daedricQuestFrame = Title.EndPiece._currentframe; 54 | 55 | Title.EndPiece.gotoAndStop("Favor"); 56 | favorQuestFrame = Title.EndPiece._currentframe; 57 | 58 | Title.EndPiece.gotoAndStop("CivilWar"); 59 | civilWarQuestFrame = Title.EndPiece._currentframe; 60 | 61 | Title.EndPiece.gotoAndStop("DLC01"); 62 | dlc01QuestFrame = Title.EndPiece._currentframe; 63 | 64 | Title.EndPiece.gotoAndStop("DLC02"); 65 | dlc02QuestFrame = Title.EndPiece._currentframe; 66 | 67 | Title.Bracket.gotoAndStop("longest name"); 68 | bracketOpenLongestNameFrame = Title.Bracket._currentframe; 69 | } 70 | 71 | public function SetQuestInfo(a_type:Number, a_title:String, a_isInSameLocation:Boolean, a_objectives:Array, a_ageIndex:Number):Void 72 | { 73 | // Set end piece art 74 | Title.EndPiece.gotoAndStop(a_type); 75 | 76 | // Set quest title as in the journal 77 | TitleTextField.text = a_title.toUpperCase(); 78 | 79 | // Make room for the title 80 | var bracketOpenFrame:Number = Math.min(bracketOpenLongestNameFrame, Math.ceil(TitleTextField.textWidth * bracketOpenLongestNameFrame / TitleTextField._width)); 81 | Title.Bracket.gotoAndStop(bracketOpenFrame); 82 | 83 | var yOffset = Title.Bracket._y + Title.Bracket._height; 84 | for (var i:Number = 0; i < a_objectives.length; i++) 85 | { 86 | var objectiveItem:MovieClip = attachMovie("ObjectiveItem", "objective" + i, getNextHighestDepth(), { _x:Title._x, _y: yOffset }); 87 | 88 | if (a_isInSameLocation) 89 | { 90 | objectiveItem.Objective.gotoAndStop("NormalSelected"); 91 | } 92 | objectiveItem.Objective.textField.text = a_objectives[i]; 93 | 94 | ObjectiveItemList.push(objectiveItem); 95 | 96 | yOffset += 1.1 * objectiveItem._height; 97 | } 98 | 99 | ageIndex = a_ageIndex; 100 | } 101 | 102 | public function SetSide(a_side:String):Void 103 | { 104 | Title.EndPiece.SideArt.gotoAndStop(a_side); 105 | } 106 | 107 | public function Show():Void 108 | { 109 | gotoAndPlay("FadeIn"); 110 | 111 | for (var i:Number = 0; i < ObjectiveItemList.length; i++) 112 | { 113 | ObjectiveItemList[i].gotoAndPlay("FadeIn"); 114 | } 115 | } 116 | 117 | public function Remove():Void 118 | { 119 | for (var i:Number = 0; i < ObjectiveItemList.length; i++) 120 | { 121 | ObjectiveItemList[i].gotoAndPlay("FadeOut"); 122 | } 123 | 124 | gotoAndPlay("FadeOut"); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /source/RE/N/NiPoint3.cpp: -------------------------------------------------------------------------------- 1 | #include "RE/N/NiPoint3.h" 2 | 3 | #include 4 | 5 | namespace RE 6 | { 7 | float& NiPoint3::operator[](std::size_t a_idx) 8 | { 9 | assert(a_idx < 3); 10 | return std::addressof(x)[a_idx]; 11 | } 12 | 13 | const float& NiPoint3::operator[](std::size_t a_idx) const 14 | { 15 | assert(a_idx < 3); 16 | return std::addressof(x)[a_idx]; 17 | } 18 | 19 | bool NiPoint3::operator==(const NiPoint3& a_rhs) const 20 | { 21 | return (x == a_rhs.x && y == a_rhs.y && z == a_rhs.z); 22 | } 23 | 24 | bool NiPoint3::operator!=(const NiPoint3& a_rhs) const 25 | { 26 | return !operator==(a_rhs); 27 | } 28 | 29 | NiPoint3 NiPoint3::operator+(const NiPoint3& a_rhs) const 30 | { 31 | return NiPoint3(x + a_rhs.x, y + a_rhs.y, z + a_rhs.z); 32 | } 33 | 34 | NiPoint3 NiPoint3::operator-(const NiPoint3& a_rhs) const 35 | { 36 | return NiPoint3(x - a_rhs.x, y - a_rhs.y, z - a_rhs.z); 37 | } 38 | 39 | float NiPoint3::operator*(const NiPoint3& a_rhs) const 40 | { 41 | return x * a_rhs.x + y * a_rhs.y + z * a_rhs.z; 42 | } 43 | 44 | NiPoint3 NiPoint3::operator*(float a_scalar) const 45 | { 46 | return NiPoint3(x * a_scalar, y * a_scalar, z * a_scalar); 47 | } 48 | 49 | NiPoint3 NiPoint3::operator/(float a_scalar) const 50 | { 51 | return operator*(1.0F / a_scalar); 52 | } 53 | 54 | NiPoint3 NiPoint3::operator-() const 55 | { 56 | return NiPoint3(-x, -y, -z); 57 | } 58 | 59 | NiPoint3& NiPoint3::operator+=(const NiPoint3& a_rhs) 60 | { 61 | x += a_rhs.x; 62 | y += a_rhs.y; 63 | z += a_rhs.z; 64 | return *this; 65 | } 66 | 67 | NiPoint3& NiPoint3::operator-=(const NiPoint3& a_rhs) 68 | { 69 | x -= a_rhs.x; 70 | y -= a_rhs.y; 71 | z -= a_rhs.z; 72 | return *this; 73 | } 74 | 75 | NiPoint3& NiPoint3::operator*=(const NiPoint3& a_rhs) 76 | { 77 | x *= a_rhs.x; 78 | y *= a_rhs.y; 79 | z *= a_rhs.z; 80 | return *this; 81 | } 82 | 83 | NiPoint3& NiPoint3::operator/=(const NiPoint3& a_rhs) 84 | { 85 | x /= a_rhs.x; 86 | y /= a_rhs.y; 87 | z /= a_rhs.z; 88 | return *this; 89 | } 90 | 91 | NiPoint3& NiPoint3::operator*=(float a_scalar) 92 | { 93 | x *= a_scalar; 94 | y *= a_scalar; 95 | z *= a_scalar; 96 | return *this; 97 | } 98 | 99 | NiPoint3& NiPoint3::operator/=(float a_scalar) 100 | { 101 | return operator*=(1.0F / a_scalar); 102 | } 103 | 104 | NiPoint3 NiPoint3::Cross(const NiPoint3& a_pt) const 105 | { 106 | return NiPoint3( 107 | y * a_pt.z - z * a_pt.y, 108 | z * a_pt.x - x * a_pt.z, 109 | x * a_pt.y - y * a_pt.x); 110 | } 111 | 112 | float NiPoint3::Dot(const NiPoint3& a_pt) const 113 | { 114 | return x * a_pt.x + y * a_pt.y + z * a_pt.z; 115 | } 116 | 117 | float NiPoint3::GetDistance(const NiPoint3& a_pt) const noexcept 118 | { 119 | return std::sqrtf(GetSquaredDistance(a_pt)); 120 | } 121 | 122 | float NiPoint3::GetSquaredDistance(const NiPoint3& a_pt) const noexcept 123 | { 124 | const float dx = a_pt.x - x; 125 | const float dy = a_pt.y - y; 126 | const float dz = a_pt.z - z; 127 | return dx * dx + dy * dy + dz * dz; 128 | } 129 | 130 | float NiPoint3::Length() const 131 | { 132 | return std::sqrtf(x * x + y * y + z * z); 133 | } 134 | 135 | float NiPoint3::SqrLength() const 136 | { 137 | return x * x + y * y + z * z; 138 | } 139 | 140 | NiPoint3 NiPoint3::UnitCross(const NiPoint3& a_pt) const 141 | { 142 | auto cross = Cross(a_pt); 143 | cross.Unitize(); 144 | return cross; 145 | } 146 | 147 | float NiPoint3::Unitize() 148 | { 149 | auto length = Length(); 150 | if (length == 1.f) { 151 | return length; 152 | } else if (length > FLT_EPSILON) { 153 | operator/=(length); 154 | } else { 155 | x = 0.0; 156 | y = 0.0; 157 | z = 0.0; 158 | length = 0.0; 159 | } 160 | return length; 161 | } 162 | 163 | float NiPoint3::GetHorizontalAngleTo(const NiPoint3& a_pt) const 164 | { 165 | NiPoint3 diff{ a_pt.x - x, a_pt.y - y, a_pt.z - z }; 166 | 167 | float angle; 168 | if (diff.y) { 169 | angle = atanf(diff.x / diff.y); 170 | if (diff.y < 0.0F) { 171 | angle += std::numbers::pi_v; 172 | } 173 | } else { 174 | if (diff.x <= 0.0F) { 175 | angle = 3 * std::numbers::pi_v / 2; 176 | } else { 177 | angle = std::numbers::pi_v / 2; 178 | } 179 | } 180 | 181 | return angle; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /swf/QuestItemList.as: -------------------------------------------------------------------------------- 1 | var questItem:QuestItem; 2 | var entries:Array; 3 | 4 | var All:Boolean; 5 | var Favor:Boolean; 6 | var DialogueMode:Boolean; 7 | var StealthMode:Boolean; 8 | var Swimming:Boolean; 9 | var HorseMode:Boolean; 10 | var WarHorseMode:Boolean; 11 | 12 | var positionY0:Number; 13 | var maxHeight:Number; 14 | 15 | var SCALE:Number = 65; 16 | 17 | function QuestItemList(a_positionX:Number, a_positionY:Number, a_maxHeight:Number):Void 18 | { 19 | entries = new Array(); 20 | 21 | positionX0 = Stage.width * a_positionX; 22 | positionY0 = Stage.height * a_positionY; 23 | 24 | var point:Object = { x:positionX0, y:positionY0 }; 25 | globalToLocal(point); 26 | _x = point.x; 27 | _y = point.y; 28 | 29 | maxHeight = Stage.height * a_maxHeight; 30 | 31 | All = true; 32 | Favor = true; 33 | DialogueMode = true; 34 | StealthMode = true; 35 | Swimming = true; 36 | HorseMode = true; 37 | WarHorseMode = true; 38 | } 39 | 40 | function AddToHudElements():Void 41 | { 42 | _level0.HUDMovieBaseInstance.HudElements.push(this); 43 | } 44 | 45 | function AddQuest(a_type:Number, a_title:String, a_isInSameLocation:Boolean, a_objectives:Array, a_ageIndex:Number):Void 46 | { 47 | questItem = attachMovie("QuestItem", "questItem", getNextHighestDepth(), { _xscale:SCALE, _yscale:SCALE }); 48 | 49 | entries.push(questItem); 50 | 51 | questItem.SetQuestInfo(a_type, a_title, a_isInSameLocation, a_objectives, a_ageIndex); 52 | questItem.gotoAndStop("IdleHide"); 53 | } 54 | 55 | function SetQuestSide(a_side:String):Void 56 | { 57 | questItem.SetSide(a_side); 58 | } 59 | 60 | function Update():Void 61 | { 62 | // iHUD show/hide compatibility 63 | if (_root.HUDMovieBaseInstance.CompassShoutMeterHolder.Compass.DirectionRect._alpha && 64 | // Toggle Compass Hotkey show/hide compatibility 65 | _root.HUDMovieBaseInstance.CompassShoutMeterHolder._alpha 66 | ) 67 | { 68 | if (entries.length > 1) 69 | { 70 | entries.sort(ByAgeThenMiscellaneousQuests); 71 | 72 | var yOffset = 0; 73 | for (var i:Number = 0; i < entries.length; i++) 74 | { 75 | questItem = entries[i]; 76 | 77 | questItem._y = yOffset; 78 | 79 | var point:Object = { x:0, y:0 }; 80 | questItem.localToGlobal(point); 81 | 82 | if (point.y >= (positionY0 + maxHeight)) 83 | { 84 | questItem._visible = false; 85 | } 86 | else if (questItem.ObjectiveItemList.length > 1) 87 | { 88 | for (var j:Number = 1; j < questItem.ObjectiveItemList.length; j++) 89 | { 90 | var objectiveItem:MovieClip = questItem.ObjectiveItemList[j]; 91 | 92 | var point:Object = { x:0, y:0 }; 93 | objectiveItem.localToGlobal(point); 94 | 95 | if (point.y >= (positionY0 + maxHeight)) 96 | { 97 | objectiveItem._alpha = 0.0; 98 | } 99 | } 100 | } 101 | 102 | yOffset += questItem._height + 5; 103 | } 104 | } 105 | 106 | _alpha = 100; 107 | } 108 | else 109 | { 110 | _alpha = 0; 111 | } 112 | } 113 | 114 | function ShowQuest():Void 115 | { 116 | questItem.Show(); 117 | } 118 | 119 | function RemoveQuest():Void 120 | { 121 | questItem.Remove(); 122 | } 123 | 124 | function ShowAllQuests():Void 125 | { 126 | for (var i:Number = 0; i < entries.length; i++) 127 | { 128 | questItem = entries[i]; 129 | 130 | if (!questItem.isBeingShown) 131 | { 132 | questItem.Show(); 133 | } 134 | } 135 | } 136 | 137 | function RemoveAllQuests():Void 138 | { 139 | for (var i:Number = 0; i < entries.length; i++) 140 | { 141 | questItem = entries[i]; 142 | if (!questItem.isBeingShown) 143 | { 144 | questItem._alpha = 0; 145 | } 146 | questItem.Remove(); 147 | } 148 | 149 | entries.splice(0, entries.length); 150 | } 151 | 152 | function ByAgeThenMiscellaneousQuests(a_questItem1:QuestItem, a_questItem2:QuestItem):Number 153 | { 154 | if (a_questItem1.Title.EndPiece._currentframe != a_questItem1.miscQuestFrame && 155 | a_questItem2.Title.EndPiece._currentframe == a_questItem2.miscQuestFrame) 156 | { 157 | return -1; 158 | } 159 | else if (a_questItem1.Title.EndPiece._currentframe == a_questItem1.miscQuestFrame && 160 | a_questItem2.Title.EndPiece._currentframe != a_questItem2.miscQuestFrame) 161 | { 162 | return 1; 163 | } 164 | else if (a_questItem1.ageIndex > a_questItem2.ageIndex) 165 | { 166 | return -1; 167 | } 168 | else if (a_questItem1.ageIndex < a_questItem2.ageIndex) 169 | { 170 | return 1; 171 | } 172 | 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /include/RE/G/GFxMovieDefImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GAtomic.h" 4 | #include "RE/G/GFxLoadUpdateSync.h" 5 | #include "RE/G/GFxMovieDef.h" 6 | #include "RE/G/GFxMovieDefBindStates.h" 7 | #include "RE/G/GFxResource.h" 8 | #include "RE/G/GFxResourceKey.h" 9 | #include "RE/G/GFxResourceLib.h" 10 | #include "RE/G/GFxStateBagImpl.h" 11 | #include "RE/G/GPtr.h" 12 | #include "RE/G/GRefCountBase.h" 13 | #include "RE/G/GStats.h" 14 | 15 | namespace RE 16 | { 17 | class GFxMovieDataDef; 18 | class GFxMovieDefImpl; 19 | 20 | struct GFxResourceBinding; 21 | 22 | struct GFxResourceBindData 23 | { 24 | GPtr resource; // 00 25 | GFxResourceBinding* binding; // 08 26 | }; 27 | 28 | struct GFxResourceBinding 29 | { 30 | GMemoryHeap* heap; // 00 31 | volatile std::uint32_t resourceCount; // 08 32 | std::uint32_t pad0C; // 0C 33 | GFxResourceBindData* volatile resources; // 10 34 | GLock resourceLock; // 18 35 | volatile bool frozen; // 40 36 | std::uint8_t pad41; // 41 37 | std::uint16_t pad42; // 42 38 | std::uint32_t pad44; // 44 39 | GFxMovieDefImpl* movieDef; // 48 40 | }; 41 | static_assert(sizeof(GFxResourceBinding) == 0x50); 42 | 43 | class GFxMovieDefImpl : public GFxMovieDef 44 | { 45 | public: 46 | 47 | enum BindStateType 48 | { 49 | kNotStarted = 0, 50 | kInProgress = 1, 51 | kFinished = 2, 52 | kCanceled = 3, // Canceled due to a user request. 53 | kError = 4, 54 | // Mask for above states. 55 | kStateMask = 0xF, 56 | 57 | // These bits store the status of what was 58 | // actually loaded; we can wait based on them. 59 | kFrame1Loaded = 0x100, 60 | kLastFrameLoaded = 0x200, 61 | }; 62 | 63 | class BindTaskData : public GRefCountBase 64 | { 65 | public: 66 | virtual ~BindTaskData(); // 00 67 | 68 | // members 69 | GMemoryHeap* heap; // 10 70 | GPtr dataDef; // 18 71 | GFxMovieDefImpl* defImplUnsafe; // 20 72 | std::uint32_t loadFlags; // 28 73 | std::uint32_t pad2C; // 2C 74 | GFxResourceBinding resourceBinding; // 30 75 | GArrayLH importSourceMovies; // 80 76 | GLock importSourceLock; // 98 77 | GArrayLH, GFxStatMovieData::kGFxStatMD_Other_Mem> resourceImports; // C0 78 | std::uint32_t bindState; // D8 79 | std::uint32_t padDC; // DC 80 | GPtr bindUpdate; // E0 81 | std::uint32_t bindingFrame; // E8 82 | std::uint32_t bytesLoaded; // EC 83 | bool bindingCancelled; // F0 84 | std::uint8_t padF1; // F1 85 | std::uint16_t padF2; // F2 86 | std::uint32_t padF4; // F4 87 | }; 88 | static_assert(sizeof(BindTaskData) == 0xF8); 89 | static_assert(sizeof(GArrayLH, GFxStatMovieData::kGFxStatMD_Other_Mem>) == 0x18); 90 | 91 | virtual ~GFxMovieDefImpl(); // 00 92 | 93 | // add 94 | virtual GFxResource* GetFont(const char* a_name, std::uint32_t a_fontFlags, std::int32_t& a_arg3); // 1C 95 | 96 | // members 97 | GPtr stateBag; // 20 98 | GPtr loaderImpl; // 28 99 | GPtr bindStates; // 30 100 | GPtr bindData; // 38 101 | }; 102 | static_assert(sizeof(GFxMovieDefImpl) == 0x40); 103 | } 104 | -------------------------------------------------------------------------------- /include/RE/G/GASObjectInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GASString.h" 4 | 5 | namespace RE 6 | { 7 | class GASObject; 8 | class GASValue; 9 | class GASMember; 10 | class GASPropFlags; 11 | class GASFunctionRef; 12 | class GASFunctionObject; 13 | class GASEnvironment; 14 | 15 | class GASObjectInterface 16 | { 17 | public: 18 | 19 | enum ObjectType : std::uint8_t 20 | { 21 | kUnknown, 22 | 23 | // This type is for non-scriptable characters; it is not ObjectInterface. 24 | kBaseCharacter, 25 | 26 | // These need to be grouped in range for IsASCharacter(). 27 | kSprite, 28 | kButton, 29 | kTextField, 30 | kVideo, 31 | 32 | kASObject, 33 | kArray, 34 | kString, 35 | kNumber, 36 | kBoolean, 37 | kMovieClipObject, 38 | kButtonASObject, 39 | kTextFieldASObject, 40 | kVideoASObject, 41 | kMatrix, 42 | kPoint, 43 | kRectangle, 44 | kColorTransform, 45 | kCapabilities, 46 | kTransform, 47 | kColor, 48 | kKey, 49 | kFunction, 50 | kStage, 51 | kMovieClipLoader, 52 | kBitmapData, 53 | kLoadVars, 54 | kXML, 55 | kXMLNode, 56 | kTextFormat, 57 | kStyleSheet, 58 | kSound, 59 | kNetConnection, 60 | kNetStream, 61 | kDate, 62 | kAsBroadcaster, 63 | kBitmapFilter, 64 | kDropShadowFilter, 65 | kGlowFilter, 66 | kBlurFilter, 67 | kBevelFilter, 68 | kColorMatrixFilter, 69 | kTextSnapshot, 70 | kSharedObject 71 | }; 72 | 73 | struct MemberVisitor 74 | { 75 | virtual ~MemberVisitor() {} 76 | 77 | virtual void Visit(const GASString& name, const GASValue& val, std::uint8_t flags) = 0; 78 | }; 79 | 80 | struct UserDataHolder; 81 | 82 | virtual ~GASObjectInterface(); // 00 83 | 84 | // add 85 | virtual char const* GetTextValue(GASEnvironment*) const; // 01 86 | virtual ObjectType GetObjectType2() const; // 02 87 | virtual bool SetMember(GASEnvironment*, GASString const&, GASValue const&, GASPropFlags const&); // 03 88 | virtual bool GetMember(GASEnvironment*, const GASString&, GASValue*) = 0; // 04 89 | virtual bool FindMember(GASStringContext*, const GASString&, GASMember*) = 0; // 05 90 | virtual bool DeleteMember(GASStringContext*, const GASString&) = 0; // 06 91 | virtual bool SetMemberFlags(GASStringContext*, const GASString&, std::uint8_t) = 0; // 07 92 | virtual void VisitMembers(GASStringContext*, MemberVisitor*, std::uint32_t, const GASObjectInterface*) const = 0; // 08 93 | virtual bool HasMember(GASStringContext*, const GASString&, bool) = 0; // 09 94 | virtual bool SetMemberRaw(GASStringContext*, const GASString&, const GASValue&, const GASPropFlags&) = 0; // 0A 95 | virtual bool GetMemberRaw(GASStringContext*, const GASString&, GASValue*) = 0; // 0B 96 | virtual GASFunctionRef ToFunction(); // 0C 97 | virtual void Set__proto__(GASStringContext*, GASObject*) = 0; // 0D 98 | virtual GASFunctionRef Get__constructor__(GASStringContext*); // 0E 99 | virtual bool IsSuper() const; // 0F 100 | virtual bool IsBuiltinPrototype() const; // 10 101 | virtual void AddInterface(GASStringContext*, int, GASFunctionObject*); // 11 102 | virtual bool InstanceOf(GASEnvironment*, const GASObject*, bool) const; // 12 103 | virtual bool Watch(GASStringContext*, const GASString&, const GASFunctionRef&, const GASValue&); // 13 104 | virtual bool Unwatch(GASStringContext*, const GASString&); // 14 105 | 106 | // members 107 | UserDataHolder* userDataHolder; // 08 108 | GASObject* proto; // 10 109 | }; 110 | static_assert(sizeof(GASObjectInterface) == 0x18); 111 | 112 | } -------------------------------------------------------------------------------- /source/Settings.cpp: -------------------------------------------------------------------------------- 1 | #include "Settings.h" 2 | 3 | #include "utils/INISettingCollection.h" 4 | 5 | namespace settings 6 | { 7 | using namespace utils; 8 | 9 | void Init(const std::string& a_iniFileName) 10 | { 11 | INISettingCollection* iniSettingCollection = INISettingCollection::GetSingleton(); 12 | 13 | { 14 | using namespace debug; 15 | iniSettingCollection->AddSettings 16 | ( 17 | MakeSetting("uLogLevel:Debug", static_cast(logLevel)) 18 | ); 19 | } 20 | { 21 | using namespace display; 22 | iniSettingCollection->AddSettings 23 | ( 24 | MakeSetting("bUseMetricUnits:Display", useMetricUnits), 25 | MakeSetting("bShowUndiscoveredLocationMarkers:Display", showUndiscoveredLocationMarkers), 26 | MakeSetting("bUndiscoveredMeansUnknownMarkers:Display", undiscoveredMeansUnknownMarkers), 27 | MakeSetting("bUndiscoveredMeansUnknownInfo:Display", undiscoveredMeansUnknownInfo), 28 | MakeSetting("bShowEnemyMarkers:Display", showEnemyMarkers), 29 | MakeSetting("bShowEnemyNameUnderMarker:Display", showEnemyNameUnderMarker), 30 | MakeSetting("bShowObjectiveAsTarget:Display", showObjectiveAsTarget), 31 | MakeSetting("bShowOtherObjectivesCount:Display", showOtherObjectivesCount), 32 | MakeSetting("bShowInteriorMarkers:Display", showInteriorMarkers), 33 | MakeSetting("fAngleToShowMarkerDetails:Display", angleToShowMarkerDetails), 34 | MakeSetting("fAngleToKeepMarkerDetailsShown:Display", angleToKeepMarkerDetailsShown), 35 | MakeSetting("fFocusingDelayToShow:Display", focusingDelayToShow) 36 | ); 37 | } 38 | { 39 | using namespace questlist; 40 | iniSettingCollection->AddSettings 41 | ( 42 | MakeSetting("fPositionX:QuestList", positionX), 43 | MakeSetting("fPositionY:QuestList", positionY), 44 | MakeSetting("fMaxHeight:QuestList", maxHeight), 45 | MakeSetting("bShowInExteriors:QuestList", showInExteriors), 46 | MakeSetting("bShowInInteriors:QuestList", showInInteriors), 47 | MakeSetting("fWalkingDelayToShow:QuestList", walkingDelayToShow), 48 | MakeSetting("fJoggingDelayToShow:QuestList", joggingDelayToShow), 49 | MakeSetting("fSprintingDelayToShow:QuestList", sprintingDelayToShow), 50 | MakeSetting("bHideInCombat:QuestList", hideInCombat) 51 | ); 52 | } 53 | 54 | if (!iniSettingCollection->ReadFromFile(a_iniFileName)) 55 | { 56 | logger::warn("Could not read {}, falling back to default options", a_iniFileName); 57 | } 58 | 59 | { 60 | using namespace debug; 61 | logLevel = static_cast(iniSettingCollection->GetSetting("uLogLevel:Debug")); 62 | } 63 | { 64 | using namespace display; 65 | useMetricUnits = iniSettingCollection->GetSetting("bUseMetricUnits:Display"); 66 | showUndiscoveredLocationMarkers = iniSettingCollection->GetSetting("bShowUndiscoveredLocationMarkers:Display"); 67 | undiscoveredMeansUnknownMarkers = iniSettingCollection->GetSetting("bUndiscoveredMeansUnknownMarkers:Display"); 68 | undiscoveredMeansUnknownInfo = iniSettingCollection->GetSetting("bUndiscoveredMeansUnknownInfo:Display"); 69 | showEnemyMarkers = iniSettingCollection->GetSetting("bShowEnemyMarkers:Display"); 70 | showEnemyNameUnderMarker = iniSettingCollection->GetSetting("bShowEnemyNameUnderMarker:Display"); 71 | showObjectiveAsTarget = iniSettingCollection->GetSetting("bShowObjectiveAsTarget:Display"); 72 | showOtherObjectivesCount = iniSettingCollection->GetSetting("bShowOtherObjectivesCount:Display"); 73 | showInteriorMarkers = iniSettingCollection->GetSetting("bShowInteriorMarkers:Display"); 74 | angleToShowMarkerDetails = iniSettingCollection->GetSetting("fAngleToShowMarkerDetails:Display"); 75 | angleToKeepMarkerDetailsShown = iniSettingCollection->GetSetting("fAngleToKeepMarkerDetailsShown:Display"); 76 | focusingDelayToShow = iniSettingCollection->GetSetting("fFocusingDelayToShow:Display"); 77 | } 78 | { 79 | using namespace questlist; 80 | positionX = iniSettingCollection->GetSetting("fPositionX:QuestList"); 81 | positionY = iniSettingCollection->GetSetting("fPositionY:QuestList"); 82 | maxHeight = iniSettingCollection->GetSetting("fMaxHeight:QuestList"); 83 | showInExteriors = iniSettingCollection->GetSetting("bShowInExteriors:QuestList"); 84 | showInInteriors = iniSettingCollection->GetSetting("bShowInInteriors:QuestList"); 85 | walkingDelayToShow = iniSettingCollection->GetSetting("fWalkingDelayToShow:QuestList"); 86 | joggingDelayToShow = iniSettingCollection->GetSetting("fJoggingDelayToShow:QuestList"); 87 | sprintingDelayToShow = iniSettingCollection->GetSetting("fSprintingDelayToShow:QuestList"); 88 | hideInCombat = iniSettingCollection->GetSetting("bHideInCombat:QuestList"); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /include/RE/G/GFxASCharacter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GASObjectInterface.h" 4 | #include "RE/G/GFxCharacter.h" 5 | 6 | namespace RE 7 | { 8 | class GASMovieClipObject; 9 | class GFxMovieDef; 10 | 11 | // InteractiveObject in Scaleform 4.1 12 | class GFxASCharacter : 13 | public GFxCharacter, // 000 14 | public GASObjectInterface // 098 15 | { 16 | public: 17 | virtual ~GFxASCharacter(); // 00 18 | 19 | // override (GFxCharacter) 20 | void UpdateAlphaFlag() override; // 01 21 | bool GetVisible() const override; // 04 22 | GRenderer::BlendType GetBlendMode() const override; // 05 23 | bool GetContinueAnimationFlag() const override; // 06 24 | bool GetAcceptAnimMoves() const override; // 07 25 | void SetAcceptAnimMoves(bool) override; // 08 26 | void SetBlendMode(GRenderer::BlendType) override; // 09 27 | void SetName(const GASString&) override; // 0A 28 | void SetOriginalName(const GASString&) override; // 0B 29 | void SetFilters(GArray) override; // 0C 30 | void OnEventUnload() override; // 22 31 | bool OnUnloading() override; // 23 32 | GASObjectInterface::ObjectType GetObjectType() const override; // 2C 33 | bool IsUsedAsMask() const override; // 2D 34 | void SetStateChangeFlags(std::uint8_t) override; // 2E 35 | std::uint8_t GetStateChangeFlags() const override; // 2F 36 | void OnRendererChanged() override; // 30 37 | 38 | // override (GASObjectInterface) 39 | GASObjectInterface::ObjectType GetObjectType2() const override; // 02 40 | bool SetMember(GASEnvironment*, GASString const&, GASValue const&, GASPropFlags const&) override; // 03 41 | bool GetMember(GASEnvironment*, const GASString&, GASValue*) override; // 04 42 | bool FindMember(GASStringContext*, const GASString&, GASMember*) override; // 05 43 | bool DeleteMember(GASStringContext*, const GASString&) override; // 06 44 | bool SetMemberFlags(GASStringContext*, const GASString&, std::uint8_t) override; // 07 45 | void VisitMembers(GASStringContext*, MemberVisitor*, std::uint32_t, const GASObjectInterface*) const override; // 08 46 | bool HasMember(GASStringContext*, const GASString&, bool) override; // 09 47 | bool SetMemberRaw(GASStringContext*, const GASString&, const GASValue&, const GASPropFlags&) override; // 0A 48 | bool GetMemberRaw(GASStringContext*, const GASString&, GASValue*) override; // 0B 49 | void Set__proto__(GASStringContext* a_stringContext, GASObject* a_object) override; // 0D 50 | bool InstanceOf(GASEnvironment*, const GASObject*, bool) const override; // 12 51 | bool Watch(GASStringContext*, const GASString&, const GASFunctionRef&, const GASValue&) override; // 13 52 | bool Unwatch(GASStringContext*, const GASString&) override; // 14 53 | 54 | // add 55 | virtual void Unk_31(void); // 31 56 | virtual void Unk_32(void); // 32 57 | virtual void Unk_33(void); // 33 58 | virtual void Unk_34(void); // 34 59 | virtual void Unk_35(void); // 35 - pure 60 | virtual void Unk_36(void); // 36 61 | virtual void Unk_37(void); // 37 62 | virtual void Unk_38(void); // 38 63 | virtual void Unk_39(void); // 39 64 | virtual void Unk_3A(void); // 3A 65 | virtual void Unk_3B(void); // 3B 66 | virtual void Unk_3C(void); // 3C 67 | virtual void Unk_3D(void); // 3D 68 | virtual void Unk_3E(void); // 3E 69 | virtual void Unk_3F(void); // 3F 70 | virtual void Unk_40(void); // 40 71 | virtual GASMovieClipObject* GetMovieClip(); // 41 - { return nullptr; } 72 | virtual void Unk_42(void); // 42 73 | virtual void Unk_43(void); // 43 74 | virtual void Unk_44(void); // 44 75 | virtual void Unk_45(void); // 45 76 | virtual void Unk_46(void); // 46 77 | virtual void Unk_47(void); // 47 78 | virtual void Unk_48(void); // 48 79 | virtual void Unk_49(void); // 49 80 | virtual void Unk_4A(void); // 4A 81 | virtual void Unk_4B(void); // 4B 82 | virtual void Unk_4C(void); // 4C 83 | virtual void Unk_4D(void); // 4D 84 | virtual void Unk_4E(void); // 4E 85 | virtual void Unk_4F(void); // 4F 86 | virtual void Unk_50(void); // 50 87 | virtual void Unk_51(void); // 51 88 | virtual void Unk_52(void); // 52 89 | virtual void Unk_53(void); // 53 90 | virtual void Unk_54(void); // 54 91 | virtual void Unk_55(void); // 55 92 | virtual void Unk_56(void); // 56 93 | virtual void Unk_57(void); // 57 94 | 95 | // members 96 | std::uint64_t unk0B0; // 0B0 97 | std::uint64_t unk0B8; // 0B8 98 | std::uint64_t unk0C0; // 0C0 99 | GFxMovieDef* movieDef; // 0C8 100 | std::uint64_t unk0D0; // 0D0 101 | std::uint64_t unk0D8; // 0D0 102 | std::uint64_t unk0E0; // 0D0 103 | std::uint64_t unk0E8; // 0D0 104 | std::uint64_t unk0F0; // 0D0 105 | std::uint64_t unk0F8; // 0D0 106 | std::uint64_t unk100; // 0D0 107 | std::uint64_t unk118; // 0D0 108 | }; 109 | static_assert(sizeof(GFxASCharacter) == 0x110); 110 | } 111 | -------------------------------------------------------------------------------- /include/IUI/API.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace RE 4 | { 5 | class GFxMovie; 6 | class GFxMovieDef; 7 | class GFxSpriteDef; 8 | class GFxValue; 9 | class IMenu; 10 | } 11 | 12 | namespace IUI::API 13 | { 14 | struct Message 15 | { 16 | enum Type : std::uint32_t 17 | { 18 | kStartLoadInstances, 19 | kPreReplaceInstance, 20 | kPostPatchInstance, 21 | kAbortPatchInstance, 22 | kFinishLoadInstances, 23 | kPostInitExtensions 24 | }; 25 | 26 | RE::IMenu* menu; 27 | RE::GFxMovie* movie; 28 | }; 29 | 30 | struct StartLoadInstancesMessage : Message 31 | { 32 | static constexpr inline Type type = Type::kStartLoadInstances; 33 | }; 34 | 35 | struct PreReplaceInstanceMessage : Message 36 | { 37 | static constexpr inline Type type = Type::kPreReplaceInstance; 38 | 39 | RE::GFxValue& originalInstance; 40 | }; 41 | 42 | struct PostPatchInstanceMessage : Message 43 | { 44 | static constexpr inline Type type = Type::kPostPatchInstance; 45 | 46 | RE::GFxValue& newInstance; 47 | RE::GFxMovieDef* newInstanceMovieDef; 48 | RE::GFxSpriteDef* newInstanceSpriteDef; 49 | }; 50 | 51 | struct AbortPatchInstanceMessage : Message 52 | { 53 | static constexpr inline Type type = Type::kAbortPatchInstance; 54 | 55 | RE::GFxValue& originalValue; 56 | }; 57 | 58 | struct FinishLoadInstancesMessage : Message 59 | { 60 | static constexpr inline Type type = Type::kFinishLoadInstances; 61 | 62 | int loadedCount; 63 | }; 64 | 65 | struct PostInitExtensionsMessage : Message 66 | { 67 | static constexpr inline Type type = Type::kPostInitExtensions; 68 | }; 69 | 70 | template 71 | concept valid_message = std::is_base_of_v; 72 | 73 | template requires valid_message 74 | inline const MessageT* TranslateAs(SKSE::MessagingInterface::Message* a_msg) 75 | { 76 | if constexpr (std::is_same_v) 77 | { 78 | return static_cast(a_msg->data); 79 | } 80 | else 81 | { 82 | if (a_msg->type == MessageT::type && a_msg->dataLen == sizeof(MessageT)) 83 | { 84 | return static_cast(a_msg->data); 85 | } 86 | 87 | return nullptr; 88 | } 89 | } 90 | } 91 | 92 | /* API INSTRUCTIONS */ 93 | // 94 | // 95 | // 1. After calling `SKSE::Init' in `SKSEPlugin_Load', register an SKSE messages listener function. In this function, register a 96 | // Infinity UI messages listener after that plugin is loaded (upon receiving a post load message from SKSE). 97 | // If Infinity UI is not detected, registering the listener will fail on game launch. 98 | // 99 | // In `SKSEPlugin_Load': 100 | // 101 | // ... 102 | // if (!SKSE::GetMessagingInterface()->RegisterListener("SKSE", SKSEMessageListener)) 103 | // { 104 | // // ... failure handling 105 | // } 106 | // ... 107 | // 108 | // Also define the SKSE message listener function elsewhere: 109 | // 110 | // void SKSEMessageListener(SKSE::MessagingInterface::Message* a_msg) 111 | // { 112 | // // If all plugins have been loaded 113 | // if (a_msg->type == SKSE::MessagingInterface::kPostLoad) { 114 | // if (SKSE::GetMessagingInterface()->RegisterListener("InfinityUI", InfinityUIMessageListener)) { 115 | // // ... success handling 116 | // } else { 117 | // // ... failure handling 118 | // } 119 | // } 120 | // } 121 | // 122 | // 123 | // 2. Define the listener function for payload interpreter messages. The received `SKSE::MessagingInterface::Message' 124 | // will contain a `IUI::API::Message' in its "data" field. Depending on the SKSE message type, use `IUI::API::TranslateAs<>()' 125 | // to get the content of the message. 126 | // 127 | // void InfinityUIMessageListener(SKSE::MessagingInterface::Message* a_msg) 128 | // { 129 | // if (!a_msg || std::string_view(a_msg->sender) != "InfinityUI") { 130 | // return; 131 | // } 132 | // 133 | // // ... You can remove some of the cases in the switch below if you don't depend on them 134 | // switch (a_msg->type) 135 | // { 136 | // case IUI::API::Message::Type::kStartLoadInstances: 137 | // if (auto startLoadMsg = IUI::API::TranslateAs(a_msg)) { 138 | // // ... Infinity UI starts loading patches for a menu 139 | // } 140 | // break; 141 | // case IUI::API::Message::Type::kPreReplaceInstance: 142 | // if (auto preReplaceMsg = IUI::API::TranslateAs(a_msg)) { 143 | // // ... The message contains data about the original instance to be retrieved before being replaced 144 | // } 145 | // break; 146 | // case IUI::API::Message::Type::kPostPatchInstance: 147 | // if (auto postPatchMsg = IUI::API::TranslateAs(a_msg)) { 148 | // // ... The message contains data about the instance that is replacing the old one 149 | // } 150 | // break; 151 | // case IUI::API::Message::Type::kAbortPatchInstance: 152 | // if (auto abortPatchMsg = IUI::API::TranslateAs(a_msg)) { 153 | // // ... Infinity UI signals an abort message for you to take further actions. 154 | // // ... This happens when any element in the hierarchy to reach the instance to be replaced 155 | // // ... is not a movieclip. 156 | // } 157 | // break; 158 | // case IUI::API::Message::Type::kFinishLoadInstances: 159 | // if (auto finishLoadMsg = IUI::API::TranslateAs(a_msg)) { 160 | // // ... Infinity UI finishes loading patches for a menu 161 | // } 162 | // break; 163 | // case IUI::API::Message::Type::kPostInitExtensions: 164 | // if (auto postInitExtMsg = IUI::API::TranslateAs(a_msg)) { 165 | // // ... Some menus init extensions after loading the SWF to finish their setup. 166 | // // ... You may want to make some additional configurations before the menu starts running. 167 | // } 168 | // break; 169 | // } 170 | // } -------------------------------------------------------------------------------- /source/MessageListeners.cpp: -------------------------------------------------------------------------------- 1 | #include "Settings.h" 2 | 3 | #include "IUI/API.h" 4 | #include "NPCNameProvider.h" 5 | 6 | #include "Compass.h" 7 | #include "QuestItemList.h" 8 | #include "Test.h" 9 | 10 | #include "IUI/GFxLoggers.h" 11 | 12 | #include "Hooks.h" 13 | 14 | #undef GetModuleHandle 15 | 16 | const SKSE::LoadInterface* skse; 17 | 18 | void InfinityUIMessageListener(SKSE::MessagingInterface::Message* a_msg); 19 | 20 | void SKSEMessageListener(SKSE::MessagingInterface::Message* a_msg) 21 | { 22 | // If all plugins have been loaded 23 | if (a_msg->type == SKSE::MessagingInterface::kPostLoad) 24 | { 25 | if (SKSE::GetMessagingInterface()->RegisterListener("InfinityUI", InfinityUIMessageListener)) 26 | { 27 | logger::info("Successfully registered for Infinity UI messages!"); 28 | } 29 | else 30 | { 31 | logger::error("Infinity UI installation not detected. Please, download it from https://www.nexusmods.com/skyrimspecialedition/mods/74483"); 32 | } 33 | 34 | NPCNameProvider::GetSingleton()->RequestAPI(); 35 | 36 | const SKSE::PluginInfo* mapMarkerFrameworkPluginInfo = skse->GetPluginInfo("MapMarkerFramework"); 37 | 38 | if (mapMarkerFrameworkPluginInfo && mapMarkerFrameworkPluginInfo->version < 0x02020000) 39 | { 40 | logger::info("CoMAP detected. Loading compatibility patch..."); 41 | hooks::compat::MapMarkerFramework::Install(SKSE::WinAPI::GetModuleHandle("MapMarkerFramework.dll")); 42 | hooks::compat::MapMarkerFramework::pluginInfo = mapMarkerFrameworkPluginInfo; 43 | logger::info("Successfully loaded compatibility patch for CoMAP!"); 44 | } 45 | } 46 | } 47 | 48 | void InfinityUIMessageListener(SKSE::MessagingInterface::Message* a_msg) 49 | { 50 | if (!a_msg || std::string_view(a_msg->sender) != "InfinityUI") 51 | { 52 | return; 53 | } 54 | 55 | if (auto message = IUI::API::TranslateAs(a_msg)) 56 | { 57 | std::string_view movieUrl = message->movie->GetMovieDef()->GetFileURL(); 58 | 59 | if (movieUrl.find("HUDMenu") == std::string::npos) 60 | { 61 | return; 62 | } 63 | 64 | GFxMemberLogger memberLogger; 65 | 66 | switch (a_msg->type) 67 | { 68 | case IUI::API::Message::Type::kStartLoadInstances: 69 | logger::info("Started loading HUD patches"); 70 | break; 71 | case IUI::API::Message::Type::kPreReplaceInstance: 72 | if (auto preReplaceMessage = IUI::API::TranslateAs(a_msg)) 73 | { 74 | std::string pathToOriginal = preReplaceMessage->originalInstance.ToString().c_str(); 75 | 76 | if (pathToOriginal == extended::Compass::path) 77 | { 78 | extended::Compass::InitSingleton(preReplaceMessage->originalInstance); 79 | auto compass = extended::Compass::GetSingleton(); 80 | 81 | logger::debug("Before replacing:"); 82 | memberLogger.LogMembersOf(*compass); 83 | 84 | RE::GPointF coord = compass->LocalToGlobal(); 85 | logger::debug("{} is on ({}, {})", compass->ToString().c_str(), coord.x, coord.y); 86 | } 87 | } 88 | break; 89 | case IUI::API::Message::Type::kPostPatchInstance: 90 | if (auto postPatchMessage = IUI::API::TranslateAs(a_msg)) 91 | { 92 | std::string pathToNew = postPatchMessage->newInstance.ToString().c_str(); 93 | 94 | if (pathToNew == extended::Compass::path) 95 | { 96 | // We initialised the CompassShoutMeterHolder singleton in the pre-replace step, 97 | // if not, there has been an error 98 | if (auto compass = extended::Compass::GetSingleton()) 99 | { 100 | compass->SetupMod(postPatchMessage->newInstance); 101 | compass->SetUnits(settings::display::useMetricUnits); 102 | 103 | logger::debug("After replacing:"); 104 | memberLogger.LogMembersOf(*compass); 105 | 106 | RE::GPointF coord = compass->LocalToGlobal(); 107 | logger::debug("{} is on ({}, {})", compass->ToString().c_str(), coord.x, coord.y); 108 | 109 | if (hooks::compat::MapMarkerFramework::pluginInfo) 110 | { 111 | hooks::compat::MapMarkerFramework::compassMovieDef = postPatchMessage->newInstanceMovieDef; 112 | } 113 | } 114 | else 115 | { 116 | logger::error("Compass instance counterpart not ready for {}", extended::Compass::path); 117 | } 118 | } 119 | else if (pathToNew == QuestItemList::path) 120 | { 121 | QuestItemList::InitSingleton(postPatchMessage->newInstance); 122 | auto questItemList = QuestItemList::GetSingleton(); 123 | 124 | memberLogger.LogMembersOf(*questItemList); 125 | 126 | RE::GPointF coord = questItemList->LocalToGlobal(); 127 | logger::debug("{} is on ({}, {})", questItemList->ToString().c_str(), coord.x, coord.y); 128 | } 129 | } 130 | break; 131 | case IUI::API::Message::Type::kAbortPatchInstance: 132 | if (auto abortPatchMessage = IUI::API::TranslateAs(a_msg)) 133 | { 134 | std::string pathToOriginal = abortPatchMessage->originalValue.ToString().c_str(); 135 | 136 | if (pathToOriginal == extended::Compass::path) 137 | { 138 | logger::error("Aborted replacement of {}", extended::Compass::path); 139 | } 140 | } 141 | break; 142 | case IUI::API::Message::Type::kFinishLoadInstances: 143 | if (auto finishLoadMessage = IUI::API::TranslateAs(a_msg)) 144 | { 145 | RE::GFxValue test; 146 | if (finishLoadMessage->movie->GetVariable(&test, Test::path.data())) 147 | { 148 | Test::InitSingleton(test); 149 | } 150 | } 151 | logger::info("Finished loading HUD patches"); 152 | break; 153 | case IUI::API::Message::Type::kPostInitExtensions: 154 | if (auto postInitExtMessage = IUI::API::TranslateAs(a_msg)) 155 | { 156 | if (auto questItemList = QuestItemList::GetSingleton()) 157 | { 158 | questItemList->AddToHudElements(); 159 | 160 | logger::debug("QuestItemList added to HUD elements"); 161 | } 162 | 163 | logger::debug("Extensions initialization finished"); 164 | } 165 | break; 166 | default: 167 | break; 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 21, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "vcpkg", 11 | "hidden": true, 12 | "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", 13 | "cacheVariables": { 14 | "VCPKG_OVERLAY_PORTS": "${sourceDir}/cmake/ports/", 15 | "VCPKG_TARGET_TRIPLET": "x64-windows-static-md", 16 | "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$:Debug>DLL" 17 | } 18 | }, 19 | { 20 | "name": "commonlibsse-config", 21 | "hidden": true, 22 | "environment": { 23 | "COMMONLIBSSE_PLATFORM": "-DWIN32_LEAN_AND_MEAN -DNOMINMAX", 24 | "COMMONLIBSSE_TEXT": "-DUNICODE -D_UNICODE" 25 | }, 26 | "cacheVariables": { 27 | "CMAKE_CXX_FLAGS": "/permissive- /Zc:preprocessor /EHsc $penv{CXXFLAGS} $env{COMMONLIBSSE_COMPILER} $env{COMMONLIBSSE_PLATFORM} $env{COMMONLIBSSE_TEXT} $env{RUNTIME_DISABLE_FLAGS}" 28 | } 29 | }, 30 | { 31 | "name": "commonlibsse-all", 32 | "hidden": true, 33 | "environment": { 34 | "RUNTIME_DISABLE_FLAGS": "", 35 | "COMMONLIBSSE_COMPILER": "/showIncludes" 36 | } 37 | }, 38 | { 39 | "name": "commonlibsse-se-only", 40 | "hidden": true, 41 | "environment": { 42 | "RUNTIME_DISABLE_FLAGS": "-UENABLE_SKYRIM_VR", 43 | "COMMONLIBSSE_COMPILER": "" 44 | } 45 | }, 46 | { 47 | "name": "commonlibsse-vr-only", 48 | "hidden": true, 49 | "environment": { 50 | "RUNTIME_DISABLE_FLAGS": "-UENABLE_SKYRIM_SE -UENABLE_SKYRIM_AE", 51 | "COMMONLIBSSE_COMPILER": "" 52 | } 53 | }, 54 | { 55 | "name": "build-debug", 56 | "hidden": true, 57 | "inherits": [ 58 | "vcpkg", 59 | "commonlibsse-config" 60 | ], 61 | "generator": "Ninja", 62 | "cacheVariables": { 63 | "CMAKE_BUILD_TYPE": { 64 | "type": "STRING", 65 | "value": "Debug" 66 | } 67 | } 68 | }, 69 | { 70 | "name": "build-relwithdebinfo", 71 | "hidden": true, 72 | "inherits": [ 73 | "vcpkg", 74 | "commonlibsse-config" 75 | ], 76 | "generator": "Ninja", 77 | "cacheVariables": { 78 | "CMAKE_BUILD_TYPE": { 79 | "type": "STRING", 80 | "value": "RelWithDebInfo" 81 | } 82 | } 83 | }, 84 | { 85 | "name": "build-debug-all", 86 | "inherits": [ 87 | "build-debug", 88 | "commonlibsse-all" 89 | ], 90 | "displayName": "Debug", 91 | "binaryDir": "${sourceDir}/build/debug" 92 | }, 93 | { 94 | "name": "build-relwithdebinfo-all", 95 | "inherits": [ 96 | "build-relwithdebinfo", 97 | "commonlibsse-all" 98 | ], 99 | "displayName": "RelWithDebInfo", 100 | "binaryDir": "${sourceDir}/build/relwithdebinfo" 101 | }, 102 | { 103 | "name": "build-debug-se-only", 104 | "inherits": [ 105 | "build-debug", 106 | "commonlibsse-se-only" 107 | ], 108 | "displayName": "Debug (SE-AE only)", 109 | "binaryDir": "${sourceDir}/build/debug-se-only" 110 | }, 111 | { 112 | "name": "build-relwithdebinfo-se-only", 113 | "inherits": [ 114 | "build-relwithdebinfo", 115 | "commonlibsse-se-only" 116 | ], 117 | "displayName": "RelWithDebInfo (SE-AE only)", 118 | "binaryDir": "${sourceDir}/build/relwithdebinfo-se-only" 119 | }, 120 | { 121 | "name": "build-debug-vr-only", 122 | "inherits": [ 123 | "build-debug", 124 | "commonlibsse-vr-only" 125 | ], 126 | "displayName": "Debug (VR only)", 127 | "binaryDir": "${sourceDir}/build/debug-vr-only" 128 | }, 129 | { 130 | "name": "build-relwithdebinfo-vr-only", 131 | "inherits": [ 132 | "build-relwithdebinfo", 133 | "commonlibsse-vr-only" 134 | ], 135 | "displayName": "RelWithDebInfo (VR only)", 136 | "binaryDir": "${sourceDir}/build/relwithdebinfo-vr-only" 137 | } 138 | ], 139 | "buildPresets": [ 140 | { 141 | "name": "debug-se-only", 142 | "displayName": "Debug (SE only)", 143 | "configurePreset": "build-debug-se-only" 144 | }, 145 | { 146 | "name": "relwithdebinfo-se-only", 147 | "displayName": "RelWithDebInfo (SE only)", 148 | "configurePreset": "build-relwithdebinfo-se-only" 149 | }, 150 | { 151 | "name": "debug-vr-only", 152 | "displayName": "Debug (VR only)", 153 | "configurePreset": "build-debug-vr-only" 154 | }, 155 | { 156 | "name": "relwithdebinfo-vr-only", 157 | "displayName": "RelWithDebInfo (VR only)", 158 | "configurePreset": "build-relwithdebinfo-vr-only" 159 | }, 160 | { 161 | "name": "debug-all", 162 | "displayName": "Debug (All)", 163 | "configurePreset": "build-debug-all" 164 | }, 165 | { 166 | "name": "relwithdebinfo-all", 167 | "displayName": "RelWithDebInfo (All)", 168 | "configurePreset": "build-relwithdebinfo-all" 169 | } 170 | ] 171 | } 172 | -------------------------------------------------------------------------------- /include/utils/Trampoline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(SKSE_SUPPORT_XBYAK) 4 | 5 | #include 6 | #include 7 | 8 | #include "SKSE/Trampoline.h" 9 | 10 | namespace hooks 11 | { 12 | template 13 | class Hook 14 | { 15 | static_assert(SrcSize == 5 || SrcSize == 6); 16 | 17 | static constexpr std::size_t getSizeForSrc() 18 | { 19 | // Reference: write_5branch() and write_6branch() of Trampoline.h 20 | if constexpr (SrcSize == 5) 21 | { 22 | #pragma pack(push, 1) 23 | // FF /4 24 | // JMP r/m64 25 | struct TrampolineAssembly 26 | { 27 | // jmp [rip] 28 | std::uint8_t jmp; // 0 - 0xFF 29 | std::uint8_t modrm; // 1 - 0x25 30 | std::int32_t disp; // 2 - 0x00000000 31 | std::uint64_t addr; // 6 - [rip] 32 | }; 33 | #pragma pack(pop) 34 | 35 | return sizeof(TrampolineAssembly); 36 | } 37 | else 38 | { 39 | return sizeof(std::uintptr_t); 40 | } 41 | } 42 | 43 | static constexpr std::size_t getSizeFor(const Xbyak::CodeGenerator& a_dst) 44 | { 45 | return getSizeForSrc() + a_dst.getSize(); 46 | } 47 | 48 | public: 49 | 50 | Hook(std::uintptr_t a_src, const Xbyak::CodeGenerator& a_codeGen) : 51 | size{ getSizeFor(a_codeGen) }, src{ a_src }, 52 | asmCode{ a_codeGen.getCode(), a_codeGen.getCode() + a_codeGen.getSize() } 53 | { } 54 | 55 | Hook(std::uintptr_t a_src, std::uintptr_t a_dst) : 56 | size{ getSizeForSrc() }, src{ a_src }, dst{ a_dst } 57 | { } 58 | 59 | std::size_t getSize() const { return size; } 60 | 61 | std::uintptr_t getSrc() const { return src; } 62 | 63 | std::uintptr_t getDst() const { return dst; } 64 | 65 | void createDst(SKSE::Trampoline* a_allocator) 66 | { 67 | if (!asmCode.empty()) 68 | { 69 | void* buffer = a_allocator->allocate(asmCode.size()); 70 | std::memcpy(buffer, asmCode.data(), asmCode.size()); 71 | dst = reinterpret_cast(buffer); 72 | } 73 | } 74 | 75 | private: 76 | 77 | std::size_t size; 78 | std::uintptr_t src; 79 | std::uintptr_t dst = reinterpret_cast(nullptr); 80 | std::vector asmCode; 81 | }; 82 | 83 | class Trampoline 84 | { 85 | public: 86 | 87 | template 88 | std::uintptr_t write_branch(Hook& a_hook) 89 | { 90 | if (!a_hook.getDst()) { 91 | a_hook.createDst(inst); 92 | } 93 | 94 | return inst->write_branch(a_hook.getSrc(), a_hook.getDst()); 95 | } 96 | 97 | template 98 | std::uintptr_t write_call(Hook& a_hook) 99 | { 100 | if (!a_hook.getDst()) { 101 | a_hook.createDst(inst); 102 | } 103 | 104 | return inst->write_call(a_hook.getSrc(), a_hook.getDst()); 105 | } 106 | 107 | protected: 108 | 109 | Trampoline(SKSE::Trampoline& a_trampoline) : 110 | inst{ &a_trampoline } 111 | { } 112 | 113 | Trampoline(const std::string_view& a_name) : 114 | inst{ new SKSE::Trampoline{ a_name } }, deleteOnDestruct{ true } 115 | { } 116 | 117 | ~Trampoline() { if (deleteOnDestruct) delete inst; } 118 | 119 | SKSE::Trampoline* inst; 120 | 121 | private: 122 | 123 | bool deleteOnDestruct = false; 124 | }; 125 | 126 | class DefaultTrampoline : public Trampoline 127 | { 128 | public: 129 | 130 | DefaultTrampoline(std::size_t a_size, bool a_trySKSEReserve = true) : 131 | Trampoline{ SKSE::GetTrampoline() } 132 | { 133 | SKSE::AllocTrampoline(a_size, a_trySKSEReserve); 134 | } 135 | }; 136 | 137 | class CustomTrampoline : public Trampoline 138 | { 139 | public: 140 | 141 | // Reference: BranchTrampoline::Create() of https://github.com/ianpatt/skse64/blob/master/skse64_common/BranchTrampoline.cpp 142 | CustomTrampoline(const std::string_view& a_name, void* a_module, std::size_t a_size) : 143 | Trampoline{ a_name } 144 | { 145 | // search backwards from module base 146 | auto moduleBase = reinterpret_cast(a_module); 147 | std::uintptr_t addr = moduleBase; 148 | std::uintptr_t maxDisplacement = 0x80000000 - (1024 * 1024 * 128); // largest 32-bit displacement with 128MB scratch space 149 | std::uintptr_t lowestOKAddress = (moduleBase >= maxDisplacement) ? moduleBase - maxDisplacement : 0; 150 | addr--; 151 | 152 | void* base = nullptr; 153 | 154 | while (!base) 155 | { 156 | MEMORY_BASIC_INFORMATION info; 157 | 158 | if (!VirtualQuery((void*)addr, &info, sizeof(info))) 159 | { 160 | break; 161 | } 162 | 163 | if (info.State == MEM_FREE) 164 | { 165 | // free block, big enough? 166 | if (info.RegionSize >= a_size) 167 | { 168 | // try to allocate it 169 | addr = reinterpret_cast(info.BaseAddress) + info.RegionSize - a_size; 170 | 171 | base = VirtualAlloc(reinterpret_cast(addr), a_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 172 | } 173 | } 174 | 175 | // move back and try again 176 | if (!base) 177 | { 178 | addr = ((uintptr_t)info.BaseAddress) - 1; 179 | } 180 | 181 | if (addr < lowestOKAddress) 182 | { 183 | break; 184 | } 185 | } 186 | 187 | inst->set_trampoline(base, a_size, 188 | [](void* a_mem, std::size_t) 189 | { 190 | SKSE::WinAPI::VirtualFree(a_mem, 0, MEM_RELEASE); 191 | }); 192 | } 193 | }; 194 | 195 | class SigScanner 196 | { 197 | public: 198 | 199 | template 200 | static std::uintptr_t FindPattern(SKSE::WinAPI::HMODULE a_moduleHandle) 201 | { 202 | MODULEINFO moduleInfo; 203 | GetModuleInformation(GetCurrentProcess(), reinterpret_cast(a_moduleHandle), &moduleInfo, sizeof(MODULEINFO)); 204 | auto base = reinterpret_cast(moduleInfo.lpBaseOfDll); 205 | std::size_t size = moduleInfo.SizeOfImage; 206 | 207 | std::size_t patternLength = (str.length() + 1) / 3; // 2/3 useful chars (1 space between byte chars) 208 | auto pattern = REL::make_pattern(); 209 | 210 | for (std::size_t offset = 0; offset < size - patternLength; offset++) 211 | { 212 | std::uintptr_t addr = base + offset; 213 | 214 | if (pattern.match(addr)) 215 | { 216 | return addr; 217 | } 218 | } 219 | 220 | return reinterpret_cast(nullptr); 221 | } 222 | }; 223 | } 224 | 225 | #else 226 | #error "Xbyak support needed for Trampoline" 227 | #endif -------------------------------------------------------------------------------- /source/Hooks.cpp: -------------------------------------------------------------------------------- 1 | #include "Hooks.h" 2 | 3 | #include "Settings.h" 4 | 5 | #include "HUDMarkerManager.h" 6 | 7 | RE::BSTArray& GetPlayerObjectives() 8 | { 9 | auto playerAddress = reinterpret_cast(RE::PlayerCharacter::GetSingleton()); 10 | 11 | std::size_t objectivesOffset; 12 | if (REL::Module::IsVR()) 13 | { 14 | objectivesOffset = 0xB70; 15 | } else { 16 | objectivesOffset = REL::Module::get().version().compare(SKSE::RUNTIME_SSE_1_6_629) == std::strong_ordering::less ? 0x580 : 0x588; 17 | } 18 | 19 | return *reinterpret_cast*>(playerAddress + objectivesOffset); 20 | } 21 | 22 | namespace hooks 23 | { 24 | bool UpdateQuests(const RE::HUDMarkerManager* a_hudMarkerManager, RE::HUDMarker::ScaleformData* a_markerData, 25 | RE::NiPoint3* a_pos, const RE::RefHandle& a_refHandle, std::uint32_t a_markerGotoFrame, 26 | RE::TESQuestTarget* a_questTarget) 27 | { 28 | // The game loops through active quest targets, and calls `AddMarker` for each one. 29 | // If multiple targets correspond to the same marker, `AddMarker` returns the 30 | // previously-created marker (via `a_refHandle`), so we can iteratively 31 | // build the structure containing all the targets, objectives, etc. corresponding 32 | // to the marker. 33 | if (HUDMarkerManager::AddMarker(a_hudMarkerManager, a_markerData, a_pos, a_refHandle, a_markerGotoFrame)) 34 | { 35 | RE::TESObjectREFR* marker = RE::TESObjectREFR::LookupByHandle(a_refHandle).get(); 36 | 37 | RE::BSTArray& playerObjectives = GetPlayerObjectives(); 38 | 39 | RE::TESQuest* quest = nullptr; 40 | RE::BGSInstancedQuestObjective objective; 41 | RE::TESQuestTarget* target = nullptr; 42 | for (int i = 0; i < playerObjectives.size(); i++) 43 | { 44 | RE::BGSQuestObjective* questObjective = playerObjectives[i].objective; 45 | 46 | for (int j = 0; j < questObjective->numTargets; j++) 47 | { 48 | auto questObjectiveTarget = reinterpret_cast(a_questTarget->unk00); 49 | 50 | if (questObjectiveTarget == questObjective->targets[j]) 51 | { 52 | quest = questObjective->ownerQuest; 53 | objective = playerObjectives[i]; 54 | target = questObjectiveTarget; 55 | break; 56 | } 57 | } 58 | } 59 | 60 | extended::HUDMarkerManager::GetSingleton()->ProcessQuestMarker(quest, objective, target, marker, a_markerGotoFrame); 61 | 62 | return true; 63 | } 64 | 65 | return false; 66 | } 67 | 68 | RE::TESWorldSpace* AllowedToShowMapMarker(const RE::TESObjectREFR* a_marker) 69 | { 70 | RE::TESWorldSpace* markerWorldspace = a_marker->GetWorldspace(); 71 | 72 | if (settings::display::showInteriorMarkers) 73 | { 74 | auto player = RE::PlayerCharacter::GetSingleton(); 75 | 76 | RE::TESWorldSpace* playerWorldspace = player->GetWorldspace(); 77 | 78 | if (playerWorldspace && markerWorldspace && playerWorldspace != markerWorldspace) 79 | { 80 | if (!playerWorldspace->parentWorld && markerWorldspace->parentWorld == playerWorldspace) 81 | { 82 | return playerWorldspace; 83 | } 84 | } 85 | } 86 | 87 | return markerWorldspace; 88 | } 89 | 90 | bool UpdateLocations(const RE::HUDMarkerManager* a_hudMarkerManager, RE::HUDMarker::ScaleformData* a_markerData, 91 | RE::NiPoint3* a_pos, const RE::RefHandle& a_refHandle, std::uint32_t a_markerGotoFrame) 92 | { 93 | RE::TESObjectREFR* marker = RE::TESObjectREFR::LookupByHandle(a_refHandle).get(); 94 | RE::PlayerCharacter* player = RE::PlayerCharacter::GetSingleton(); 95 | 96 | RE::NiPoint3 markerPos = util::GetRealPosition(marker); 97 | RE::NiPoint3 playerPos = util::GetRealPosition(player); 98 | 99 | float sqDistanceToMarker = playerPos.GetSquaredDistance(markerPos); 100 | 101 | if (sqDistanceToMarker < RE::HUDMarkerManager::GetSingleton()->sqRadiusToAddLocation) 102 | { 103 | auto mapMarker = marker->extraList.GetByType(); 104 | 105 | auto frameOffsets = RE::HUDMarker::FrameOffsets::GetSingleton(); 106 | 107 | // Unvisited markers keep being shown in any case 108 | if (settings::display::showUndiscoveredLocationMarkers || mapMarker->mapData->flags.all(RE::MapMarkerData::Flag::kVisible)) 109 | { 110 | if (HUDMarkerManager::AddMarker(a_hudMarkerManager, a_markerData, a_pos, a_refHandle, a_markerGotoFrame)) 111 | { 112 | extended::HUDMarkerManager::GetSingleton()->ProcessLocationMarker(mapMarker, marker, a_markerGotoFrame); 113 | 114 | return true; 115 | } 116 | } 117 | } 118 | 119 | return false; 120 | } 121 | 122 | bool UpdateEnemies(const RE::HUDMarkerManager* a_hudMarkerManager, RE::HUDMarker::ScaleformData* a_markerData, 123 | RE::NiPoint3* a_pos, const RE::RefHandle& a_refHandle, std::uint32_t a_markerGotoFrame) 124 | { 125 | if (settings::display::showEnemyMarkers) 126 | { 127 | if (HUDMarkerManager::AddMarker(a_hudMarkerManager, a_markerData, a_pos, a_refHandle, a_markerGotoFrame)) 128 | { 129 | RE::TESObjectREFR* marker = RE::TESObjectREFR::LookupByHandle(a_refHandle).get(); 130 | 131 | extended::HUDMarkerManager::GetSingleton()->ProcessEnemyMarker(marker->As(), a_markerGotoFrame); 132 | 133 | return true; 134 | } 135 | } 136 | 137 | return false; 138 | } 139 | 140 | bool UpdatePlayerSetMarker(const RE::HUDMarkerManager* a_hudMarkerManager, RE::HUDMarker::ScaleformData* a_markerData, 141 | RE::NiPoint3* a_pos, const RE::RefHandle& a_refHandle, std::uint32_t a_markerGotoFrame) 142 | { 143 | if (HUDMarkerManager::AddMarker(a_hudMarkerManager, a_markerData, a_pos, a_refHandle, a_markerGotoFrame)) 144 | { 145 | RE::TESObjectREFR* marker = RE::TESObjectREFR::LookupByHandle(a_refHandle).get(); 146 | 147 | extended::HUDMarkerManager::GetSingleton()->ProcessPlayerSetMarker(marker, a_markerGotoFrame); 148 | 149 | return true; 150 | } 151 | 152 | return false; 153 | } 154 | 155 | bool SetCompassMarkers(RE::GFxValue::ObjectInterface* a_objectInterface, void* a_data, 156 | RE::GFxValue* a_result, const char* a_name, const RE::GFxValue* a_args, 157 | std::uint32_t a_numArgs, bool a_isDObj) 158 | { 159 | extended::HUDMarkerManager::GetSingleton()->SetMarkers(); 160 | 161 | return true; 162 | } 163 | 164 | namespace compat 165 | { 166 | RE::GFxMovieDef* MapMarkerFramework::GetCompassMovieDef() 167 | { 168 | return compassMovieDef; 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /include/RE/G/GFxCharacter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GArray.h" 4 | #include "RE/G/GASObjectInterface.h" 5 | #include "RE/G/GFxCharacterHandle.h" 6 | #include "RE/G/GFxLog.h" 7 | #include "RE/G/GFxPlayerStats.h" 8 | #include "RE/G/GMatrix2D.h" 9 | #include "RE/G/GMatrix3D.h" 10 | #include "RE/G/GPoint.h" 11 | #include "RE/G/GRect.h" 12 | #include "RE/G/GRefCountNTSImpl.h" 13 | #include "RE/G/GRefCountBaseStatImpl.h" 14 | #include "RE/G/GRefCountBaseWeakSupport.h" 15 | #include "RE/G/GRenderer.h" 16 | 17 | namespace RE 18 | { 19 | class GASEnvironment; 20 | class GASString; 21 | class GFxASCharacter; 22 | class GFxEventId; 23 | class GFxCharacterDef; 24 | class GFxDisplayContext; 25 | class GFxFilterDesc; 26 | class GFxFontManager; 27 | class GFxMovieDefImpl; 28 | class GFxMovieRoot; 29 | class GFxScale9Grid; 30 | 31 | // DisplayObjectBase, DisplayObject in Scaleform 4.1 32 | class GFxCharacter : 33 | public GRefCountBaseWeakSupport, // 00 34 | public GFxLogBase // 18 35 | { 36 | public: 37 | 38 | struct TopMostParams 39 | { 40 | 41 | }; 42 | 43 | enum Flags : uint16_t 44 | { 45 | kScale9GridExists = 0x1, 46 | kTopmostLevel = 0x2, 47 | kHitTestNegative = 0x4, 48 | kHitTestPositive = 0x8, 49 | kHitTest = 0xC, 50 | kUnloaded = 0x10, 51 | kJustLoaded = 0x20, 52 | kMarkedForRemove = 0x40, 53 | kInteractiveObject = 0x80, 54 | kScriptableObject = 0x100, 55 | kDisplayObjContainer = 0x200, 56 | kSprite = 0x400, 57 | kMovieClip = 0x800, 58 | kUnloading = 0x1000, 59 | kLoaded = 0x2000, 60 | kVisible = 0x4000, 61 | kIndirectTransform = 0x8000, 62 | }; 63 | 64 | // add 65 | virtual void UpdateAlphaFlag(); // 01 66 | virtual bool Has3D() const; // 02 67 | virtual void UpdateViewAndPerspective(); // 03 68 | virtual bool GetVisible() const; // 04 69 | virtual GRenderer::BlendType GetBlendMode() const; // 05 70 | virtual bool GetContinueAnimationFlag() const; // 06 71 | virtual bool GetAcceptAnimMoves() const; // 07 72 | virtual void SetAcceptAnimMoves(bool); // 08 73 | virtual void SetBlendMode(GRenderer::BlendType); // 09 74 | virtual void SetName(const GASString&); // 0A 75 | virtual void SetOriginalName(const GASString&); // 0B 76 | virtual void SetFilters(GArray); // 0C 77 | virtual GRectF GetBounds(const GMatrix2D&) const; // 0D 78 | virtual void Unk_0E(void); // 0E 79 | virtual void Unk_0F(void); // 0F 80 | virtual GRectF GetRectBounds(const GMatrix2D&) const; // 10 81 | virtual bool PointTestLocal(const GPointF&, std::uint8_t) const; // 11 82 | virtual GFxASCharacter* GetTopMostMouseEntity(const GPointF&, const TopMostParams&); // 12 83 | virtual const GFxScale9Grid* GetScale9Grid() const; // 13 84 | virtual void PropagateScale9GridExists(); // 14 85 | virtual GFxMovieRoot* GetMovieRoot() const; // 15 86 | virtual GFxCharacterDef* GetCharacterDef() const = 0; // 16 87 | virtual GFxMovieDefImpl* GetResourceMovieDef() const; // 17 88 | virtual GFxFontManager* GetFontManager() const; // 18 89 | virtual GFxASCharacter* GetLevelMovie(std::int32_t) const; // 19 90 | virtual GFxASCharacter* GetASRootMovie(bool) const; // 1A 91 | virtual const GASEnvironment* GetASEnvironment() const; // 1B 92 | virtual GASEnvironment* GetASEnvironment(); // 1C 93 | virtual void Display(GFxDisplayContext&); // 1D 94 | virtual void Restart(); // 1E 95 | virtual void AdvanceFrame(bool, float); // 1F 96 | virtual bool OnEvent(const GFxEventId&); // 20 97 | virtual void OnEventLoad(); // 21 98 | virtual void OnEventUnload(); // 22 99 | virtual bool OnUnloading(); // 23 100 | virtual void DetachChild(GFxASCharacter*); // 24 101 | virtual bool OnKeyEvent(const GFxEventId&, std::int32_t*); // 25 102 | virtual bool OnCharEvent(std::uint64_t, std::uint32_t); // 26 103 | virtual bool OnMouseWheelEvent(std::int32_t); // 27 104 | virtual void PropagateMouseEvent(const GFxEventId&); // 28 105 | virtual void PropagateKeyEvent(const GFxEventId&, std::int32_t*); // 29 106 | virtual GFxLog* GetLog() const; // 2A 107 | virtual bool IsVerboseAction() const; // 2B 108 | virtual GASObjectInterface::ObjectType GetObjectType() const; // 2C 109 | virtual bool IsUsedAsMask() const; // 2D 110 | virtual void SetStateChangeFlags(std::uint8_t); // 2E 111 | virtual std::uint8_t GetStateChangeFlags() const; // 2F 112 | virtual void OnRendererChanged(); // 30 113 | 114 | // members 115 | GFxResourceID resourceID; // 20 116 | std::int32_t depth; // 24 117 | std::uint32_t createFrame; // 28 118 | float ratio; // 2C 119 | GFxASCharacter* parent; // 30 120 | GRenderer::Cxform cxform; // 38 121 | GMatrix2D matrix; // 58 122 | GMatrix3D* matrix3D; // 70 123 | GMatrix3D* perspective3D; // 78 124 | GMatrix3D* view3D; // 80 125 | float perspectiveFOV; // 88 126 | std::uint8_t unk8C[8]; // 8C 127 | std::uint16_t clipDepth; // 94 128 | Flags flags; // 96 129 | }; 130 | static_assert(sizeof(GFxCharacter) == 0x98); 131 | } -------------------------------------------------------------------------------- /include/RE/G/GFxMovieDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GFxResource.h" 4 | #include "RE/G/GFxResourceID.h" 5 | #include "RE/G/GFxStateBag.h" 6 | #include "RE/G/GMemoryHeap.h" 7 | #include "RE/G/GRect.h" 8 | #include "RE/G/GStats.h" 9 | 10 | namespace RE 11 | { 12 | class GFxExporterInfo; 13 | class GFxMovieView; 14 | 15 | // Represents loaded shared data for an SWF movie file. These objects are normally created by Loader::CreateMovie and are shared by all movie instances. 16 | class GFxMovieDef : 17 | public GFxResource, // 00 18 | public GFxStateBag // 18 19 | { 20 | public: 21 | // SWF 8 file attributes, returned by GetFileAttributes. These attributes are configured in Publish Settings and Document Properties dialogs of the Flash studio. 22 | enum FileAttrFlags : std::uint32_t 23 | { 24 | kUseNetwork = 1 << 0, // - Indicates that "Access Network only" was selected for an SWF file in publish settings for local playback security 25 | kHasMetadata = 1 << 4 // - Indicates that the file has embedded metadata, available through the GetMetadata method 26 | }; 27 | 28 | // VisitResourceMask defines a set of resource mask flag bits passed as a visitMask argument to VisitResources. If a given flag bit is included in the visitMask, the corresponding resource types are included in the enumeration, otherwise they are ignored. 29 | enum VisitResourceMask : std::uint32_t 30 | { 31 | kNestedMovies = 1 << 15, // Indicates that resources in the imported movies should also be enumerated. 32 | 33 | // Types of resources to visit 34 | kFonts = 1 << 0, // Font resources should be enumerated. 35 | kBitmaps = 1 << 1, // Image resources with GFxResource::ResourceUse::kBitmap should be enumerated (See GFxResource::ResourceUse). These resources correspond to image shape fills used in the SWF/FLA files. 36 | kGradientImages = 1 << 2, // Image resources with GFxResource::ResourceUse::kGradientBitmaps should be enumerated (See GFxResource::ResourceUse). These resources are created based on GradientParams during loading. 37 | kEditTextFields = 1 << 3, // Edit text field resources should be enumerated. 38 | kSounds = 1 << 4, // Sound resources should be enumerated. 39 | kSprite = 1 << 5, // Sprite resources should be enumerated. 40 | 41 | // Combined flags 42 | kAllLocalImages = (kBitmaps | kGradientImages), // Combines kBitmaps and kGradientImages. 43 | kAllImages = (kBitmaps | kGradientImages | kNestedMovies) // Combines kBitmaps, kGradientImages and kNestedMovies. 44 | }; 45 | 46 | struct MemoryParams 47 | { 48 | MemoryParams(UPInt a_memoryArena = 0); 49 | 50 | // members 51 | GMemoryHeap::HeapDesc desc; // 00 52 | float heapLimitMultiplier; // 40 53 | std::uint32_t maxCollectionRoots; // 44 54 | std::uint32_t framesBetweenCollections; // 48 55 | std::uint32_t pad4C; // 4C 56 | }; 57 | static_assert(sizeof(MemoryParams) == 0x50); 58 | 59 | class MemoryContext : public GRefCountBase 60 | { 61 | public: 62 | MemoryContext() = delete; 63 | ~MemoryContext() override; // 00 64 | }; 65 | static_assert(sizeof(MemoryContext) == 0x10); 66 | 67 | struct ImportVisitor 68 | { 69 | virtual ~ImportVisitor(); // 00 70 | 71 | // add 72 | virtual void Visit(GFxMovieDef* a_parentDef, GFxMovieDef* a_importDef, const char* a_importedMovieFilename) = 0; // 01 73 | }; 74 | static_assert(sizeof(ImportVisitor) == 0x8); 75 | 76 | struct ResourceVisitor : public GFxFileConstants 77 | { 78 | virtual ~ResourceVisitor(); // 00 79 | 80 | // add 81 | virtual void Visit(GFxMovieDef* a_movieDef, GFxResource* a_resource, GFxResourceID a_id, const char* a_exportName) = 0; // 01 82 | }; 83 | static_assert(sizeof(ResourceVisitor) == 0x8); 84 | 85 | // add 86 | [[nodiscard]] virtual std::uint32_t GetVersion() const = 0; // 04 87 | [[nodiscard]] virtual std::uint32_t GetLoadingFrame() const = 0; // 05 88 | [[nodiscard]] virtual float GetWidth() const = 0; // 06 89 | [[nodiscard]] virtual float GetHeight() const = 0; // 07 90 | [[nodiscard]] virtual std::uint32_t GetFrameCount() const = 0; // 08 91 | [[nodiscard]] virtual float GetFrameRate() const = 0; // 09 92 | [[nodiscard]] virtual GRectF GetFrameRect() const = 0; // 0A 93 | [[nodiscard]] virtual std::uint32_t GetSWFFlags() const = 0; // 0B 94 | [[nodiscard]] virtual const char* GetFileURL() const = 0; // 0C 95 | virtual void WaitForLoadFinish(bool a_cancel = false) const = 0; // 0D 96 | virtual void WaitForFrame(std::uint32_t a_frame) const = 0; // 0E 97 | [[nodiscard]] virtual std::uint32_t GetFileAttributes() const = 0; // 0F 98 | virtual std::uint32_t GetMetadata(char* a_buff, std::uint32_t a_buffSize) const = 0; // 10 99 | [[nodiscard]] virtual GMemoryHeap* GetLoadDataHeap() const = 0; // 11 100 | [[nodiscard]] virtual GMemoryHeap* GetBindDataHeap() const = 0; // 12 101 | [[nodiscard]] virtual GMemoryHeap* GetImageHeap() const = 0; // 13 102 | [[nodiscard]] virtual GFxResource* GetMovieDataResource() const = 0; // 14 103 | [[nodiscard]] virtual const GFxExporterInfo* GetExporterInfo() const = 0; // 15 104 | virtual MemoryContext* CreateMemoryContext(const char* a_heapName, const MemoryParams& a_memParams, bool a_debugHeap) = 0; // 16 105 | virtual GFxMovieView* CreateInstance(const MemoryParams& a_memParams, bool a_initFirstFrame = true) = 0; // 17 106 | virtual GFxMovieView* CreateInstance(MemoryContext* a_memContext, bool a_initFirstFrame = true) = 0; // 18 107 | virtual void VisitImportedMovies(ImportVisitor* a_visitor) = 0; // 19 108 | virtual void VisitResources(ResourceVisitor* a_visitor, VisitResourceMask a_visitMask = VisitResourceMask::kAllImages) = 0; // 1A 109 | virtual GFxResource* GetResource(const char* a_exportName) const = 0; // 1B 110 | 111 | GFxMovieView* CreateInstance(bool a_initFirstFrame = true, UPInt a_memoryArena = 0); 112 | }; 113 | static_assert(sizeof(GFxMovieDef) == 0x20); 114 | } 115 | -------------------------------------------------------------------------------- /include/RE/T/TESQuest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/B/BGSStoryManagerTreeForm.h" 4 | #include "RE/B/BSAtomic.h" 5 | #include "RE/B/BSFixedString.h" 6 | #include "RE/B/BSString.h" 7 | #include "RE/B/BSTArray.h" 8 | #include "RE/B/BSTHashMap.h" 9 | #include "RE/B/BSTList.h" 10 | #include "RE/D/DialogueTypes.h" 11 | #include "RE/F/FormTypes.h" 12 | #include "RE/Q/QuestEvents.h" 13 | #include "RE/Q/QuestObjectiveStates.h" 14 | #include "RE/T/TESCondition.h" 15 | #include "RE/T/TESFullName.h" 16 | 17 | namespace RE 18 | { 19 | class BGSBaseAlias; 20 | class QueuedPromoteQuestTask; 21 | 22 | enum class QuestFlag 23 | { 24 | kStopStart = static_cast>(-1), 25 | kNone = 0, 26 | kEnabled = 1 << 0, 27 | kCompleted = 1 << 1, 28 | kAddIdleToHello = 1 << 2, 29 | kAllowRepeatStages = 1 << 3, 30 | kStartsEnabled = 1 << 4, 31 | kDisplayedInHUD = 1 << 5, 32 | kFailed = 1 << 6, 33 | kStageWait = 1 << 7, 34 | kRunOnce = 1 << 8, 35 | kExcludeFromExport = 1 << 9, 36 | kWarnOnAliasFillFailure = 1 << 10, 37 | kActive = 1 << 11, 38 | kRepeatsConditions = 1 << 12, 39 | kKeepInstance = 1 << 13, 40 | kWantDormant = 1 << 14, 41 | kHasDialogueData = 1 << 15 42 | }; 43 | 44 | enum class QUEST_OBJECTIVE_FLAGS 45 | { 46 | kNone = 0, 47 | kORWithPrevious = 1 << 0, 48 | kNoStatsTracking = 1 << 1 49 | }; 50 | 51 | struct BGSQuestInstanceText 52 | { 53 | public: 54 | struct StringData 55 | { 56 | public: 57 | // members 58 | std::uint32_t aliasID; // 0 59 | std::uint32_t fullNameFormID; // 4 60 | }; 61 | static_assert(sizeof(StringData) == 0x8); 62 | 63 | struct GlobalValueData 64 | { 65 | public: 66 | // members 67 | const TESGlobal* global; // 00 68 | float value; // 08 69 | std::uint32_t pad0C; // 0C 70 | }; 71 | static_assert(sizeof(GlobalValueData) == 0x10); 72 | 73 | // members 74 | std::uint32_t id; // 00 75 | std::uint32_t pad04; // 04 76 | BSTArray stringData; // 08 77 | BSTArray valueData; // 20 78 | std::uint16_t journalStage; // 38 79 | std::int8_t journalStageItem; // 3A 80 | std::uint8_t pad3B; // 3B 81 | std::uint32_t pad3C; // 3C 82 | }; 83 | static_assert(sizeof(BGSQuestInstanceText) == 0x40); 84 | 85 | struct QUEST_DATA // DNAM 86 | { 87 | public: 88 | enum class Type 89 | { 90 | kNone = 0, 91 | kMainQuest = 1, 92 | kMagesGuild = 2, 93 | kThievesGuild = 3, 94 | kDarkBrotherhood = 4, 95 | kCompanionsQuest = 5, 96 | kMiscellaneous = 6, 97 | kDaedric = 7, 98 | kSideQuest = 8, 99 | kCivilWar = 9, 100 | kDLC01_Vampire = 10, 101 | kDLC02_Dragonborn = 11 102 | }; 103 | 104 | // members 105 | float questDelayTime; // 0 106 | stl::enumeration flags; // 4 107 | std::int8_t priority; // 6 108 | stl::enumeration questType; // 7 109 | }; 110 | static_assert(sizeof(QUEST_DATA) == 0x8); 111 | 112 | struct QUEST_STAGE_DATA 113 | { 114 | public: 115 | enum class Flag 116 | { 117 | kNone = 0, 118 | kStartUpStage = 1 << 1, 119 | kShutDownStage = 1 << 2, 120 | kKeepInstanceDataFromHereOn = 1 << 3 121 | }; 122 | 123 | // members 124 | std::uint16_t index; // 0 125 | stl::enumeration flags; // 2 126 | std::uint8_t pad3; // 3 127 | std::uint32_t pad4; // 4 128 | }; 129 | static_assert(sizeof(QUEST_STAGE_DATA) == 0x8); 130 | 131 | class TESQuestStage 132 | { 133 | public: 134 | explicit operator bool() const; 135 | 136 | // members 137 | QUEST_STAGE_DATA data; // 0 138 | }; 139 | static_assert(sizeof(TESQuestStage) == 0x8); 140 | 141 | class TESQuestTarget // QSTA 142 | { 143 | public: 144 | enum class Flag 145 | { 146 | kNone = 0, 147 | kCompassMarkerIgnoresLocks = 1 << 0 148 | }; 149 | 150 | // members 151 | std::uint64_t unk00; // 00 152 | TESCondition conditions; // 08 153 | std::uint8_t alias; // 10 154 | std::uint8_t unk11; // 11 155 | std::uint16_t unk12; // 12 156 | std::uint32_t unk14; // 14 157 | }; 158 | static_assert(sizeof(TESQuestTarget) == 0x18); 159 | 160 | class BGSQuestObjective 161 | { 162 | public: 163 | // members 164 | BSFixedString displayText; // 00 - NNAM 165 | TESQuest* ownerQuest; // 08 166 | TESQuestTarget** targets; // 10 - QSTA 167 | std::uint32_t numTargets; // 18 168 | std::uint16_t index; // 1C - QOBJ 169 | bool initialized; // 1E 170 | stl::enumeration state; // 1E 171 | stl::enumeration flags; // 20 - FNAM 172 | std::uint32_t pad24; // 24 173 | }; 174 | static_assert(sizeof(BGSQuestObjective) == 0x28); 175 | 176 | class BGSStoryEvent 177 | { 178 | public: 179 | // members 180 | std::uint32_t id; // 00 181 | std::uint32_t index; // 04 182 | std::uint64_t members[6]; // 08 183 | }; 184 | static_assert(sizeof(BGSStoryEvent) == 0x38); 185 | 186 | class TESQuest : 187 | public BGSStoryManagerTreeForm, // 000 188 | public TESFullName // 028 189 | { 190 | public: 191 | inline static constexpr auto RTTI = RTTI_TESQuest; 192 | inline static constexpr auto VTABLE = VTABLE_TESQuest; 193 | 194 | using DT = DIALOGUE_TYPE; 195 | inline static constexpr auto FORMTYPE = FormType::Quest; 196 | 197 | struct ChangeFlags 198 | { 199 | enum ChangeFlag : std::uint32_t 200 | { 201 | kQuestFlags = 1 << 1, 202 | kQuestScriptDelay = 1 << 2, 203 | kQuestAlreadyRun = 1 << 26, 204 | kQuestInstanceData = 1 << 27, 205 | kQuestRuntimeData = 1 << 28, 206 | kQuestObjectives = 1 << 29, 207 | kQuestScript = 1 << 30, 208 | kQuestStages = (std::uint32_t)1 << 31 209 | }; 210 | }; 211 | 212 | struct RecordFlags 213 | { 214 | enum RecordFlag : std::uint32_t 215 | { 216 | kDeleted = 1 << 5, 217 | kIgnored = 1 << 12 218 | }; 219 | }; 220 | 221 | ~TESQuest() override; // 00 222 | 223 | // override (BGSStoryManagerTreeForm) 224 | void InitializeData() override; // 04 225 | void ClearData() override; // 05 226 | bool Load(TESFile* a_mod) override; // 06 227 | void SaveGame(BGSSaveFormBuffer* a_buf) override; // 0E 228 | void LoadGame(BGSLoadFormBuffer* a_buf) override; // 0F 229 | void FinishLoadGame(BGSLoadFormBuffer* a_buf) override; // 11 230 | void Revert(BGSLoadFormBuffer* a_buf) override; // 12 231 | void InitItemImpl() override; // 13 232 | const char* GetFormEditorID() const override; // 32 - { return formEditorID.c_str(); } 233 | bool SetFormEditorID(const char* a_str) override; // 33 234 | TESCondition* QConditions() override; // 3D - { return &objConditions; } 235 | BGSStoryManagerTreeVisitor::VisitControl AcceptVisitor(BGSStoryManagerTreeVisitor& a_visitor) override; // 3E 236 | 237 | ObjectRefHandle& CreateRefHandleByAliasID(ObjectRefHandle& a_handle, std::uint32_t a_aliasID); 238 | bool EnsureQuestStarted(bool& a_result, bool a_startNow); 239 | std::uint16_t GetCurrentStageID() const; 240 | [[nodiscard]] constexpr QUEST_DATA::Type GetType() const noexcept { return data.questType.get(); } 241 | bool IsActive() const; 242 | bool IsCompleted() const; 243 | bool IsEnabled() const; 244 | bool IsRunning() const; 245 | bool IsStarting() const; 246 | bool IsStopped() const; 247 | bool IsStopping() const; 248 | void Reset(); 249 | void ResetAndUpdate(); 250 | void SetEnabled(bool a_set); 251 | bool Start(); 252 | bool StartsEnabled() const; 253 | void Stop(); 254 | BSString GetCurrentDescriptionWithReplacedTags() const; 255 | 256 | // members 257 | BSTArray instanceData; // 038 258 | std::uint32_t currentInstanceID; // 050 259 | std::uint32_t pad054; // 054 260 | BSTArray aliases; // 058 261 | BSTHashMap unk070; // 070 - alias related 262 | BSTHashMap unk0A0; // 0A0 - alias related 263 | mutable BSReadWriteLock aliasAccessLock; // 0D0 264 | QUEST_DATA data; // 0D8 - DNAM 265 | QuestEvent eventID; // 0E0 - ENAM 266 | std::uint32_t pad0E4; // 0E4 267 | BSSimpleList* executedStages; // 0E8 268 | BSSimpleList* waitingStages; // 0F0 269 | BSSimpleList objectives; // 0F8 270 | TESCondition objConditions; // 108 271 | TESCondition storyManagerConditions; // 110 272 | BSTHashMap*> branchedDialogue[DT::kBranchedTotal]; // 118 273 | BSTArray topics[DT::kTotal - DT::kBranchedTotal]; // 178 274 | BSTArray scenes; // 208 275 | BSTArray* textGlobals; // 220 - QTGL 276 | std::uint16_t currentStage; // 228 277 | bool alreadyRun; // 22A 278 | std::uint8_t pad22B; // 22B 279 | std::uint32_t pad22C; // 22C 280 | BSString formEditorID; // 230 281 | const BGSStoryEvent* startEventData; // 240 282 | NiPointer promoteTask; // 248 283 | BSTArray promotedRefs; // 250 284 | }; 285 | static_assert(sizeof(TESQuest) == 0x268); 286 | 287 | void ReplaceTagsInQuestText(BSString* a_text, const TESQuest* a_quest, std::uint32_t a_questInstanceId); 288 | } 289 | -------------------------------------------------------------------------------- /include/Hooks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/Trampoline.h" 4 | 5 | #include "RE/B/BSCoreTypes.h" 6 | #include "RE/C/Compass.h" 7 | #include "RE/H/HUDMarkerManager.h" 8 | #include "RE/N/NiPoint3.h" 9 | 10 | namespace hooks 11 | { 12 | bool UpdateQuests(const RE::HUDMarkerManager* a_hudMarkerManager, RE::HUDMarker::ScaleformData* a_markerData, 13 | RE::NiPoint3* a_pos, const RE::RefHandle& a_refHandle, std::uint32_t a_markerGotoFrame, 14 | RE::TESQuestTarget* a_questTargets); 15 | 16 | RE::TESWorldSpace* AllowedToShowMapMarker(const RE::TESObjectREFR* a_marker); 17 | 18 | bool UpdateLocations(const RE::HUDMarkerManager* a_hudMarkerManager, RE::HUDMarker::ScaleformData* a_markerData, 19 | RE::NiPoint3* a_pos, const RE::RefHandle& a_refHandle, std::uint32_t a_markerGotoFrame); 20 | 21 | bool UpdateEnemies(const RE::HUDMarkerManager* a_hudMarkerManager, RE::HUDMarker::ScaleformData* a_markerData, 22 | RE::NiPoint3* a_pos, const RE::RefHandle& a_refHandle, std::uint32_t a_markerGotoFrame); 23 | 24 | bool UpdatePlayerSetMarker(const RE::HUDMarkerManager* a_hudMarkerManager, RE::HUDMarker::ScaleformData* a_markerData, 25 | RE::NiPoint3* a_pos, const RE::RefHandle& a_refHandle, std::uint32_t a_markerGotoFrame); 26 | 27 | bool SetCompassMarkers(RE::GFxValue::ObjectInterface* a_objectInterface, void* a_data, 28 | RE::GFxValue* a_result, const char* a_name, const RE::GFxValue* a_args, 29 | std::uint32_t a_numArgs, bool a_isDObj); 30 | 31 | class HUDMarkerManager 32 | { 33 | static constexpr REL::RelocationID UpdateQuestsId{ 50826, 51691 }; 34 | static constexpr REL::RelocationID UpdateLocationsId{ 50870, 51744 }; 35 | static constexpr REL::RelocationID AddMarkerId{ 50851, 51728 }; 36 | 37 | public: 38 | 39 | static inline REL::Relocation*)> UpdateQuests{ UpdateQuestsId }; 41 | 42 | static inline REL::Relocation UpdateLocations{ UpdateLocationsId }; 43 | 44 | static inline REL::Relocation AddMarker{ AddMarkerId }; 46 | }; 47 | 48 | class HUDMenu 49 | { 50 | static constexpr REL::RelocationID ProcessMessageId{ 50718, 51612 }; 51 | 52 | public: 53 | 54 | static inline REL::Relocation ProcessMessage{ ProcessMessageId }; 55 | }; 56 | 57 | class Compass 58 | { 59 | static constexpr REL::RelocationID SetMarkersId{ 50775, 51670 }; 60 | static constexpr REL::RelocationID UpdateId{ 50773, 51668 }; 61 | 62 | public: 63 | 64 | static inline REL::Relocation SetMarkers{ SetMarkersId }; 65 | static inline REL::Relocation Update{ UpdateId }; 66 | }; 67 | 68 | static inline void Install() 69 | { 70 | // `HUDMarkerManager::UpdateQuests` (call to `HUDMarkerManager::AddMarker`) 71 | struct UpdateQuestsHook : Hook<5> 72 | { 73 | static std::uintptr_t Address() { return HUDMarkerManager::UpdateQuests.address() + REL::VariantOffset{ 0x114, 0x180, 0x114 }.offset(); } 74 | 75 | struct HookCodeGenerator : Xbyak::CodeGenerator 76 | { 77 | HookCodeGenerator(std::uintptr_t a_hookedAddress) 78 | { 79 | Xbyak::Label hookLabel; 80 | Xbyak::Label retnLabel; 81 | 82 | mov(ptr[rsp + 0x28], rbx); // rbx = TESQuestTarget* 83 | call(ptr[rip + hookLabel]); 84 | 85 | jmp(ptr[rip + retnLabel]); 86 | 87 | L(hookLabel), dq(reinterpret_cast(&UpdateQuests)); 88 | L(retnLabel), dq(a_hookedAddress + 5); 89 | 90 | ready(); 91 | } 92 | }; 93 | 94 | UpdateQuestsHook(std::uintptr_t a_hookedAddress) : 95 | Hook{ a_hookedAddress, HookCodeGenerator{ a_hookedAddress } } 96 | {} 97 | }; 98 | 99 | // `HUDMarkerManager::UpdateLocations` (calls to `TESObjectREFR::GetWorldspace`) 100 | struct AllowedToShowMapMarkerHook : Hook<5> 101 | { 102 | static std::uintptr_t Address1() { return HUDMarkerManager::UpdateLocations.address() + REL::VariantOffset{ 0x139, 0x13C, 0x139 }.offset(); } 103 | static std::uintptr_t Address2() { return HUDMarkerManager::UpdateLocations.address() + REL::VariantOffset{ 0x21C, 0x24B, 0x21C }.offset(); } 104 | 105 | AllowedToShowMapMarkerHook(std::uintptr_t a_hookedAddress) : 106 | Hook{ a_hookedAddress, reinterpret_cast(&AllowedToShowMapMarker) } 107 | {} 108 | }; 109 | 110 | // `HUDMarkerManager::UpdateLocations` (call to `HUDMarkerManager::AddMarker` for locations) 111 | struct UpdateLocationsHook : Hook<5> 112 | { 113 | static std::uintptr_t Address() { return HUDMarkerManager::UpdateLocations.address() + REL::VariantOffset{ 0x450, 0x473, 0x450 }.offset(); } 114 | 115 | UpdateLocationsHook(std::uintptr_t a_hookedAddress) : 116 | Hook{ a_hookedAddress, reinterpret_cast(&UpdateLocations) } 117 | {} 118 | }; 119 | 120 | // `HUDMenu::ProcessMessage` (call to `HUDMarkerManager::AddMarker` for enemies) 121 | struct UpdateEnemiesHook : Hook<5> 122 | { 123 | // Offset changed from 1.6.640 -> 1.6.1130, so we gotta be more granular with the versions 124 | static std::uintptr_t Address() 125 | { 126 | REL::Version version = REL::Module::get().version(); 127 | std::uintptr_t offsetAE = version < SKSE::RUNTIME_SSE_1_6_1130 ? 0x1695 : 0x1735; 128 | 129 | return HUDMenu::ProcessMessage.address() + REL::VariantOffset{ 0x15AB, offsetAE, 0x15AB }.offset(); 130 | } 131 | 132 | UpdateEnemiesHook(std::uintptr_t a_hookedAddress) : 133 | Hook{ a_hookedAddress, reinterpret_cast(&UpdateEnemies) } 134 | {} 135 | }; 136 | 137 | // `Compass::SetMarkers` (call to `HUDMarkerManager::AddMarker` for Player-set marker) 138 | struct UpdatePlayerSetMarkerHook : Hook<5> 139 | { 140 | // In AE `Compass::SetMarkers` is inlined in `Compass::Update` 141 | static std::uintptr_t Address() { return REL::Module::IsAE() ? Compass::Update.address() + 0xAE : Compass::SetMarkers.address() + 0x8D; } 142 | 143 | UpdatePlayerSetMarkerHook(std::uintptr_t a_hookedAddress) : 144 | Hook{ a_hookedAddress, reinterpret_cast(&UpdatePlayerSetMarker) } 145 | {} 146 | }; 147 | 148 | // `Compass::SetMarkers` (call to movie->Invoke("SetCompassMarkers", ...)) 149 | struct SetCompassMarkersHook : Hook<5> 150 | { 151 | // In AE `Compass::SetMarkers` is inlined in `Compass::Update` 152 | static std::uintptr_t Address() { return REL::Module::IsAE() ? Compass::Update.address() + 0x128 : Compass::SetMarkers.address() + 0x10F; } 153 | 154 | SetCompassMarkersHook(std::uintptr_t a_hookedAddress) : 155 | Hook{ a_hookedAddress, reinterpret_cast(&SetCompassMarkers) } 156 | {} 157 | }; 158 | 159 | UpdateQuestsHook updateQuestsHook{ UpdateQuestsHook::Address() }; 160 | AllowedToShowMapMarkerHook allowedToShowMapMarkerHook[2] = { AllowedToShowMapMarkerHook::Address1(), AllowedToShowMapMarkerHook::Address2() }; 161 | UpdateLocationsHook updateLocationsHook{ UpdateLocationsHook::Address() }; 162 | UpdateEnemiesHook updateEnemiesHook{ UpdateEnemiesHook::Address() }; 163 | UpdatePlayerSetMarkerHook updatePlayerSetMarkerHook{ UpdatePlayerSetMarkerHook::Address() }; 164 | SetCompassMarkersHook setCompassMarkersHook{ SetCompassMarkersHook::Address() }; 165 | 166 | // The destination of the hook for `AllowedToShowMapMarker` is the same, 167 | // so we need to allocate memory for it only once 168 | static DefaultTrampoline defaultTrampoline{ updateQuestsHook.getSize() + allowedToShowMapMarkerHook->getSize() + 169 | updateLocationsHook.getSize() + updateEnemiesHook.getSize() + 170 | updatePlayerSetMarkerHook.getSize() + setCompassMarkersHook.getSize() }; 171 | 172 | defaultTrampoline.write_branch(updateQuestsHook); 173 | defaultTrampoline.write_call(allowedToShowMapMarkerHook[0]); 174 | defaultTrampoline.write_call(allowedToShowMapMarkerHook[1]); 175 | defaultTrampoline.write_call(updateLocationsHook); 176 | defaultTrampoline.write_call(updateEnemiesHook); 177 | defaultTrampoline.write_call(updatePlayerSetMarkerHook); 178 | defaultTrampoline.write_call(setCompassMarkersHook); 179 | } 180 | 181 | namespace compat 182 | { 183 | class MapMarkerFramework 184 | { 185 | public: 186 | 187 | static RE::GFxMovieDef* GetCompassMovieDef(); 188 | 189 | static inline void Install(SKSE::WinAPI::HMODULE a_moduleHandle) 190 | { 191 | std::uintptr_t getCompassMovieDefHookAddress = SigScanner::FindPattern 192 | < 193 | "4C 8B F1 " // mov r14, rcx 194 | "48 8B 02 " // mov rax, [rdx] 195 | "48 8B CA " // mov rcx, rdx <- We want this address (offset 6) 196 | "FF 50 08 " // call qword ptr [rax+8] 197 | "?? 8B ?? " // mov ??, rax 198 | "48 85 C0" // test rax, rax 199 | >(a_moduleHandle) + 6; 200 | 201 | // `ImportManager::SetupHUDMenu` call to a_movieView->GetMovieDef() 202 | struct GetCompassMovieDefHook : Hook<6> 203 | { 204 | GetCompassMovieDefHook(std::uintptr_t a_hookedAddress) : 205 | Hook{ a_hookedAddress, reinterpret_cast(&GetCompassMovieDef) } 206 | {} 207 | }; 208 | 209 | GetCompassMovieDefHook getCompassMovieDefHook{ getCompassMovieDefHookAddress }; 210 | 211 | static CustomTrampoline mapMarkerFrameworkTrampoline{ "MapMarkerFramework Trampoline", a_moduleHandle, 212 | getCompassMovieDefHook.getSize() }; 213 | 214 | mapMarkerFrameworkTrampoline.write_call(getCompassMovieDefHook); 215 | } 216 | 217 | static inline const SKSE::PluginInfo* pluginInfo = nullptr; 218 | static inline RE::GFxMovieDef* compassMovieDef = nullptr; 219 | }; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /include/RE/G/GFxMovieDataDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RE/G/GAtomic.h" 4 | #include "RE/G/GFxLoadUpdateSync.h" 5 | #include "RE/G/GFxResourceReport.h" 6 | #include "RE/G/GFxTimelineDef.h" 7 | #include "RE/G/GHashSet.h" 8 | #include "RE/G/GHashUncached.h" 9 | #include "RE/G/GRefCountBase.h" 10 | #include "RE/G/GStringHash.h" 11 | 12 | namespace RE 13 | { 14 | class GFxLog; 15 | class GFxPathAllocator; 16 | class GFxFrameBindData; 17 | class GFxFontDataUseNode; 18 | class GFxResourceDataNode; 19 | 20 | class GFxExporterInfo 21 | { 22 | public: 23 | 24 | enum ExportFlagConstants 25 | { 26 | kGlyphTexturesExported = 0x01, 27 | kGradientTexturesExported = 0x02, 28 | kGlyphsStripped = 0x10 29 | }; 30 | 31 | GFxFileConstants::FileFormatType format; // 00 32 | std::uint32_t pad04; // 04 33 | const char* pPrefix; // 08 34 | const char* pSwfName; // 10 35 | std::uint16_t version; // 18 36 | std::uint16_t pad1A; // 1A 37 | stl::enumeration exportFlags; // 1C 38 | }; 39 | static_assert(sizeof(GFxExporterInfo) == 0x20); 40 | 41 | class GFxExporterInfoImpl : GFxExporterInfo 42 | { 43 | GString prefix; // 20 44 | GString swfName; // 28 45 | GArray codeOffsets; // 30 46 | }; 47 | static_assert(sizeof(GFxExporterInfoImpl) == 0x48); 48 | 49 | class GFxResourceHandle 50 | { 51 | enum HandleType 52 | { 53 | kPointer, 54 | kIndex 55 | }; 56 | 57 | HandleType HType; 58 | union 59 | { 60 | unsigned BindIndex; 61 | GFxResource* pResource; 62 | }; 63 | }; 64 | 65 | class GFxDataAllocator 66 | { 67 | public: 68 | void* Alloc(UPInt a_size) 69 | { 70 | if (a_size > 0xFF8) { 71 | auto newBlock = static_cast(heap->Alloc(a_size + 8, 0)); 72 | if (!newBlock) { 73 | return nullptr; 74 | } 75 | 76 | newBlock[0] = lastBlock; 77 | lastBlock = newBlock; 78 | 79 | return &newBlock[1]; 80 | } 81 | 82 | if (a_size > memAvailable) { 83 | auto newBlock = static_cast(heap->Alloc(0x1FF8, 0)); 84 | if (!newBlock) { 85 | return nullptr; 86 | } 87 | 88 | newBlock[0] = lastBlock; 89 | lastBlock = newBlock; 90 | 91 | allocPtr = &newBlock[1]; 92 | memAvailable = 0x1FF0; 93 | } 94 | 95 | auto memPtr = allocPtr; 96 | 97 | memAvailable -= a_size; 98 | allocPtr = static_cast(allocPtr) + a_size; 99 | 100 | return memPtr; 101 | } 102 | 103 | template 104 | T* Alloc() 105 | { 106 | return static_cast(Alloc(sizeof(T))); 107 | } 108 | 109 | void Free() 110 | { 111 | const auto globalHeap = GMemory::GetGlobalHeap(); 112 | void* block = lastBlock; 113 | while (block) { 114 | globalHeap->Free(block); 115 | block = static_cast(block)[0]; 116 | } 117 | } 118 | 119 | // members 120 | void* allocPtr; // 00 121 | std::uint64_t memAvailable; // 08 122 | void* lastBlock; // 10 123 | GMemoryHeap* heap; // 18 124 | }; 125 | 126 | struct GFxMovieHeaderData 127 | { 128 | std::uint32_t fileLength; // 00 129 | std::uint32_t version; // 04 130 | GRectF frameRect; // 08 131 | float frameRate; // 18 132 | std::uint32_t frameCount; // 1C 133 | std::uint32_t swfFlags; // 20 134 | GFxExporterInfoImpl exporterInfo; // 24 135 | }; 136 | static_assert(sizeof(GFxMovieHeaderData) == 0x70); 137 | 138 | struct GFxResourceSource 139 | { 140 | enum SourceType : std::int32_t 141 | { 142 | kNormal, 143 | kImported, 144 | }; 145 | 146 | struct ImportSource 147 | { 148 | std::uint32_t index; 149 | std::uint32_t unk04; 150 | }; 151 | 152 | union ResourceUnion 153 | { 154 | GFxResource* resource; 155 | ImportSource importSource; 156 | }; 157 | 158 | SourceType type; // 00 159 | std::uint32_t pad04; // 04 160 | ResourceUnion data; // 08 161 | }; 162 | static_assert(sizeof(GFxResourceSource) == 0x10); 163 | 164 | struct GFxImportNode 165 | { 166 | struct ImportAssetInfo 167 | { 168 | GString name; // 00 169 | std::uint32_t id; // 08 170 | std::uint32_t importIndex; // 0C 171 | }; 172 | static_assert(sizeof(ImportAssetInfo) == 0x10); 173 | 174 | GArray assets; // 00 175 | GString filename; // 18 176 | std::uint32_t frame; // 20 177 | std::uint32_t movieIndex; // 24 178 | GFxImportNode* nextInChain; // 28 179 | }; 180 | static_assert(sizeof(GFxImportNode) == 0x30); 181 | 182 | class GFxMovieDataDef : 183 | public GFxTimelineDef, // 00 184 | public GFxResourceReport // 20 185 | { 186 | public: 187 | enum MovieDataType 188 | { 189 | kEmpty, // No data, empty clip - useful for LoadVars into new level 190 | kFlash, // SWF or GFX file 191 | kImage // An image file 192 | }; 193 | 194 | class DefBindingData 195 | { 196 | public: 197 | 198 | GFxFrameBindData* frameData; // 00 - GAtomicPtr 199 | GFxFrameBindData* frameDataLast; // 08 200 | GFxImportNode* imports; // 10 - GAtomicPtr 201 | GFxImportNode* importsLast; // 18 202 | GFxFontDataUseNode* fonts; // 20 - GAtomicPtr 203 | GFxFontDataUseNode* fontsLast; // 28 204 | GFxResourceDataNode* resourceNodes; // 30 - GAtomicPtr 205 | GFxResourceDataNode* resourceNodesLast; // 38 206 | }; 207 | static_assert(sizeof(DefBindingData) == 0x40); 208 | 209 | enum MovieLoadState 210 | { 211 | kUninitialized, 212 | kLoadingFrames, 213 | kLoadFinished, 214 | kLoadCanceled, // Canceled by user 215 | kLoadError 216 | }; 217 | 218 | class LoadTaskDataBase : public GRefCountBase 219 | { 220 | public: 221 | // members 222 | GFxDataAllocator tagMemAllocator; // 10 223 | GFxPathAllocator* pathAllocator; // 30 224 | }; 225 | static_assert(sizeof(LoadTaskDataBase) == 0x38); 226 | 227 | class LoadTaskData : public LoadTaskDataBase 228 | { 229 | public: 230 | using ResourceHash = GHashUncached; 231 | 232 | ~LoadTaskData() override; // 00 233 | 234 | // add 235 | virtual void AddFrameName(const GString& a_label, GFxLog* a_log); // 01 236 | virtual void SetLoadingPlaylistFrame(const Frame& a_frame); // 02 237 | virtual void SetLoadingInitActionFrame(const Frame& a_frame); // 03 238 | 239 | // members 240 | GMemoryHeap* loadDataHeap; // 038 241 | GPtr imageHeap; // 040 242 | GString fileURL; // 048 243 | GFxMovieHeaderData header; // 050 244 | std::uint32_t fileAttributes; // 0C0 245 | std::uint32_t padC4; // 0C4 246 | void* metadata; // 0C8 247 | std::uint32_t metadataSize; // 0D0 248 | stl::enumeration loadState; // 0D4 249 | std::int32_t loadingFrame; // 0D8 250 | bool loadingCancelled; // 0DC 251 | std::uint8_t padDD; // 0DD 252 | std::uint16_t padDE; // 0DE 253 | std::uint32_t tagCount; // 0E0 254 | std::uint32_t padE4; // 0E4 255 | GPtr frameUpdate; // 0E8 256 | DefBindingData bindData; // 0F0 257 | std::uint32_t importedResourceIndexCounter; // 130 258 | std::uint32_t pad134; // 134 259 | GLock resourceLock; // 138 260 | ResourceHash resources; // 160 261 | GStringHash exports; // 168 262 | GHash> inverseExportsMap; // 170 263 | GLock playlistLock; // 178 264 | GArrayLH playlist; // 1A0 265 | GArrayLH initActionList; // 1B8 266 | std::int32_t initActionsCount; // 1D0 267 | std::uint32_t pad1D4; // 1D4 268 | GStringHash namedFrames; // 1D8 269 | std::uint64_t unk1E0; // 1E0 270 | }; 271 | static_assert(sizeof(LoadTaskData) == 0x1E8); 272 | 273 | ~GFxMovieDataDef() override; // 00 274 | 275 | // override (GFxResource) 276 | GFxResourceKey GetKey() override; // 01 277 | std::uint32_t GetResourceTypeCode() const override; // 02 278 | GFxResourceReport* GetResourceReport() override; // 03 279 | 280 | // override (GFxCharacterDef) 281 | std::uint32_t GetVersion() const override; // 08 282 | 283 | // override (GFxTimelineDef) 284 | std::uint32_t GetFrameCount() const override; // 0A 285 | const Frame GetPlayList(std::int32_t a_frameNumber) const override; // 0B 286 | bool GetInitActions(Frame* a_frame, std::int32_t a_frameNumber) const override; // 0C 287 | bool GetLabeledFrame(const char* a_label, std::uint32_t* a_frameNumber, bool a_translateNumbers) override; // 0D 288 | 289 | // add 290 | virtual std::uint32_t GetLoadingFrame() const; // 0E 291 | virtual std::uint32_t GetSWFFlags(); // 0F 292 | 293 | // members 294 | GFxResourceKey resourceKey; // 28 295 | stl::enumeration fileFormat; // 38 296 | std::uint32_t pad3C; // 3C 297 | GPtr loadTaskData; // 40 298 | }; 299 | static_assert(sizeof(GFxMovieDataDef) == 0x48); 300 | } 301 | --------------------------------------------------------------------------------