#pragma once #include struct TESForm; struct TESObjectREFR; struct PapyrusFunctionRegisterEvent; /** * @brief Handles registering and executing Papyrus functions. */ struct PapyrusService { PapyrusService(entt::dispatcher& aDispatcher) noexcept; ~PapyrusService() noexcept = default; TP_NOCOPYMOVE(PapyrusService); const void* Get(const String& acNamespace, const String& acFunction) const noexcept; void HandlePapyrusFunctionEvent(const PapyrusFunctionRegisterEvent&) noexcept; private: Map m_functions; entt::scoped_connection m_papyrusFunctionRegisterConnection; }; template struct PapyrusFunction { using TFunction = Return(__fastcall*)(BSScript::IVirtualMachine*, uint32_t, const Type*, Args...); PapyrusFunction(const void* apAddress) : m_pFunction(reinterpret_cast(apAddress)) { } Return operator()(const Type* apThis, Args... args) const noexcept { return m_pFunction(GameVM::Get()->virtualMachine, 0, apThis, std::forward(args)...); } private: TFunction m_pFunction; }; template struct GlobalPapyrusFunction { using TFunction = Return(__fastcall*)(BSScript::IVirtualMachine*, Args...); GlobalPapyrusFunction(const void* apAddress) : m_pFunction(reinterpret_cast(apAddress)) { } Return operator()(Args... args) const noexcept { return m_pFunction(GameVM::Get()->virtualMachine, std::forward(args)...); } private: TFunction m_pFunction; }; struct RefrOrInventoryObj { const TESObjectREFR* pRefr; TESForm* pInventoryForm; uint16_t itemCount; }; template struct LatentPapyrusFunction { using TFunction = Return(__fastcall*)(BSScript::IVirtualMachine*, uint32_t, const RefrOrInventoryObj&, Args...); LatentPapyrusFunction(const void* apAddress) : m_pFunction(reinterpret_cast(apAddress)) { } Return operator()(const Type* apThis, Args... args) const noexcept { RefrOrInventoryObj self{apThis, nullptr, 0}; return m_pFunction(GameVM::Get()->virtualMachine, 0, self, std::forward(args)...); } private: TFunction m_pFunction; }; #define PAPYRUS_FUNCTION(returnType, scope, name, ...) static PapyrusFunction s_p##name(World::Get().ctx().at().Get(#scope, #name)); #define GLOBAL_PAPYRUS_FUNCTION(returnType, scope, name, ...) static GlobalPapyrusFunction s_p##name(World::Get().ctx().at().Get(#scope, #name)); #define LATENT_PAPYRUS_FUNCTION(returnType, scope, name, ...) static LatentPapyrusFunction s_p##name(World::Get().ctx().at().Get(#scope, #name));