the symptom, in your words

"A component that reads Input in OnUpdate fires on every instance at once"

✓ verified on 26.07.22
lane Writing gameplayposted

▸ SYMPTOM

You put an input read inside a per-entity component. The component calls Input.Pressed or Input.Down in its own OnUpdate to trigger an action. With one entity on screen it works exactly as intended.

Add more instances of the same component and one keypress fires the action on every instance at once. In a multi-vehicle arena, a single press to repair and respawn teleports the whole field back to its spawn points. Nothing in the log points at input, so it reads as a free world reset, not an input bug.

▸ CAUSE

Input.Pressed and Input.Down read a global input state. They do not carry a per-entity target. A component that reads them in OnUpdate samples that one global state once per instance, every frame.

The live case gated the read only on IsProxy. IsProxy is a network-replication check. It answers whether the entity is replicated from elsewhere, not whether this instance should respond to a keypress. In single-player or local testing with one entity, IsProxy is false and the read is correct. In a multi-entity arena with several locally-simulated instances, none of them is a proxy. So every instance passes the same gate and responds to the same press.

▸ FIX

Gate any global input read inside a per-entity component on genuine local ownership, not on proxy status.

  1. Read input only on the actively-controlled entity. Confirm this instance is the one the local player drives before you read Input.Pressed or Input.Down. A design that hands control to one entity at a time reads input on that entity only.
  2. Do not treat IsProxy as an ownership test. IsProxy false means simulated here, which can be true for many entities at once. It does not mean the player controls this one.
  3. Audit every unconditional Input.* read when the entity count can exceed one. A per-entity component with an unguarded input read is safe only while exactly one instance of it exists.

▸ WHY IT WORKS

The bug is a scope mismatch: a global input state read from a per-entity scope. Ownership is the missing scope. When the read runs only on the entity the local player controls, the global state maps to exactly one responder, whatever the instance count. IsProxy cannot supply that scope, because replication status and control ownership are different questions. One keypress crossing many non-proxy instances is exactly where they diverge.

Verified on engine 26.07.22: seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?
changelog
  • Published

Want to know when new guides or fixes drop? Join the community to help build this out. Report gotchas, flag outdated fixes, or just lurk.

Join the Discord