diff --git a/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp b/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp index ae8051cc7e..459e66ff5d 100644 --- a/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp +++ b/skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp @@ -1442,16 +1442,9 @@ void MpObjectReference::ProcessActivateNormal( } else if (t == espm::CONT::kType && actorActivator) { EnsureBaseContainerAdded(loader); - auto occupantPos = this->occupant ? this->occupant->GetPos() : NiPoint3(); - auto occupantCellOrWorld = - this->occupant ? this->occupant->GetCellOrWorld() : FormDesc(); - constexpr float kOccupationReach = 512.f; - auto distanceToOccupant = (occupantPos - GetPos()).Length(); - if (!this->occupant || this->occupant->IsDisabled() || - distanceToOccupant > kOccupationReach || - occupantCellOrWorld != GetCellOrWorld()) { + if (CheckIfObjectCanStartOccupyThis(activationSource, kOccupationReach)) { if (this->occupant) { this->occupant->RemoveEventSink(this->occupantDestroySink); } @@ -1471,16 +1464,9 @@ void MpObjectReference::ProcessActivateNormal( activationSource.SendOpenContainer(GetFormId()); } else if (t == "FURN" && actorActivator) { - auto occupantPos = this->occupant ? this->occupant->GetPos() : NiPoint3(); - auto occupantCellOrWorld = - this->occupant ? this->occupant->GetCellOrWorld() : FormDesc(); - constexpr float kOccupationReach = 256.f; - auto distanceToOccupant = (occupantPos - GetPos()).Length(); - if (!this->occupant || this->occupant->IsDisabled() || - distanceToOccupant > kOccupationReach || - occupantCellOrWorld != GetCellOrWorld()) { + if (CheckIfObjectCanStartOccupyThis(activationSource, kOccupationReach)) { if (this->occupant) { this->occupant->RemoveEventSink(this->occupantDestroySink); } @@ -1568,6 +1554,53 @@ void MpObjectReference::ActivateChilds() } } +bool MpObjectReference::CheckIfObjectCanStartOccupyThis( + MpObjectReference& activationSource, float occupationReach) +{ + if (!this->occupant) { + spdlog::info("MpObjectReference::ProcessActivate {:x} - no occupant " + "(activationSource = {:x})", + GetFormId(), activationSource.GetFormId()); + return true; + } + + if (this->occupant->IsDisabled()) { + spdlog::info("MpObjectReference::ProcessActivate {:x} - occupant is " + "disabled (activationSource = {:x})", + GetFormId(), activationSource.GetFormId()); + return true; + } + + auto& occupantPos = this->occupant->GetPos(); + auto distanceToOccupantSqr = (occupantPos - GetPos()).SqrLength(); + if (distanceToOccupantSqr > occupationReach * occupationReach) { + spdlog::info("MpObjectReference::ProcessActivate {:x} - occupant is too " + "far away (activationSource = {:x})", + GetFormId(), activationSource.GetFormId()); + return true; + } + + auto& occupantCellOrWorld = this->occupant->GetCellOrWorld(); + if (occupantCellOrWorld != GetCellOrWorld()) { + spdlog::info("MpObjectReference::ProcessActivate {:x} - occupant is in " + "another cell/world (activationSource = {:x})", + GetFormId(), activationSource.GetFormId()); + return true; + } + + if (this->occupant == &activationSource) { + spdlog::info("MpObjectReference::ProcessActivate {:x} - occupant is " + "already this object (activationSource = {:x})", + GetFormId(), activationSource.GetFormId()); + return true; + } + + spdlog::info("MpObjectReference::ProcessActivate {:x} - occupant is " + "another object and is nearby (activationSource = {:x})", + GetFormId(), activationSource.GetFormId()); + return false; +} + void MpObjectReference::RemoveFromGridAndUnsubscribeAll() { auto worldOrCell = GetCellOrWorld().ToFormId(GetParent()->espmFiles); diff --git a/skymp5-server/cpp/server_guest_lib/MpObjectReference.h b/skymp5-server/cpp/server_guest_lib/MpObjectReference.h index a015e6a72e..e539528d78 100644 --- a/skymp5-server/cpp/server_guest_lib/MpObjectReference.h +++ b/skymp5-server/cpp/server_guest_lib/MpObjectReference.h @@ -232,6 +232,8 @@ class MpObjectReference void ProcessActivateNormal(MpObjectReference& activationSource); bool ProcessActivateSecond(MpObjectReference& activationSource); void ActivateChilds(); + bool CheckIfObjectCanStartOccupyThis(MpObjectReference& activationSource, + float occupationReach); bool everSubscribedOrListened = false; std::unique_ptr> listeners;