ControllerRegistry

Properties

  • shareFirstControllerWithRemote (boolean) — Default true - the first browser shares playerIndex 0 with the first
  • combineRemoteInputs (boolean) — Default false - each distinct remote/gamepad gets its own stable

Constructor

new ControllerRegistry(): ControllerRegistry

Instance Methods

assignPlayerIndex(): integer

Assigns the lowest free player index to a browser controller connection. With shareFirstControllerWithRemote (default), the first browser claims index 0, shared with the first remote/gamepad regardless of connection order (see assignPlayerIndexForRemoteId); only a second browser onward gets its own index starting at 1.

Returns

  • integer

releasePlayerIndex(playerIndex: integer): void

Frees a player index previously returned by assignPlayerIndex(), e.g. when its connection closes - a later assignPlayerIndex() call may reuse it.

Parameters

  • playerIndex (integer) — the player index to release

Returns

  • void

assignPlayerIndexForRemoteId(remoteId: string): integer

Looks up (or lazily assigns) a stable playerIndex for one physical remote/gamepad, identified by roUniversalControlEvent.GetRemoteID() (e.g. "30:1"). Never released - a physical remote has no disconnect signal to key a release off, unlike a browser controller's WebSocket close. With shareFirstControllerWithRemote (default), the first remote/gamepad claims index 0 even if a browser already occupies it too (see assignPlayerIndex). With combineRemoteInputs, every remote/ gamepad is forced onto index 0 instead.

Parameters

  • remoteId (string) — the string from roUniversalControlEvent.GetRemoteID()

Returns

  • integer

updateFromMessage( playerIndex: integer, buttons: object, sticks: object, custom: object, ): Array.<string>

Updates one connection's raw state from a decoded {buttons, sticks, custom} message. Returns the button names whose boolean flipped since the last update, for Game to synthesize press/release GameInput events. The message is untrusted - a non-boolean button or non-numeric stick axis is coerced to a safe default (false / 0.0) rather than propagating whatever ParseJson happened to hand back.

Parameters

  • playerIndex (integer)
  • buttons (object) — name -> dynamic (expected boolean)
  • sticks (object) — name -> {x, y} (each dynamic, expected numeric)
  • custom (object) — opaque, passed through untouched

Returns

  • Array.<string>

isButtonHeld(playerIndex: integer, buttonName: string): boolean

Parameters

  • playerIndex (integer) — which player's connection to read
  • buttonName (string) — which button to check

Returns

  • boolean

getHeldTimeMs(playerIndex: integer, buttonName: string): integer

Parameters

  • playerIndex (integer) — which player's connection to read
  • buttonName (string) — which button to check

Returns

  • integer

getButtonNames(playerIndex: integer): Array.<string>

Parameters

  • playerIndex (integer)

Returns

  • Array.<string>

getStick( playerIndex: integer, stickName: string, ): BGE.Math.Vector

Parameters

  • playerIndex (integer) — which player's connection to read
  • stickName (string) — the stick's name, as sent in the message's sticks map

Returns

  • BGE.Math.Vector

getCustomPayload(playerIndex: integer): object

Parameters

  • playerIndex (integer)

Returns

  • object

setRemoteDpad(playerIndex: integer, x: float, y: float): void

Records one physical remote/gamepad's current d-pad-derived {x, y}, used by BGE.Controller.ControlMap.getAxis() when no controller stick is bound (or it's neutral) for this player.

Parameters

  • playerIndex (integer)
  • x (float) — 1..1
  • y (float) — 1..1

Returns

  • void

getRemoteDpad(playerIndex: integer): BGE.Math.Vector

Parameters

  • playerIndex (integer)

Returns

  • BGE.Math.Vector

setRemoteEvent(playerIndex: integer, event: dynamic): void

Caches the last Bluetooth-gamepad roUniversalControlEvent seen for this player, so getRemoteAnalogStick() can keep reading its live GetValue() every frame even on a frame with no new event for this remote (a stick held at a nonzero deflection produces no new roUniversalControlEvent - see specs/2026-09-15-multi-controller-input-design.md). A non-gamepad event (e.g. keyboard-sim) is ignored here rather than overwriting an already-cached gamepad event - under combineRemoteInputs, where both share one playerIndex, caching indiscriminately would let a keyboard press evict the gamepad's slot, and a held-but-unchanging analog stick has no later event of its own to reclaim it.

Parameters

  • playerIndex (integer)
  • event (dynamic) — the roUniversalControlEvent, passed as dynamic since GetValue() isn't part of its typed interface

Returns

  • void

getRemoteAnalogStick( playerIndex: integer, stick?: string, ): BGE.Math.Vector

Parameters

  • playerIndex (integer)
  • stick (string, optional, default: "\"1\"") — "2" reads the right stick (RIGHT_X/RIGHT_Y); any other value (including the default "1") reads the left stick - matching bindAxis()'s own stick-name convention

Returns

  • BGE.Math.Vector