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.
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
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
| Signal | Source | Event |
|---|---|---|
| Chat | Socket.IO | chat-message |
| Movement | WebRTC (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-inputevent only exists when the room uses the real transport (withpeerID), as increateRoom()andjoinRoom(). In tests with a fake transport, emitpeer-inputmanually. - 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
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.`));
}