From e1235f0fb817a771ec94c9e03cd11d0c5beff0ba Mon Sep 17 00:00:00 2001 From: Leonid Pospelov Date: Mon, 9 Dec 2024 18:53:00 +0500 Subject: [PATCH] feat(skymp5-server): add Quest.GetStage stub & disable some bad scripts (#2256) --- .../server_guest_lib/MpObjectReference.cpp | 18 +++++++++ .../script_classes/PapyrusClassesFactory.cpp | 2 + .../script_classes/PapyrusQuest.cpp | 37 +++++++++++++++++++ .../script_classes/PapyrusQuest.h | 20 ++++++++++ 4 files changed, 77 insertions(+) create mode 100644 skymp5-server/cpp/server_guest_lib/script_classes/PapyrusQuest.cpp create mode 100644 skymp5-server/cpp/server_guest_lib/script_classes/PapyrusQuest.h diff --git a/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp b/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp index 86df17e5eb..2b906f6aa4 100644 --- a/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp +++ b/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp @@ -1689,6 +1689,7 @@ void MpObjectReference::InitScripts() // A hardcoded hack to remove all scripts except SweetPie scripts from // exterior objects + // TODO: make is a server setting with proper conditions or an API if (GetParent() && GetParent()->disableVanillaScriptsInExterior && GetFormId() < 0x05000000) { auto cellOrWorld = GetCellOrWorld().ToFormId(GetParent()->espmFiles); @@ -1708,6 +1709,23 @@ void MpObjectReference::InitScripts() } } + // A hardcoded hack to remove unsupported scripts + // TODO: make is a server setting with proper conditions or an API + auto isScriptEraseNeeded = [](const std::string& val) { + // 1. GetStage in OnTrigger + // 2. Unable to determine Actor for 'Game.GetPlayer' in 'OnLoad' + const bool isRemoveNeeded = + !Utils::stricmp(val.data(), "DA06PreRitualSceneTriggerScript") || + !Utils::stricmp(val.data(), "CritterSpawn"); + + spdlog::info("Skipping script {}", val); + + return isRemoveNeeded; + }; + scriptNames.erase(std::remove_if(scriptNames.begin(), scriptNames.end(), + isScriptEraseNeeded), + scriptNames.end()); + if (!scriptNames.empty()) { pImpl->scriptState = std::make_unique(); diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusClassesFactory.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusClassesFactory.cpp index 12731f64b8..6eb3e3bbb0 100644 --- a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusClassesFactory.cpp +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusClassesFactory.cpp @@ -13,6 +13,7 @@ #include "PapyrusNetImmerse.h" #include "PapyrusObjectReference.h" #include "PapyrusPotion.h" +#include "PapyrusQuest.h" #include "PapyrusSkymp.h" #include "PapyrusSound.h" #include "PapyrusUtility.h" @@ -42,6 +43,7 @@ PapyrusClassesFactory::CreateAndRegister( result.emplace_back(std::make_unique()); result.emplace_back(std::make_unique()); result.emplace_back(std::make_unique()); + result.emplace_back(std::make_unique()); for (auto& papyrusClass : result) { papyrusClass->Register(vm, compatibilityPolicy); diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusQuest.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusQuest.cpp new file mode 100644 index 0000000000..6d1ca7b79c --- /dev/null +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusQuest.cpp @@ -0,0 +1,37 @@ +#include "PapyrusQuest.h" +#include "script_objects/EspmGameObject.h" + +VarValue PapyrusQuest::GetStage(VarValue self, + const std::vector& arguments) +{ + return GetCurrentStageID(self, arguments); +} + +VarValue PapyrusQuest::GetCurrentStageID( + VarValue self, const std::vector& arguments) +{ + static std::once_flag g_flag; + + std::call_once(g_flag, [&] { + espm::CompressedFieldsCache cache; + + const auto& quest = GetRecordPtr(self); + const char* editorId = + quest.rec ? quest.rec->GetEditorId(cache) : ""; + + spdlog::warn( + "GetCurrentStageID - Not implemented, returning 0 (quest was {})", + editorId ? editorId : ""); + spdlog::warn("GetCurrentStageID - Won't output further warnings due to " + "performance reasons"); + }); + + return VarValue(0); +} + +void PapyrusQuest::Register( + VirtualMachine& vm, std::shared_ptr policy) +{ + AddMethod(vm, "GetStage", &PapyrusQuest::GetStage); + AddMethod(vm, "GetCurrentStageID", &PapyrusQuest::GetCurrentStageID); +} diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusQuest.h b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusQuest.h new file mode 100644 index 0000000000..08345e5e89 --- /dev/null +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusQuest.h @@ -0,0 +1,20 @@ +#pragma once +#include "IPapyrusClass.h" +#include "SpSnippetFunctionGen.h" + +class PapyrusQuest final : public IPapyrusClass +{ +public: + const char* GetName() override { return "Quest"; } + + // Non-native in original Papyrus, just a wrapper around GetCurrentStageID + VarValue GetStage(VarValue self, const std::vector& arguments); + + VarValue GetCurrentStageID(VarValue self, + const std::vector& arguments); + + void Register(VirtualMachine& vm, + std::shared_ptr policy) override; + + std::shared_ptr compatibilityPolicy; +};