From b5a603d0d7408d2e87422d6fbe65f59e55080b33 Mon Sep 17 00:00:00 2001 From: Roman Nikonov Date: Sat, 14 Dec 2024 14:20:15 +0300 Subject: [PATCH] perf(skymp5-server): avoid copying in DynamicFields.set (mp.set) (#2265) --- .../cpp/server_guest_lib/DynamicFields.cpp | 7 ++- .../cpp/server_guest_lib/DynamicFields.h | 8 +-- .../server_guest_lib/MpObjectReference.cpp | 51 +++++++++---------- .../cpp/server_guest_lib/MpObjectReference.h | 12 ++--- .../gamemode_events/RespawnEvent.cpp | 4 +- 5 files changed, 38 insertions(+), 44 deletions(-) diff --git a/skymp5-server/cpp/server_guest_lib/DynamicFields.cpp b/skymp5-server/cpp/server_guest_lib/DynamicFields.cpp index 73882ae629..2185e4070e 100644 --- a/skymp5-server/cpp/server_guest_lib/DynamicFields.cpp +++ b/skymp5-server/cpp/server_guest_lib/DynamicFields.cpp @@ -1,12 +1,11 @@ #include "DynamicFields.h" + #include -#include -void DynamicFields::Set(const std::string& propName, - const nlohmann::json& value) +void DynamicFields::Set(const std::string& propName, nlohmann::json value) { jsonCache.reset(); - props[propName] = value; + props[propName] = std::move(value); } const nlohmann::json& DynamicFields::Get(const std::string& propName) const diff --git a/skymp5-server/cpp/server_guest_lib/DynamicFields.h b/skymp5-server/cpp/server_guest_lib/DynamicFields.h index 8a3b578879..e21e286f2e 100644 --- a/skymp5-server/cpp/server_guest_lib/DynamicFields.h +++ b/skymp5-server/cpp/server_guest_lib/DynamicFields.h @@ -1,14 +1,14 @@ #pragma once -#include -#include -#include + #include #include +#include + class DynamicFields { public: - void Set(const std::string& propName, const nlohmann::json& value); + void Set(const std::string& propName, nlohmann::json value); const nlohmann::json& Get(const std::string& propName) const; const nlohmann::json& GetAsJson() const; diff --git a/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp b/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp index 2b906f6aa4..605855f3f2 100644 --- a/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp +++ b/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp @@ -6,6 +6,7 @@ #include "Inventory.h" #include "LeveledListUtils.h" #include "MathUtils.h" +#include "MessageBase.h" #include "MpActor.h" #include "MpChangeForms.h" #include "MsgType.h" @@ -13,6 +14,7 @@ #include "ScopedTask.h" #include "ScriptVariablesHolder.h" #include "TimeUtils.h" +#include "UpdatePropertyMessage.h" #include "WorldState.h" #include "gamemode_events/ActivateEvent.h" #include "gamemode_events/PutItemEvent.h" @@ -567,7 +569,9 @@ void MpObjectReference::SetHarvested(bool harvested) EditChangeForm([&](MpChangeFormREFR& changeForm) { changeForm.isHarvested = harvested; }); - SendPropertyToListeners("isHarvested", harvested); + SendMessageToActorListeners( + CreatePropertyMessage(this, "isHarvested", /*value=*/harvested), + /*reliable=*/true); } } @@ -576,7 +580,9 @@ void MpObjectReference::SetOpen(bool open) if (open != ChangeForm().isOpen) { EditChangeForm( [&](MpChangeFormREFR& changeForm) { changeForm.isOpen = open; }); - SendPropertyToListeners("isOpen", open); + SendMessageToActorListeners( + CreatePropertyMessage(this, "isOpen", /*value=*/open), + /*reliable=*/true); } } @@ -686,26 +692,28 @@ void MpObjectReference::UpdateHoster(uint32_t newHosterId) auto hostedMsg = CreatePropertyMessage(this, "isHostedByOther", true); auto notHostedMsg = CreatePropertyMessage(this, "isHostedByOther", false); for (auto listener : this->GetActorListeners()) { - this->SendPropertyTo( - newHosterId != 0 && newHosterId != listener->GetFormId() ? hostedMsg - : notHostedMsg, - *listener); + if (newHosterId != 0 && newHosterId != listener->GetFormId()) { + listener->SendToUser(hostedMsg, /*reliable=*/true); + } else { + listener->SendToUser(notHostedMsg, /*reliable=*/true); + } } } void MpObjectReference::SetProperty(const std::string& propertyName, - const nlohmann::json& newValue, + nlohmann::json newValue, bool isVisibleByOwner, bool isVisibleByNeighbor) { + auto msg = CreatePropertyMessage(this, propertyName.c_str(), newValue); EditChangeForm([&](MpChangeFormREFR& changeForm) { - changeForm.dynamicFields.Set(propertyName, newValue); + changeForm.dynamicFields.Set(propertyName, std::move(newValue)); }); if (isVisibleByNeighbor) { - SendPropertyToListeners(propertyName.data(), newValue); + SendMessageToActorListeners(msg, /*reliable=*/true); } else if (isVisibleByOwner) { if (auto ac = AsActor()) { - SendPropertyTo(propertyName.data(), newValue, *ac); + ac->SendToUser(msg, /*reliable=*/true); } } pImpl->setPropertyCalled = true; @@ -1449,7 +1457,9 @@ void MpObjectReference::ProcessActivateNormal( this->occupant->RemoveEventSink(this->occupantDestroySink); } SetOpen(true); - SendPropertyTo("inventory", GetInventory().ToJson(), *actorActivator); + actorActivator->SendToUser( + CreatePropertyMessage(this, "inventory", GetInventory().ToJson()), + /*reliable=*/true); activationSource.SendOpenContainer(GetFormId()); this->occupant = actorActivator; @@ -1935,29 +1945,14 @@ void MpObjectReference::CheckInteractionAbility(MpObjectReference& refr) } } -void MpObjectReference::SendPropertyToListeners(const char* name, - const nlohmann::json& value) +void MpObjectReference::SendMessageToActorListeners(const IMessageBase& msg, + bool reliable) const { - auto msg = CreatePropertyMessage(this, name, value); for (auto listener : GetActorListeners()) { listener->SendToUser(msg, true); } } -void MpObjectReference::SendPropertyTo(const char* name, - const nlohmann::json& value, - MpActor& target) -{ - auto msg = CreatePropertyMessage(this, name, value); - SendPropertyTo(msg, target); -} - -void MpObjectReference::SendPropertyTo(const IMessageBase& preparedPropMsg, - MpActor& target) -{ - target.SendToUser(preparedPropMsg, true); -} - void MpObjectReference::BeforeDestroy() { if (this->occupant && this->occupantDestroySink) { diff --git a/skymp5-server/cpp/server_guest_lib/MpObjectReference.h b/skymp5-server/cpp/server_guest_lib/MpObjectReference.h index e539528d78..87761b3ca7 100644 --- a/skymp5-server/cpp/server_guest_lib/MpObjectReference.h +++ b/skymp5-server/cpp/server_guest_lib/MpObjectReference.h @@ -5,6 +5,7 @@ #include "Inventory.h" #include "JsonUtils.h" #include "LocationalData.h" +#include "MessageBase.h" #include "MpChangeForms.h" #include "MpForm.h" #include "libespm/Loader.h" @@ -136,9 +137,8 @@ class MpObjectReference void ForceSubscriptionsUpdate(); void SetPrimitive(const NiPoint3& boundsDiv2); void UpdateHoster(uint32_t newHosterId); - void SetProperty(const std::string& propertyName, - const nlohmann::json& newValue, bool isVisibleByOwner, - bool isVisibleByNeighbor); + void SetProperty(const std::string& propertyName, nlohmann::json newValue, + bool isVisibleByOwner, bool isVisibleByNeighbor); void SetTeleportFlag(bool value); void SetPosAndAngleSilent(const NiPoint3& pos, const NiPoint3& rot); void Delete(); @@ -215,10 +215,8 @@ class MpObjectReference void EnsureBaseContainerAdded(espm::Loader& espm); - void SendPropertyToListeners(const char* name, const nlohmann::json& value); - void SendPropertyTo(const char* name, const nlohmann::json& value, - MpActor& target); - void SendPropertyTo(const IMessageBase& preparedPropMsg, MpActor& target); + void SendMessageToActorListeners(const IMessageBase& msg, + bool reliable) const; private: void AddContainerObject(const espm::CONT::ContainerObject& containerObject, diff --git a/skymp5-server/cpp/server_guest_lib/gamemode_events/RespawnEvent.cpp b/skymp5-server/cpp/server_guest_lib/gamemode_events/RespawnEvent.cpp index 7bec86a662..04902db891 100644 --- a/skymp5-server/cpp/server_guest_lib/gamemode_events/RespawnEvent.cpp +++ b/skymp5-server/cpp/server_guest_lib/gamemode_events/RespawnEvent.cpp @@ -27,5 +27,7 @@ void RespawnEvent::OnFireSuccess(WorldState*) actor->SendAndSetDeathState(false, shouldTeleport); // TODO: should probably not sending to ourselves. see also RespawnTest.cpp - actor->SendPropertyToListeners("isDead", false); + actor->SendMessageToActorListeners( + actor->CreatePropertyMessage(actor, "isDead", /*value=*/false), + /*reliable=*/true); }