Skip to content

Commit

Permalink
fix(skymp5-server): fix containers becoming unusable randomly (skyrim…
Browse files Browse the repository at this point in the history
  • Loading branch information
Pospelove authored Sep 24, 2024
1 parent e61406b commit ae8d2bf
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 16 deletions.
65 changes: 49 additions & 16 deletions skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions skymp5-server/cpp/server_guest_lib/MpObjectReference.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::set<MpObjectReference*>> listeners;
Expand Down

0 comments on commit ae8d2bf

Please sign in to comment.