Skip to content

Commit

Permalink
perf(skymp5-server): replace set with vector & optimize out dynamic_c…
Browse files Browse the repository at this point in the history
  • Loading branch information
Pospelove authored Aug 1, 2024
1 parent 3b27fc4 commit a4afff6
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 96 deletions.
14 changes: 7 additions & 7 deletions skymp5-server/cpp/server_guest_lib/ActionListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ MpActor* ActionListener::SendToNeighbours(
return nullptr;
}

MpActor* actor =
dynamic_cast<MpActor*>(partOne.worldState.LookupFormByIdx(idx));
MpForm* form = partOne.worldState.LookupFormByIdx(idx);
MpActor* actor = form ? form->AsActor() : nullptr;
if (!actor) {
spdlog::error("SendToNeighbours - Target actor doesn't exist");
return nullptr;
Expand Down Expand Up @@ -542,7 +542,7 @@ void ActionListener::OnHostAttempt(const RawMessageData& rawMsgData,

auto& remote = partOne.worldState.GetFormAt<MpObjectReference>(remoteId);

auto user = partOne.serverState.UserByActor(dynamic_cast<MpActor*>(&remote));
auto user = partOne.serverState.UserByActor(remote.AsActor());
if (user != Networking::InvalidUserId) {
return;
}
Expand Down Expand Up @@ -571,7 +571,7 @@ void ActionListener::OnHostAttempt(const RawMessageData& rawMsgData,
partOne.worldState.lastMovUpdateByIdx[remoteIdx] =
std::chrono::system_clock::now();

auto remoteAsActor = dynamic_cast<MpActor*>(&remote);
auto remoteAsActor = remote.AsActor();

if (remoteAsActor) {
remoteAsActor->EquipBestWeapon();
Expand Down Expand Up @@ -604,8 +604,8 @@ void ActionListener::OnHostAttempt(const RawMessageData& rawMsgData,
remote.SendToUser(msg, true); // in fact sends to hoster
});

if (MpActor* prevHosterActor = dynamic_cast<MpActor*>(
partOne.worldState.LookupFormById(prevHoster).get())) {
auto& prevHosterForm = partOne.worldState.LookupFormById(prevHoster);
if (MpActor* prevHosterActor = prevHosterForm->AsActor()) {
auto prevHosterUser = partOne.serverState.UserByActor(prevHosterActor);
if (prevHosterUser != Networking::InvalidUserId &&
prevHosterUser != rawMsgData.userId) {
Expand Down Expand Up @@ -910,7 +910,7 @@ void ActionListener::OnHit(const RawMessageData& rawMsgData_,
args[6] = VarValue(hitData.isHitBlocked); // abHitBlocked
refr->SendPapyrusEvent("OnHit", args.data(), args.size());

auto targetActorPtr = dynamic_cast<MpActor*>(refr.get());
auto targetActorPtr = refr->AsActor();
if (!targetActorPtr) {
return; // Not an actor, damage calculation is not needed
}
Expand Down
1 change: 1 addition & 0 deletions skymp5-server/cpp/server_guest_lib/ConsoleCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ void ExecuteDisable(MpActor& caller,
? caller
: caller.GetParent()->GetFormAt<MpObjectReference>(targetId);

// TODO: allow disable for all
if (target.GetFormId() >= 0xff000000 ||
dynamic_cast<MpActor*>(&target) != nullptr) {
target.Disable();
Expand Down
1 change: 1 addition & 0 deletions skymp5-server/cpp/server_guest_lib/MpActor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ MpActor::MpActor(const LocationalData& locationalData_,
optBaseId == 0 ? 0x7 : optBaseId, "NPC_")
{
pImpl.reset(new Impl);
asActor = this;
}

void MpActor::IncreaseBlockCount() noexcept
Expand Down
5 changes: 5 additions & 0 deletions skymp5-server/cpp/server_guest_lib/MpForm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ MpForm::MpForm()
{
}

MpActor* MpForm::AsActor() const noexcept
{
return asActor;
}

void MpForm::Init(WorldState* parent_, uint32_t formId_, bool hasChangeForm)
{
parent = parent_;
Expand Down
8 changes: 7 additions & 1 deletion skymp5-server/cpp/server_guest_lib/MpForm.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class WorldState;
class IGameObject;
class ActivePexInstance;
struct VarValue;
class MpActor;

class MpForm
{
Expand All @@ -19,6 +20,9 @@ class MpForm
public:
MpForm();

// Fast dynamic_cast replacement
MpActor* AsActor() const noexcept;

static const char* Type() { return "Form"; }
bool IsEspmForm() const noexcept;
virtual const char* GetFormType() const { return "Form"; }
Expand Down Expand Up @@ -76,10 +80,12 @@ class MpForm
std::vector<std::shared_ptr<ActivePexInstance>> activePexInstances;

protected:
virtual void BeforeDestroy(){};
virtual void BeforeDestroy() {}

const std::vector<std::shared_ptr<ActivePexInstance>>&
ListActivePexInstances() const;

void AddScript(const std::shared_ptr<ActivePexInstance>& script) noexcept;

MpActor* asActor = nullptr;
};
84 changes: 43 additions & 41 deletions skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ void MpObjectReference::VisitProperties(const PropertiesVisitor& visitor,
visitor("isOpen", "true");
}

if (auto actor = dynamic_cast<MpActor*>(this); actor && actor->IsDead()) {
if (auto actor = AsActor(); actor && actor->IsDead()) {
visitor("isDead", "true");
}

Expand Down Expand Up @@ -386,8 +386,7 @@ void MpObjectReference::Activate(MpObjectReference& activationSource,

// Block if only activation parents can activate this
auto refrId = GetFormId();
if (!workaroundBypassParentsCheck && IsEspmForm() &&
!dynamic_cast<MpActor*>(this)) {
if (!workaroundBypassParentsCheck && IsEspmForm() && !AsActor()) {
auto lookupRes = worldState->GetEspm().GetBrowser().LookupById(refrId);
auto data = espm::GetData<espm::REFR>(refrId, worldState);
auto it = std::find_if(
Expand Down Expand Up @@ -434,7 +433,7 @@ void MpObjectReference::Disable()
EditChangeForm(
[&](MpChangeFormREFR& changeForm) { changeForm.isDisabled = true; });

if (!IsEspmForm() || dynamic_cast<MpActor*>(this)) {
if (!IsEspmForm() || AsActor()) {
RemoveFromGridAndUnsubscribeAll();
}
}
Expand All @@ -448,7 +447,7 @@ void MpObjectReference::Enable()
EditChangeForm(
[&](MpChangeFormREFR& changeForm) { changeForm.isDisabled = false; });

if (!IsEspmForm() || dynamic_cast<MpActor*>(this)) {
if (!IsEspmForm() || AsActor()) {
ForceSubscriptionsUpdate();
}
}
Expand Down Expand Up @@ -674,15 +673,11 @@ void MpObjectReference::UpdateHoster(uint32_t newHosterId)
{
auto hostedMsg = CreatePropertyMessage(this, "isHostedByOther", true);
auto notHostedMsg = CreatePropertyMessage(this, "isHostedByOther", false);
for (auto listener : this->GetListeners()) {
auto listenerAsActor = dynamic_cast<MpActor*>(listener);
if (listenerAsActor) {
this->SendPropertyTo(newHosterId != 0 &&
newHosterId != listener->GetFormId()
? hostedMsg
: notHostedMsg,
*listenerAsActor);
}
for (auto listener : this->GetActorListeners()) {
this->SendPropertyTo(
newHosterId != 0 && newHosterId != listener->GetFormId() ? hostedMsg
: notHostedMsg,
*listener);
}
}

Expand All @@ -697,7 +692,7 @@ void MpObjectReference::SetProperty(const std::string& propertyName,
if (isVisibleByNeighbor) {
SendPropertyToListeners(propertyName.data(), newValue);
} else if (isVisibleByOwner) {
if (auto ac = dynamic_cast<MpActor*>(this)) {
if (auto ac = AsActor()) {
SendPropertyTo(propertyName.data(), newValue, *ac);
}
}
Expand Down Expand Up @@ -911,8 +906,8 @@ void MpObjectReference::RegisterPrivateIndexedProperty(
void MpObjectReference::Subscribe(MpObjectReference* emitter,
MpObjectReference* listener)
{
auto actorEmitter = dynamic_cast<MpActor*>(emitter);
auto actorListener = dynamic_cast<MpActor*>(listener);
auto actorEmitter = emitter->AsActor();
auto actorListener = listener->AsActor();
if (!actorEmitter && !actorListener) {
return;
}
Expand All @@ -933,11 +928,15 @@ void MpObjectReference::Subscribe(MpObjectReference* emitter,

emitter->InitListenersAndEmitters();
listener->InitListenersAndEmitters();
emitter->listeners->insert(listener);
if (actorListener) {
emitter->actorListeners.insert(actorListener);

auto [it, inserted] = emitter->listeners->insert(listener);

if (actorListener && inserted) {
emitter->actorListenerArray.push_back(actorListener);
}

listener->emitters->insert(emitter);

if (!hasPrimitive) {
emitter->callbacks->subscribe(emitter, listener);
}
Expand All @@ -953,8 +952,8 @@ void MpObjectReference::Subscribe(MpObjectReference* emitter,
void MpObjectReference::Unsubscribe(MpObjectReference* emitter,
MpObjectReference* listener)
{
auto actorEmitter = dynamic_cast<MpActor*>(emitter);
auto actorListener = dynamic_cast<MpActor*>(listener);
auto actorEmitter = emitter->AsActor();
auto actorListener = listener->AsActor();
bool bothNonActors = !actorEmitter && !actorListener;
if (bothNonActors) {
return;
Expand All @@ -965,10 +964,16 @@ void MpObjectReference::Unsubscribe(MpObjectReference* emitter,
if (!hasPrimitive) {
emitter->callbacks->unsubscribe(emitter, listener);
}
emitter->listeners->erase(listener);
if (actorListener) {
emitter->actorListeners.erase(actorListener);

size_t numElementsErased = emitter->listeners->erase(listener);

if (actorListener && numElementsErased > 0) {
emitter->actorListenerArray.erase(
std::remove(emitter->actorListenerArray.begin(),
emitter->actorListenerArray.end(), actorListener),
emitter->actorListenerArray.end());
}

listener->emitters->erase(emitter);

if (listener->emittersWithPrimitives && hasPrimitive) {
Expand Down Expand Up @@ -1030,9 +1035,10 @@ const std::set<MpObjectReference*>& MpObjectReference::GetListeners() const
return listeners ? *listeners : kEmptyListeners;
}

const std::set<MpActor*>& MpObjectReference::GetActorListeners() const noexcept
const std::vector<MpActor*>& MpObjectReference::GetActorListeners()
const noexcept
{
return actorListeners;
return actorListenerArray;
}

const std::set<MpObjectReference*>& MpObjectReference::GetEmitters() const
Expand Down Expand Up @@ -1165,8 +1171,7 @@ void MpObjectReference::ApplyChangeForm(const MpChangeForm& changeForm)

// Perform all required grid operations
// Mirrors MpActor impl
// TODO: get rid of dynamic_cast
if (!dynamic_cast<MpActor*>(this)) {
if (!AsActor()) {
changeForm.isDisabled ? Disable() : Enable();
SetCellOrWorldObsolete(changeForm.worldOrCellDesc);
SetPos(changeForm.position);
Expand Down Expand Up @@ -1255,7 +1260,7 @@ void MpObjectReference::Init(WorldState* parent, uint32_t formId,
mode);

auto refrId = GetFormId();
if (parent->HasEspm() && IsEspmForm() && !dynamic_cast<MpActor*>(this)) {
if (parent->HasEspm() && IsEspmForm() && !AsActor()) {
auto lookupRes = parent->GetEspm().GetBrowser().LookupById(refrId);
auto data = espm::GetData<espm::REFR>(refrId, parent);
for (auto& info : data.activationParents) {
Expand All @@ -1278,7 +1283,7 @@ bool MpObjectReference::IsLocationSavingNeeded() const

void MpObjectReference::ProcessActivate(MpObjectReference& activationSource)
{
auto actorActivator = dynamic_cast<MpActor*>(&activationSource);
auto actorActivator = activationSource.AsActor();

auto worldState = GetParent();
auto& loader = GetParent()->GetEspm();
Expand Down Expand Up @@ -1543,7 +1548,7 @@ void MpObjectReference::InitScripts()

if (record == base.rec && record->GetType() == "NPC_") {
auto baseId = base.ToGlobalId(base.rec->GetId());
if (auto actor = dynamic_cast<MpActor*>(this)) {
if (auto actor = AsActor()) {
auto& templateChain = actor->GetTemplateChain();
scriptData = EvaluateTemplate<espm::NPC_::UseScript>(
GetParent(), baseId, templateChain,
Expand Down Expand Up @@ -1624,14 +1629,14 @@ void MpObjectReference::InitListenersAndEmitters()
if (!listeners) {
listeners.reset(new std::set<MpObjectReference*>);
emitters.reset(new std::set<MpObjectReference*>);
actorListeners.clear();
actorListenerArray.clear();
}
}

void MpObjectReference::SendInventoryUpdate()
{
constexpr int kChannelSetInventory = 0;
auto actor = dynamic_cast<MpActor*>(this);
auto actor = AsActor();
if (actor) {
std::string msg;
msg += Networking::MinPacketId;
Expand All @@ -1646,7 +1651,7 @@ void MpObjectReference::SendInventoryUpdate()

void MpObjectReference::SendOpenContainer(uint32_t targetId)
{
auto actor = dynamic_cast<MpActor*>(this);
auto actor = AsActor();
if (actor) {
OpenContainerMessage msg;
msg.target = targetId;
Expand Down Expand Up @@ -1737,7 +1742,7 @@ void MpObjectReference::EnsureBaseContainerAdded(espm::Loader& espm)
return;
}

auto actor = dynamic_cast<MpActor*>(this);
auto actor = AsActor();
const std::vector<FormDesc> kEmptyTemplateChain;
const std::vector<FormDesc>& templateChain =
actor ? actor->GetTemplateChain() : kEmptyTemplateChain;
Expand Down Expand Up @@ -1811,11 +1816,8 @@ void MpObjectReference::SendPropertyToListeners(const char* name,
const nlohmann::json& value)
{
auto msg = CreatePropertyMessage(this, name, value);
for (auto listener : GetListeners()) {
auto listenerAsActor = dynamic_cast<MpActor*>(listener);
if (listenerAsActor) {
listenerAsActor->SendToUser(msg, true);
}
for (auto listener : GetActorListeners()) {
listener->SendToUser(msg, true);
}
}

Expand Down
4 changes: 2 additions & 2 deletions skymp5-server/cpp/server_guest_lib/MpObjectReference.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ class MpObjectReference
void VisitNeighbours(const Visitor& visitor);

void SendInventoryUpdate();
const std::set<MpActor*>& GetActorListeners() const noexcept;
const std::vector<MpActor*>& GetActorListeners() const noexcept;

static const char* GetPropertyPrefixPrivate() noexcept { return "private."; }
static const char* GetPropertyPrefixPrivateIndexed() noexcept
Expand Down Expand Up @@ -224,7 +224,7 @@ class MpObjectReference

bool everSubscribedOrListened = false;
std::unique_ptr<std::set<MpObjectReference*>> listeners;
std::set<MpActor*> actorListeners;
std::vector<MpActor*> actorListenerArray;

// Should be empty for non-actor refs
std::unique_ptr<std::set<MpObjectReference*>> emitters;
Expand Down
Loading

0 comments on commit a4afff6

Please sign in to comment.