Treat a deleted entity as undefined for the rest of its frame

delete() only queues an entity; it is retired at the scheduler's frame
boundary so scripts can still read its fields for the rest of the frame.
isdefined() looked only at retired entities, though, so an entity deleted
earlier in the same frame still tested defined.

The game's scripts expect the opposite. common_scripts/_pipes deletes the
sound of a finished pipe burst and immediately runs array_removeUndefined
on its list. The dead sound stayed in the list, and the next hit on that
pipe faulted in pipe_logic (DistanceSquared on the sound's now-undefined
origin), took the "return false" path, and the pipe never burst again for
the rest of the match (mp_highrise).

isdefined() now also treats an entity with a pending delete as gone.
Field reads are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
JohnM
2026-10-10 00:08:34 +08:00
parent 91217cd0ac
commit 9c4d4320f4
+4 -1
View File
@@ -17,7 +17,10 @@ impl Default for NativeRegistry {
}
let defined = match &args[0] {
Value::Undefined => false,
Value::Object(id) => world.resource::<Runtime>().live(id),
Value::Object(id) => {
let runtime = world.resource::<Runtime>();
runtime.live(id) && !runtime.pending_deletes.contains(id)
}
_ => true,
};
Ok(Value::Int(i32::from(defined)))