From 7c0b194b1cdc2304df9306e20c800d16ca5ab341 Mon Sep 17 00:00:00 2001 From: Leonid Pospelov Date: Wed, 10 Apr 2024 20:48:13 +0500 Subject: [PATCH] perf: optimize SpSnippet (#1911) --- .../src/services/services/spSnippetService.ts | 5 +++++ .../cpp/server_guest_lib/MpActor.cpp | 2 +- .../cpp/server_guest_lib/SpSnippet.cpp | 6 ++++-- .../cpp/server_guest_lib/SpSnippet.h | 8 ++++++- .../server_guest_lib/SpSnippetFunctionGen.h | 7 +++++-- .../cpp/server_guest_lib/SweetPieScript.cpp | 8 ++++--- .../script_classes/PapyrusActor.cpp | 15 ++++++------- .../script_classes/PapyrusDebug.cpp | 3 ++- .../script_classes/PapyrusEffectShader.cpp | 4 ++-- .../script_classes/PapyrusGame.cpp | 8 ++++--- .../script_classes/PapyrusNetImmerse.cpp | 4 ++-- .../script_classes/PapyrusObjectReference.cpp | 21 ++++++++++--------- .../script_classes/PapyrusSound.cpp | 2 +- unit/ConsoleCommandTest.cpp | 2 +- unit/PapyrusDebugTest.cpp | 4 ++-- 15 files changed, 61 insertions(+), 38 deletions(-) diff --git a/skymp5-client/src/services/services/spSnippetService.ts b/skymp5-client/src/services/services/spSnippetService.ts index 8ff3c587bc..2638f0c6a9 100644 --- a/skymp5-client/src/services/services/spSnippetService.ts +++ b/skymp5-client/src/services/services/spSnippetService.ts @@ -21,6 +21,11 @@ export class SpSnippetService extends ClientListener { this.controller.once('update', async () => { this.run(msg) .then((res) => { + const isNoResultSnippet = msg.snippetIdx === 0xffffffff; + if (isNoResultSnippet) { + return; + } + if (res === undefined) { res = null; } diff --git a/skymp5-server/cpp/server_guest_lib/MpActor.cpp b/skymp5-server/cpp/server_guest_lib/MpActor.cpp index b2ea112773..1d247b96d7 100644 --- a/skymp5-server/cpp/server_guest_lib/MpActor.cpp +++ b/skymp5-server/cpp/server_guest_lib/MpActor.cpp @@ -368,7 +368,7 @@ bool MpActor::OnEquip(uint32_t baseId) auto targetRefr = dynamic_cast(listener); if (targetRefr && targetRefr != this) { SpSnippet("Actor", "EquipItem", serializedArgs.data(), GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } else if (isBook) { diff --git a/skymp5-server/cpp/server_guest_lib/SpSnippet.cpp b/skymp5-server/cpp/server_guest_lib/SpSnippet.cpp index a9f99b4417..206c6436a9 100644 --- a/skymp5-server/cpp/server_guest_lib/SpSnippet.cpp +++ b/skymp5-server/cpp/server_guest_lib/SpSnippet.cpp @@ -12,7 +12,7 @@ SpSnippet::SpSnippet(const char* cl_, const char* func_, const char* args_, { } -Viet::Promise SpSnippet::Execute(MpActor* actor) +Viet::Promise SpSnippet::Execute(MpActor* actor, SpSnippetMode mode) { auto worldState = actor->GetParent(); if (!actor->IsCreatedAsPlayer()) { @@ -24,7 +24,9 @@ Viet::Promise SpSnippet::Execute(MpActor* actor) Viet::Promise promise; - auto snippetIdx = actor->NextSnippetIndex(promise); + const uint32_t snippetIdx = mode == SpSnippetMode::kReturnResult + ? actor->NextSnippetIndex(promise) + : std::numeric_limits::max(); // Player character is always 0x14 on client, but 0xff000000+ in our server // See also SpSnippetFunctionGen.cpp diff --git a/skymp5-server/cpp/server_guest_lib/SpSnippet.h b/skymp5-server/cpp/server_guest_lib/SpSnippet.h index ff39b3bb74..4ebd0ce437 100644 --- a/skymp5-server/cpp/server_guest_lib/SpSnippet.h +++ b/skymp5-server/cpp/server_guest_lib/SpSnippet.h @@ -6,13 +6,19 @@ class MpActor; +enum class SpSnippetMode +{ + kNoReturnResult, + kReturnResult, +}; + class SpSnippet { public: SpSnippet(const char* cl_, const char* func_, const char* args_, uint32_t selfId_ = 0); - Viet::Promise Execute(MpActor* actor); + Viet::Promise Execute(MpActor* actor, SpSnippetMode mode); private: const char *const cl, *const func, *const args; diff --git a/skymp5-server/cpp/server_guest_lib/SpSnippetFunctionGen.h b/skymp5-server/cpp/server_guest_lib/SpSnippetFunctionGen.h index 91a84bdf3a..481be00b4c 100644 --- a/skymp5-server/cpp/server_guest_lib/SpSnippetFunctionGen.h +++ b/skymp5-server/cpp/server_guest_lib/SpSnippetFunctionGen.h @@ -14,17 +14,20 @@ class SpSnippetFunctionGen static uint32_t GetFormId(VarValue varValue); }; +// TODO: unhardcode mode #define DEFINE_STATIC_SPSNIPPET(name) \ VarValue name(VarValue self, const std::vector& arguments) \ { \ if (auto actor = compatibilityPolicy->GetDefaultActor( \ GetName(), #name, self.GetMetaStackId())) { \ auto s = SpSnippetFunctionGen::SerializeArguments(arguments, actor); \ - SpSnippet(GetName(), (#name), s.data()).Execute(actor); \ + SpSnippet(GetName(), (#name), s.data()) \ + .Execute(actor, SpSnippetMode::kNoReturnResult); \ } \ return VarValue::None(); \ } +// TODO: unhardcode mode #define DEFINE_METHOD_SPSNIPPET(name) \ VarValue name(VarValue self, const std::vector& arguments) \ { \ @@ -33,7 +36,7 @@ class SpSnippetFunctionGen auto s = SpSnippetFunctionGen::SerializeArguments(arguments, actor); \ auto promise = SpSnippet(GetName(), (#name), s.data(), \ SpSnippetFunctionGen::GetFormId(self)) \ - .Execute(actor); \ + .Execute(actor, SpSnippetMode::kReturnResult); \ return VarValue(promise); \ } \ \ diff --git a/skymp5-server/cpp/server_guest_lib/SweetPieScript.cpp b/skymp5-server/cpp/server_guest_lib/SweetPieScript.cpp index 8ef5d577f9..f27412acb3 100644 --- a/skymp5-server/cpp/server_guest_lib/SweetPieScript.cpp +++ b/skymp5-server/cpp/server_guest_lib/SweetPieScript.cpp @@ -157,7 +157,8 @@ void SweetPieScript::Notify(MpActor& actor, const WorldState& worldState, << (static_cast(silent) ? "true" : "false"); ss << "]"; std::string args = ss.str(); - (void)SpSnippet("SkympHacks", "AddItem", args.data()).Execute(&actor); + (void)SpSnippet("SkympHacks", "AddItem", args.data()) + .Execute(&actor, SpSnippetMode::kNoReturnResult); } void SweetPieScript::Play(MpActor& actor, WorldState& worldState, @@ -242,8 +243,9 @@ void SweetPieScript::EquipItem(MpActor& actor, uint32_t baseId, std::string args = ss.str(); spdlog::info("Equipping item: {}", args); SpSnippet("Actor", "EquipItem", args.data(), actor.GetFormId()) - .Execute(&actor); + .Execute(&actor, SpSnippetMode::kNoReturnResult); if (!isShield && !isArrow) { - SpSnippet("Actor", "DrawWeapon", "[]", actor.GetFormId()).Execute(&actor); + SpSnippet("Actor", "DrawWeapon", "[]", actor.GetFormId()) + .Execute(&actor, SpSnippetMode::kNoReturnResult); } } diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusActor.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusActor.cpp index bf5d55424d..4c951283c2 100644 --- a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusActor.cpp +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusActor.cpp @@ -67,7 +67,8 @@ VarValue PapyrusActor::SetActorValue(VarValue self, actor->GetFormId()) .Execute(it == actor->GetParent()->hosters.end() ? actor - : &actor->GetParent()->GetFormAt(it->second)); + : &actor->GetParent()->GetFormAt(it->second), + SpSnippetMode::kNoReturnResult); } return VarValue(); } @@ -171,7 +172,7 @@ VarValue PapyrusActor::SetAlpha(VarValue self, if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data(), selfRefr->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } @@ -219,7 +220,7 @@ VarValue PapyrusActor::EquipItem(VarValue self, SpSnippet(GetName(), "EquipItem", SpSnippetFunctionGen::SerializeArguments(arguments).data(), actor->GetFormId()) - .Execute(actor); + .Execute(actor, SpSnippetMode::kNoReturnResult); } return VarValue::None(); } @@ -235,7 +236,7 @@ VarValue PapyrusActor::UnequipItem(VarValue self, SpSnippet(GetName(), "UnequipItem", SpSnippetFunctionGen::SerializeArguments(arguments).data(), actor->GetFormId()) - .Execute(actor); + .Execute(actor, SpSnippetMode::kNoReturnResult); } return VarValue::None(); } @@ -250,7 +251,7 @@ VarValue PapyrusActor::SetDontMove(VarValue self, SpSnippet(GetName(), "SetDontMove", SpSnippetFunctionGen::SerializeArguments(arguments).data(), actor->GetFormId()) - .Execute(actor); + .Execute(actor, SpSnippetMode::kNoReturnResult); } return VarValue::None(); } @@ -336,7 +337,7 @@ VarValue PapyrusActor::AddSpell(VarValue self, SpSnippet(GetName(), "AddSpell", SpSnippetFunctionGen::SerializeArguments(arguments).data(), actor->GetFormId()) - .Execute(actor); + .Execute(actor, SpSnippetMode::kNoReturnResult); return VarValue(true); } @@ -380,7 +381,7 @@ VarValue PapyrusActor::RemoveSpell(VarValue self, SpSnippet(GetName(), "RemoveSpell", SpSnippetFunctionGen::SerializeArguments(arguments).data(), actor->GetFormId()) - .Execute(actor); + .Execute(actor, SpSnippetMode::kNoReturnResult); return VarValue(true); } diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusDebug.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusDebug.cpp index ba9a1ba896..74afca3a81 100644 --- a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusDebug.cpp +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusDebug.cpp @@ -10,7 +10,8 @@ VarValue PapyrusDebug::SendAnimationEvent( if (targetActor) { auto funcName = "SendAnimationEvent"; auto s = SpSnippetFunctionGen::SerializeArguments(arguments, targetActor); - SpSnippet(GetName(), funcName, s.data()).Execute(targetActor); + SpSnippet(GetName(), funcName, s.data()) + .Execute(targetActor, SpSnippetMode::kNoReturnResult); } return VarValue::None(); } diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusEffectShader.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusEffectShader.cpp index 0cb3d45025..d22a211d4d 100644 --- a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusEffectShader.cpp +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusEffectShader.cpp @@ -38,14 +38,14 @@ void PapyrusEffectShader::Helper(VarValue& self, const char* funcName, SpSnippetFunctionGen::SerializeArguments(arguments, targetRefr) .data(), selfRec.ToGlobalId(selfRec.rec->GetId())) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); // Workaround to use this function on player clone if (actorForm->GetFormId() == targetRefr->GetFormId()) { SpSnippet( GetName(), funcName, SpSnippetFunctionGen::SerializeArguments(arguments).data(), selfRec.ToGlobalId(selfRec.rec->GetId())) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusGame.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusGame.cpp index b0839939fc..9dedfe4611 100644 --- a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusGame.cpp +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusGame.cpp @@ -100,7 +100,7 @@ VarValue PapyrusGame::GetCameraState(VarValue self, GetName(), "GetCameraState", self.GetMetaStackId())) { Viet::Promise promise = SpSnippet(GetName(), "GetCameraState", serializedArgs.data()) - .Execute(actor); + .Execute(actor, SpSnippetMode::kReturnResult); return VarValue(Viet::Promise(promise)); } return VarValue(-1); @@ -113,7 +113,8 @@ void PapyrusGame::RaceMenuHelper(VarValue& self, const char* funcName, if (auto actor = compatibilityPolicy->GetDefaultActor( GetName(), funcName, self.GetMetaStackId())) { actor->SetRaceMenuOpen(true); - SpSnippet(GetName(), funcName, serializedArgs.data()).Execute(actor); + SpSnippet(GetName(), funcName, serializedArgs.data()) + .Execute(actor, SpSnippetMode::kNoReturnResult); } } @@ -163,7 +164,8 @@ VarValue PapyrusGame::ShakeController(VarValue self, auto serializedArgs = SpSnippetFunctionGen::SerializeArguments(arguments); if (auto actor = compatibilityPolicy->GetDefaultActor( GetName(), funcName, self.GetMetaStackId())) { - SpSnippet(GetName(), funcName, serializedArgs.data()).Execute(actor); + SpSnippet(GetName(), funcName, serializedArgs.data()) + .Execute(actor, SpSnippetMode::kNoReturnResult); } return VarValue::None(); diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusNetImmerse.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusNetImmerse.cpp index 9a0730e0f9..7db30675ba 100644 --- a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusNetImmerse.cpp +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusNetImmerse.cpp @@ -35,7 +35,7 @@ VarValue PapyrusNetImmerse::SetNodeTextureSet( auto targetRefr = dynamic_cast(listener); if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } @@ -70,7 +70,7 @@ VarValue PapyrusNetImmerse::SetNodeScale( auto targetRefr = dynamic_cast(listener); if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusObjectReference.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusObjectReference.cpp index 3e60063345..534373f1ac 100644 --- a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusObjectReference.cpp +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusObjectReference.cpp @@ -165,7 +165,8 @@ VarValue PapyrusObjectReference::AddItem( if (!silent && count > 0) { if (auto actor = dynamic_cast(selfRefr)) { auto args = SpSnippetFunctionGen::SerializeArguments(arguments); - (void)SpSnippet("SkympHacks", "AddItem", args.data()).Execute(actor); + (void)SpSnippet("SkympHacks", "AddItem", args.data()) + .Execute(actor, SpSnippetMode::kNoReturnResult); } } } @@ -251,7 +252,7 @@ VarValue PapyrusObjectReference::RemoveItem( if (auto actor = dynamic_cast(selfRefr)) { auto args = SpSnippetFunctionGen::SerializeArguments(arguments); (void)SpSnippet("SkympHacks", "RemoveItem", args.data()) - .Execute(actor); + .Execute(actor, SpSnippetMode::kNoReturnResult); } } } @@ -316,7 +317,7 @@ void PlaceAtMeSpSnippet(MpObjectReference* self, if (targetRefr) { SpSnippet("ObjectReference", funcName, serializedArgs.data(), self->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } @@ -414,7 +415,7 @@ VarValue PapyrusObjectReference::Enable(VarValue self, if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data(), selfRefr->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } @@ -438,7 +439,7 @@ VarValue PapyrusObjectReference::Disable( if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data(), selfRefr->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } @@ -551,7 +552,7 @@ VarValue PapyrusObjectReference::SetPosition( if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data(), selfRefr->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } @@ -593,7 +594,7 @@ VarValue PapyrusObjectReference::PlayAnimation( if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data(), selfRefr->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } @@ -621,7 +622,7 @@ VarValue PapyrusObjectReference::PlayAnimationAndWait( if (targetRefr) { auto promise = SpSnippet(GetName(), funcName, serializedArgs.data(), selfRefr->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kReturnResult); promises.push_back(promise); } } @@ -663,7 +664,7 @@ VarValue PapyrusObjectReference::PlayGamebryoAnimation( if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data(), selfRefr->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } @@ -867,7 +868,7 @@ VarValue PapyrusObjectReference::SetDisplayName( if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data(), selfRefr->GetFormId()) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } diff --git a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusSound.cpp b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusSound.cpp index edd7b4e133..4e786a39d8 100644 --- a/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusSound.cpp +++ b/skymp5-server/cpp/server_guest_lib/script_classes/PapyrusSound.cpp @@ -25,7 +25,7 @@ VarValue PapyrusSound::Play(VarValue self, auto targetRefr = dynamic_cast(listener); if (targetRefr) { SpSnippet(GetName(), funcName, serializedArgs.data(), selfId) - .Execute(targetRefr); + .Execute(targetRefr, SpSnippetMode::kNoReturnResult); } } } diff --git a/unit/ConsoleCommandTest.cpp b/unit/ConsoleCommandTest.cpp index 1d9da71762..426ff70f49 100644 --- a/unit/ConsoleCommandTest.cpp +++ b/unit/ConsoleCommandTest.cpp @@ -105,7 +105,7 @@ TEST_CASE("AddItem executes", "[ConsoleCommand][espm]") REQUIRE( p.Messages()[1].j == nlohmann::json::parse( - R"({"arguments":[{"formId":77495,"type":"weapon"},264,false],"class":"SkympHacks","function":"AddItem","selfId":0,"snippetIdx":0,"type":"spSnippet"})")); + R"({"arguments":[{"formId":77495,"type":"weapon"},264,false],"class":"SkympHacks","function":"AddItem","selfId":0,"snippetIdx":4294967295,"type":"spSnippet"})")); p.DestroyActor(0xff000000); DoDisconnect(p, 0); diff --git a/unit/PapyrusDebugTest.cpp b/unit/PapyrusDebugTest.cpp index 2ce58344ac..4684f79289 100644 --- a/unit/PapyrusDebugTest.cpp +++ b/unit/PapyrusDebugTest.cpp @@ -37,7 +37,7 @@ TEST_CASE("Notification", "[Papyrus][Debug]") REQUIRE(p.Messages()[1].reliable); REQUIRE(p.Messages()[1].j == nlohmann::json{ { "type", "spSnippet" }, - { "snippetIdx", 0 }, + { "snippetIdx", 4294967295 }, { "selfId", 0 }, { "class", "debug" }, { "function", "Notification" }, @@ -46,7 +46,7 @@ TEST_CASE("Notification", "[Papyrus][Debug]") REQUIRE(p.Messages()[2].reliable); REQUIRE(p.Messages()[2].j == nlohmann::json{ { "type", "spSnippet" }, - { "snippetIdx", 1 }, + { "snippetIdx", 4294967295 }, { "selfId", 0 }, { "class", "debug" }, { "function", "Notification" },