Room Callbacks
Standard Rooms provide comprehensive callbacks to monitor and respond to all room events. These callbacks allow you to create responsive multiplayer experiences by reacting to player joins, leaves, connections, and room state changes.
Available Callbacks
| Callback | Trigger | Purpose |
|---|---|---|
onRoomCreated | Room successfully created | Handle room creation success/failure |
onJoinedRoom | Successfully joined a room | Handle successful room join |
onMessageReceived | Message received from player | Process incoming messages |
onPeerJoined | New player joins room | Update UI and game state |
onPeerLeft | Player leaves room | Handle player departure |
onLeftRoom | You leave the room | Clean up and return to lobby |
onRoomConnected | Room fully connected | Start gameplay |
onRoomDisconnected | Room connection lost | Handle disconnection |
Room Creation and Joining Callbacks
onRoomCreated
Called when your room creation request is processed:
- JavaScript
- TypeScript
onRoomCreated: (status, room) => {
if (status) {
console.log('✅ Room created successfully');
console.log('Room ID:', room.roomID);
console.log('Status:', room.status);
console.log('Auto-match wait time:', room.autoMatchWaitSeconds);
// Show room created UI
showRoomCreatedScreen(room);
// If auto-matching, show waiting screen
if (room.isAutoMatch) {
showAutoMatchWaiting(room);
} else {
// Private room - show invitation code
showInvitationCode(room.roomID);
}
// Start room state monitoring
startRoomStateMonitoring(room);
} else {
console.error('❌ Failed to create room');
showRoomCreationError('Unable to create room. Please try again.');
returnToLobby();
}
}
import type { Room, RoomStatus } from '@veniso/moitribe-js';
onRoomCreated: (status: boolean, room: Room) => {
if (status) {
console.log('✅ Room created successfully');
console.log('Room ID:', room.roomID);
console.log('Status:', room.status);
console.log('Auto-match wait time:', room.autoMatchWaitSeconds);
// Show room created UI
showRoomCreatedScreen(room);
// If auto-matching, show waiting screen
if (room.isAutoMatch) {
showAutoMatchWaiting(room);
} else {
// Private room - show invitation code
showInvitationCode(room.roomID);
}
// Start room state monitoring
startRoomStateMonitoring(room);
} else {
console.error('❌ Failed to create room');
showRoomCreationError('Unable to create room. Please try again.');
returnToLobby();
}
}
onJoinedRoom
Called when you successfully join a room:
- JavaScript
- TypeScript
onJoinedRoom: (status, room) => {
if (status) {
console.log('✅ Successfully joined room');
console.log('Room ID:', room.roomID);
console.log('Creator:', room.creatorID);
console.log('Current players:', room.participants.length);
// Display room information
showRoomInfo(room);
// Show list of current players
displayPlayerList(room.participants);
// Check if room is ready to start
if (room.status === 3) { // RoomStatus.ACTIVE
console.log('Room is active - ready to play!');
enableGameControls();
startGameCountdown();
} else {
console.log('Room is not yet active - waiting for players');
showWaitingForPlayers(room);
}
// Send join announcement
sendJoinAnnouncement();
} else {
console.error('❌ Failed to join room');
showJoinError('Unable to join room. The room may be full or no longer available.');
returnToLobby();
}
}
import type { Room, RoomStatus } from '@veniso/moitribe-js';
onJoinedRoom: (status: boolean, room: Room) => {
if (status) {
console.log('✅ Successfully joined room');
console.log('Room ID:', room.roomID);
console.log('Creator:', room.creatorID);
console.log('Current players:', room.participants.length);
// Display room information
showRoomInfo(room);
// Show list of current players
displayPlayerList(room.participants);
// Check if room is ready to start
if (room.status === RoomStatus.ACTIVE) {
console.log('Room is active - ready to play!');
enableGameControls();
startGameCountdown();
} else {
console.log('Room is not yet active - waiting for players');
showWaitingForPlayers(room);
}
// Send join announcement
sendJoinAnnouncement();
} else {
console.error('❌ Failed to join room');
showJoinError('Unable to join room. The room may be full or no longer available.');
returnToLobby();
}
}
Player Management Callbacks
onPeerJoined
Called when a new player joins the room:
- JavaScript
- TypeScript
onPeerJoined: (room, participantList) => {
console.log('👋 New player joined the room');
console.log('Total players:', participantList.length);
// Find the new participant
const newParticipant = room.participants.find(p =>
!previousParticipants.has(p.participantID)
);
if (newParticipant) {
console.log('New player:', newParticipant.name);
// Show join notification
showPlayerJoinedNotification(newParticipant);
// Add to player list
addPlayerToUI(newParticipant);
// Play join sound
playSound('playerJoined');
// Update previous participants set
previousParticipants.add(newParticipant.participantID);
}
// Update player count display
updatePlayerCount(participantList.length);
// Check if room is now full
const maxPlayers = room.max_automatch_players || room.participants.length;
if (participantList.length >= maxPlayers) {
console.log('Room is now full!');
showRoomFullNotification();
startGameCountdown();
}
// Update game state if needed
updateGameStateForNewPlayer(room);
}
import type { Room, Participant } from '@veniso/moitribe-js';
// Track previous participants to detect new ones
const previousParticipants = new Set<string>();
onPeerJoined: (room: Room, participantList: string[]) => {
console.log('👋 New player joined the room');
console.log('Total players:', participantList.length);
// Find the new participant
const newParticipant = room.participants.find(p =>
!previousParticipants.has(p.participantID)
);
if (newParticipant) {
console.log('New player:', newParticipant.name);
// Show join notification
showPlayerJoinedNotification(newParticipant);
// Add to player list
addPlayerToUI(newParticipant);
// Play join sound
playSound('playerJoined');
// Update previous participants set
previousParticipants.add(newParticipant.participantID);
}
// Update player count display
updatePlayerCount(participantList.length);
// Check if room is now full
const maxPlayers = room.max_automatch_players || room.participants.length;
if (participantList.length >= maxPlayers) {
console.log('Room is now full!');
showRoomFullNotification();
startGameCountdown();
}
// Update game state if needed
updateGameStateForNewPlayer(room);
}
onPeerLeft
Called when a player leaves the room:
- JavaScript
- TypeScript
onPeerLeft: (room, participantList) => {
console.log('👋 Player left the room');
console.log('Remaining players:', participantList.length);
// Find who left by comparing with previous participants
const leftParticipantId = Array.from(previousParticipants).find(id =>
!participantList.includes(id)
);
if (leftParticipantId) {
// Find participant details from room data
const leftParticipant = room.participants.find(p =>
p.participantID === leftParticipantId
);
if (leftParticipant) {
console.log('Player who left:', leftParticipant.name);
// Show leave notification
showPlayerLeftNotification(leftParticipant);
// Remove from player list
removePlayerFromUI(leftParticipant.participantID);
// Play leave sound
playSound('playerLeft');
// Clean up player-specific data
cleanupPlayerData(leftParticipant.participantID);
}
// Update previous participants set
previousParticipants.delete(leftParticipantId);
}
// Update player count display
updatePlayerCount(participantList.length);
// Handle game state changes
if (participantList.length < 2) {
console.log('Not enough players to continue');
pauseGameplay('Not enough players');
showWaitingForPlayers();
} else {
// Check if game can continue
checkGameContinuation(room);
}
// Check if room creator left
if (leftParticipantId === room.creatorID) {
console.log('Room creator left - room may close soon');
showCreatorLeftWarning();
}
}
import type { Room, Participant } from '@veniso/moitribe-js';
// Track previous participants to detect who left
const previousParticipants = new Set<string>();
onPeerLeft: (room: Room, participantList: string[]) => {
console.log('👋 Player left the room');
console.log('Remaining players:', participantList.length);
// Find who left by comparing with previous participants
const leftParticipantId = Array.from(previousParticipants).find(id =>
!participantList.includes(id)
);
if (leftParticipantId) {
// Find participant details from room data
const leftParticipant = room.participants.find(p =>
p.participantID === leftParticipantId
);
if (leftParticipant) {
console.log('Player who left:', leftParticipant.name);
// Show leave notification
showPlayerLeftNotification(leftParticipant);
// Remove from player list
removePlayerFromUI(leftParticipant.participantID);
// Play leave sound
playSound('playerLeft');
// Clean up player-specific data
cleanupPlayerData(leftParticipant.participantID);
}
// Update previous participants set
previousParticipants.delete(leftParticipantId);
}
// Update player count display
updatePlayerCount(participantList.length);
// Handle game state changes
if (participantList.length < 2) {
console.log('Not enough players to continue');
pauseGameplay('Not enough players');
showWaitingForPlayers();
} else {
// Check if game can continue
checkGameContinuation(room);
}
// Check if room creator left
if (leftParticipantId === room.creatorID) {
console.log('Room creator left - room may close soon');
showCreatorLeftWarning();
}
}
Connection State Callbacks
onRoomConnected
Called when the room is fully connected and ready:
- JavaScript
- TypeScript
onRoomConnected: (status, room) => {
if (status) {
console.log('🔗 Room fully connected and ready');
console.log('All players connected:', room.participants.length);
// Hide any loading/waiting screens
hideLoadingScreen();
hideWaitingScreen();
// Show game ready state
showGameReadyScreen();
// Enable game controls
enableAllGameControls();
// Start the game
startMultiplayerGame(room);
// Begin game state synchronization
startGameStateSync();
// Show connected notification
showNotification('All players connected!', 'success');
// Start game timer
startGameTimer();
// Enable voice chat if available
if (isVoiceChatEnabled()) {
enableVoiceChat();
}
// Log game start for analytics
logGameStart(room);
} else {
console.error('❌ Failed to connect room');
showConnectionError('Unable to establish connection with all players');
// Offer retry option
showRetryConnectionOption();
}
}
import type { Room } from '@veniso/moitribe-js';
onRoomConnected: (status: boolean, room: Room) => {
if (status) {
console.log('🔗 Room fully connected and ready');
console.log('All players connected:', room.participants.length);
// Hide any loading/waiting screens
hideLoadingScreen();
hideWaitingScreen();
// Show game ready state
showGameReadyScreen();
// Enable game controls
enableAllGameControls();
// Start the game
startMultiplayerGame(room);
// Begin game state synchronization
startGameStateSync();
// Show connected notification
showNotification('All players connected!', 'success');
// Start game timer
startGameTimer();
// Enable voice chat if available
if (isVoiceChatEnabled()) {
enableVoiceChat();
}
// Log game start for analytics
logGameStart(room);
} else {
console.error('❌ Failed to connect room');
showConnectionError('Unable to establish connection with all players');
// Offer retry option
showRetryConnectionOption();
}
}
onRoomDisconnected
Called when the room connection is lost:
- JavaScript
- TypeScript
onRoomDisconnected: (room) => {
console.log('🔌 Room connection lost');
console.log('Room ID:', room.roomID);
// Show disconnection warning
showDisconnectionWarning('Connection to room lost');
// Pause game immediately
pauseGameplay();
// Disable game controls
disableGameControls();
// Show reconnection attempt
showReconnectionScreen();
// Start reconnection timer
startReconnectionTimer();
// Save current game state
saveGameStateForReconnection();
// Notify players
showNotification('Connection lost. Attempting to reconnect...', 'warning');
// Log disconnection for analytics
logDisconnection(room);
// Attempt automatic reconnection
attemptReconnection(room);
}
// Handle reconnection
function attemptReconnection(room) {
let attempts = 0;
const maxAttempts = 5;
const reconnectInterval = setInterval(() => {
attempts++;
console.log(`Reconnection attempt ${attempts}/${maxAttempts}`);
updateReconnectionStatus(attempts, maxAttempts);
if (attempts >= maxAttempts) {
clearInterval(reconnectInterval);
handleReconnectionFailure();
return;
}
// Attempt to rejoin room
// This would use your room reconnection logic
attemptRoomRejoin(room.roomID);
}, 3000); // Try every 3 seconds
}
import type { Room } from '@veniso/moitribe-js';
onRoomDisconnected: (room: Room) => {
console.log('🔌 Room connection lost');
console.log('Room ID:', room.roomID);
// Show disconnection warning
showDisconnectionWarning('Connection to room lost');
// Pause game immediately
pauseGameplay();
// Disable game controls
disableGameControls();
// Show reconnection attempt
showReconnectionScreen();
// Start reconnection timer
startReconnectionTimer();
// Save current game state
saveGameStateForReconnection();
// Notify players
showNotification('Connection lost. Attempting to reconnect...', 'warning');
// Log disconnection for analytics
logDisconnection(room);
// Attempt automatic reconnection
attemptReconnection(room);
}
// Handle reconnection
function attemptReconnection(room: Room): void {
let attempts = 0;
const maxAttempts = 5;
const reconnectInterval = setInterval(() => {
attempts++;
console.log(`Reconnection attempt ${attempts}/${maxAttempts}`);
updateReconnectionStatus(attempts, maxAttempts);
if (attempts >= maxAttempts) {
clearInterval(reconnectInterval);
handleReconnectionFailure();
return;
}
// Attempt to rejoin room
// This would use your room reconnection logic
attemptRoomRejoin(room.roomID);
}, 3000); // Try every 3 seconds
}
Room Exit Callbacks
onLeftRoom
Called when you leave the room:
- JavaScript
- TypeScript
onLeftRoom: (status, roomID) => {
console.log('🚪 Left the room');
console.log('Room ID:', roomID);
console.log('Leave status:', status);
if (status) {
console.log('✅ Successfully left room');
// Clean up game state
cleanupGameState();
// Clear room-specific data
clearRoomData();
// Stop any ongoing timers
clearAllTimers();
// Reset UI to lobby state
returnToLobbyScreen();
// Show leave confirmation
showNotification('Left room successfully', 'info');
// Log room exit for analytics
logRoomExit(roomID, 'voluntary');
// Reset player tracking
previousParticipants.clear();
// Disable voice chat
disableVoiceChat();
// Clear message history
clearMessageHistory();
} else {
console.error('❌ Failed to leave room properly');
// Force cleanup anyway
forceCleanup();
// Show error message
showNotification('Error leaving room', 'error');
// Return to lobby anyway
returnToLobbyScreen();
// Log error for debugging
logRoomExitError(roomID);
}
// Reset connection state
resetConnectionState();
}
import type { Room } from '@veniso/moitribe-js';
// Track previous participants
const previousParticipants = new Set<string>();
onLeftRoom: (status: boolean, roomID: string) => {
console.log('🚪 Left the room');
console.log('Room ID:', roomID);
console.log('Leave status:', status);
if (status) {
console.log('✅ Successfully left room');
// Clean up game state
cleanupGameState();
// Clear room-specific data
clearRoomData();
// Stop any ongoing timers
clearAllTimers();
// Reset UI to lobby state
returnToLobbyScreen();
// Show leave confirmation
showNotification('Left room successfully', 'info');
// Log room exit for analytics
logRoomExit(roomID, 'voluntary');
// Reset player tracking
previousParticipants.clear();
// Disable voice chat
disableVoiceChat();
// Clear message history
clearMessageHistory();
} else {
console.error('❌ Failed to leave room properly');
// Force cleanup anyway
forceCleanup();
// Show error message
showNotification('Error leaving room', 'error');
// Return to lobby anyway
returnToLobbyScreen();
// Log error for debugging
logRoomExitError(roomID);
}
// Reset connection state
resetConnectionState();
}
Complete Callback Implementation
Here's a comprehensive example with all callbacks:
- JavaScript
- TypeScript
const roomCallbacks = {
// Room creation and joining
onRoomCreated: (status, room) => {
if (status) {
console.log('Room created:', room.roomID);
initializeRoomUI(room);
if (room.isAutoMatch) {
startAutoMatchWaiting(room);
} else {
showInvitationCode(room.roomID);
}
} else {
console.error('Room creation failed');
showRoomCreationError();
}
},
onJoinedRoom: (status, room) => {
if (status) {
console.log('Joined room:', room.roomID);
displayRoomInfo(room);
if (room.status === 3) {
startGameplay(room);
} else {
showWaitingScreen(room);
}
} else {
console.error('Failed to join room');
showJoinError();
}
},
// Player management
onPeerJoined: (room, participantList) => {
console.log('Player joined. Total:', participantList.length);
updatePlayerList(room.participants);
checkRoomReady(room);
playSound('playerJoined');
},
onPeerLeft: (room, participantList) => {
console.log('Player left. Remaining:', participantList.length);
updatePlayerList(room.participants);
if (participantList.length < 2) {
pauseGameplay('Not enough players');
}
playSound('playerLeft');
},
// Connection management
onRoomConnected: (status, room) => {
if (status) {
console.log('Room connected and ready');
hideWaitingScreen();
startMultiplayerGame(room);
showNotification('Game starting!', 'success');
} else {
console.error('Room connection failed');
showConnectionError();
}
},
onRoomDisconnected: (room) => {
console.log('Room disconnected');
pauseGameplay();
showReconnectionScreen();
attemptReconnection(room);
},
// Room exit
onLeftRoom: (status, roomID) => {
console.log('Left room:', roomID);
cleanupGameState();
returnToLobby();
if (status) {
showNotification('Left room successfully', 'info');
} else {
showNotification('Error leaving room', 'error');
}
},
// Message handling
onMessageReceived: (messageData, senderID, isReliable) => {
handleIncomingMessage(messageData, senderID, isReliable);
}
};
// Use callbacks when creating or joining room
MoitribeSDK('my-game-id', 'createstandardroom', {
...roomParams,
...roomCallbacks
}, (result) => {
console.log('Room creation request sent');
});
import type { Room, RTMStandardParams } from '@veniso/moitribe-js';
const roomCallbacks: Partial<RTMStandardParams> = {
// Room creation and joining
onRoomCreated: (status: boolean, room: Room) => {
if (status) {
console.log('Room created:', room.roomID);
initializeRoomUI(room);
if (room.isAutoMatch) {
startAutoMatchWaiting(room);
} else {
showInvitationCode(room.roomID);
}
} else {
console.error('Room creation failed');
showRoomCreationError();
}
},
onJoinedRoom: (status: boolean, room: Room) => {
if (status) {
console.log('Joined room:', room.roomID);
displayRoomInfo(room);
if (room.status === RoomStatus.ACTIVE) {
startGameplay(room);
} else {
showWaitingScreen(room);
}
} else {
console.error('Failed to join room');
showJoinError();
}
},
// Player management
onPeerJoined: (room: Room, participantList: string[]) => {
console.log('Player joined. Total:', participantList.length);
updatePlayerList(room.participants);
checkRoomReady(room);
playSound('playerJoined');
},
onPeerLeft: (room: Room, participantList: string[]) => {
console.log('Player left. Remaining:', participantList.length);
updatePlayerList(room.participants);
if (participantList.length < 2) {
pauseGameplay('Not enough players');
}
playSound('playerLeft');
},
// Connection management
onRoomConnected: (status: boolean, room: Room) => {
if (status) {
console.log('Room connected and ready');
hideWaitingScreen();
startMultiplayerGame(room);
showNotification('Game starting!', 'success');
} else {
console.error('Room connection failed');
showConnectionError();
}
},
onRoomDisconnected: (room: Room) => {
console.log('Room disconnected');
pauseGameplay();
showReconnectionScreen();
attemptReconnection(room);
},
// Room exit
onLeftRoom: (status: boolean, roomID: string) => {
console.log('Left room:', roomID);
cleanupGameState();
returnToLobby();
if (status) {
showNotification('Left room successfully', 'info');
} else {
showNotification('Error leaving room', 'error');
}
},
// Message handling
onMessageReceived: (messageData: ArrayBuffer, senderID: string, isReliable: boolean) => {
handleIncomingMessage(messageData, senderID, isReliable);
}
};
// Use callbacks when creating or joining room
const roomParams: RTMStandardParams = {
variant: 1,
min_automatch_players: 2,
max_automatch_players: 4,
...roomCallbacks
};
MoitribeSDK('my-game-id', 'createstandardroom', roomParams, (result) => {
console.log('Room creation request sent');
});
Best Practices
Error Handling
- Always check status parameters in callbacks
- Implement graceful degradation for connection issues
- Provide user feedback for all room events
- Log errors for debugging and analytics
UI Updates
- Update UI immediately in response to callbacks
- Show loading states during transitions
- Provide clear feedback for room state changes
- Use animations for smooth transitions
State Management
- Maintain consistent state across all callbacks
- Clean up resources when leaving rooms
- Save game state for potential reconnection
- Reset state properly between sessions
Performance
- Avoid heavy operations in callback handlers
- Use debouncing for frequent updates
- Implement efficient player list management
- Cache frequently accessed data