#81: every MP respawn is a cross-machine round trip -- one degraded peer ghosts everyone
Two-node bench with the fixed host:local labels shows each player's drop-zone
request is answered by the OTHER machine's DropZone: A asks, B grants; B asks, A
grants. FindGroup("DropZones") iterates replicants of remotely-mastered zones
too and takes the geometrically closest, so a respawn is
my request -> an arbitrary peer's DropZone -> that peer's reply -> back to me.
With 5 players that is 5 round trips through arbitrary peers, and ONE degraded
peer can strand everybody else's respawn. That finally explains the otherwise
unexplained field datum that one machine stopped processing the death-transition
stream 57% into a match and never recovered (0 explosions/wreck swaps/burials
while four other machines logged 4/4/4) -- a node in that state cannot answer
anyone's respawn. It also explains why solo is 100% reliable (in-process) and
why a healthy 2-node bench passes.
Also fixes the instrumentation before it costs a night: every [dz] line printed
"entity 1" because a player's LOCAL entity id is 1 on every machine -- with five
players the log would have said a respawn stalled but not WHOSE. All [dz] lines
now print host:local (including the usedBy= owner of each busy slot).
Doc: two candidate fixes recorded (prefer a locally-mastered DropZone / make the
reply path tolerant of a deathCount that is ahead of ours), neither to be guessed
at -- the [ghost] DISCARDED line's mismatch direction decides it in one line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
0dbdad17f3
commit
bf0555ccf1
@@ -137,6 +137,13 @@ DropZone::~DropZone()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #81: print an EntityID as host:local. A player's LOCAL id is 1 on every
|
||||
// machine, so printing only the local part made every one of five players read
|
||||
// "entity 1" -- useless for telling WHO stalled. GetHostID() is non-const.
|
||||
static inline int DZHost(const EntityID &id) { EntityID c(id); return (int)c.GetHostID(); }
|
||||
static inline int DZLocal(const EntityID &id) { return (int)id; }
|
||||
|
||||
//#############################################################################
|
||||
// Dropzone assignment
|
||||
//
|
||||
@@ -223,7 +230,9 @@ void
|
||||
|
||||
if (dzLog)
|
||||
{
|
||||
DEBUG_STREAM << "[dz] REQUEST from entity " << (int)message->requestingEntity
|
||||
DEBUG_STREAM << "[dz] REQUEST from "
|
||||
<< DZHost(message->requestingEntity) << ":"
|
||||
<< DZLocal(message->requestingEntity)
|
||||
<< " deathCount=" << message->deathCount
|
||||
<< " waited=" << waited << "s slots[";
|
||||
for (int d = 0; d < dropZoneCount; ++d)
|
||||
@@ -383,7 +392,8 @@ void
|
||||
{
|
||||
s_waitLastLog[wslot] = Now();
|
||||
DEBUG_STREAM << (waited >= 15.0f ? "[dz] GHOST LIKELY -- " : "[dz] STALL -- ")
|
||||
<< "entity " << (int)message->requestingEntity
|
||||
<< DZHost(message->requestingEntity) << ":"
|
||||
<< DZLocal(message->requestingEntity)
|
||||
<< " death#" << message->deathCount
|
||||
<< " has waited " << waited << "s for a slot; all "
|
||||
<< dropZoneCount << " busy [";
|
||||
@@ -391,7 +401,8 @@ void
|
||||
{
|
||||
Scalar age = lastUsageTime[d].ticks ? (Scalar)(Now() - lastUsageTime[d]) : -1.0f;
|
||||
DEBUG_STREAM << (d ? " " : "") << d << ":usedBy="
|
||||
<< (int)lastUsedBy[d] << ",age=" << age << "s";
|
||||
<< DZHost(lastUsedBy[d]) << ":" << DZLocal(lastUsedBy[d])
|
||||
<< ",age=" << age << "s";
|
||||
}
|
||||
DEBUG_STREAM << "]\n" << std::flush;
|
||||
}
|
||||
@@ -399,8 +410,9 @@ void
|
||||
{
|
||||
static int s_rp = 0;
|
||||
if (++s_rp <= 5)
|
||||
DEBUG_STREAM << "[dz] repost #" << s_rp << " (entity "
|
||||
<< (int)message->requestingEntity << ")\n" << std::flush;
|
||||
DEBUG_STREAM << "[dz] repost #" << s_rp << " ("
|
||||
<< DZHost(message->requestingEntity) << ":"
|
||||
<< DZLocal(message->requestingEntity) << ")\n" << std::flush;
|
||||
}
|
||||
Time when=Now();
|
||||
when += 0.1f;
|
||||
@@ -423,8 +435,10 @@ Found_One:
|
||||
int slot = (int)(drop_zone - dropZones);
|
||||
if (waited > 0.5f) ++s_stalledGrants;
|
||||
++s_grants;
|
||||
DEBUG_STREAM << "[dz] GRANTED slot " << slot << " to entity "
|
||||
<< (int)message->requestingEntity << " death#" << message->deathCount
|
||||
DEBUG_STREAM << "[dz] GRANTED slot " << slot << " to "
|
||||
<< DZHost(message->requestingEntity) << ":"
|
||||
<< DZLocal(message->requestingEntity)
|
||||
<< " death#" << message->deathCount
|
||||
<< " waited=" << waited << "s"
|
||||
<< (waited >= 15.0f ? " (GHOST RECOVERED)" : "")
|
||||
<< " [grants=" << s_grants << " stalled=" << s_stalledGrants << "]"
|
||||
|
||||
Reference in New Issue
Block a user