Library

Anti-AFK

Detect idle players by movement and by chat, with a 12 s tolerance.

Anti-AFK flags as AFK a player who stayed 12 seconds without moving and without chatting. Either signal resets the clock.

ts
room.enableAntiAfk();                                  // default: 12 s

room.on('player-afk',  (id) => room.kickPlayer(id));   // once, when they become AFK
room.on('player-back', (id) => room.chat(`player ${id} is back`));

room.isAfk(playerId);                                  // one-off check
room.disableAntiAfk();

Options

ts
room.enableAntiAfk({
  thresholdMs: 12_000,     // idle time until AFK
  checkIntervalMs: 1_000,  // check frequency
});

The default time is also available as the AFK_THRESHOLD_MS constant.

Who is watched

Only players on a team during a match. Spectators and the bot itself are ignored. The clock starts when the match starts (or when the player joins a team during the match) and is discarded when the match ends.

Where the signals come from

SignalSourceEvent
ChatSocket.IOchat-message
MovementWebRTC (input frames between peers)peer-input

Movement does not go through Socket.IO: players exchange input frames with each other over WebRTC. The library completes the WebRTC handshake as if it were a player and receives those frames. It gets one frame per key pressed or released, and none while the player is idle, which makes the detection reliable.

peer-input delivers { playerId, peerID, data }, with the frame already tied to the right player. You can use it directly for activity statistics.

Important limitations

  • Needs the real mode. The peer-input event only exists when the room uses the real transport (with peerID), as in createRoom() and joinRoom(). In tests with a fake transport, emit peer-input manually.
  • Signal reliability. If, for some reason, no movement frame arrives during a whole match, the signal is not reliable. The 24/7 room ignores automatic AFK in that case, so it never punishes everyone over a network failure. Do the same if you apply penalties.

Complete example

ts
import type { BonkRoom } from 'bonktools';

export function setupAntiAfk(room: BonkRoom): void {
  room.enableAntiAfk();

  const name = (id: number) => room.state.players.get(id)?.userName ?? `#${id}`;

  room.on('player-afk', (id) => {
    room.chat(`${name(id)} is AFK!`);
    room.kickPlayer(id); // remove this line if you only want to warn
  });

  room.on('player-back', (id) => room.chat(`${name(id)} is back.`));
}