Room Callbacks
Endless rooms provide various callbacks to handle room events, player connections, and state changes. These callbacks allow you to create responsive multiplayer experiences.
Available Callbacks
Connection Callbacks
| Callback | Description |
|---|---|
onRoomCreated | Called when room is successfully created |
onJoinedRoom | Called when successfully joined a room |
onLeftRoom | Called when left a room |
onConnectedToRoom | Called when fully connected to room |
onDisconnectedFromRoom | Called when disconnected from room |
Player Management Callbacks
| Callback | Description |
|---|---|
onPeerJoined | Called when a player joins the room |
onPeerLeft | Called when a player leaves the room |
onPeerConnected | Called when a player connects to room |
onPeerDisconnected | Called when a player disconnects from room |
Reconnection Callbacks
| Callback | Description |
|---|---|
reconnectSuccessful | Called when reconnection succeeds |
attemptingReconnect | Called when attempting to reconnect |
Examples
Complete Callback Setup
MoitribeSDK('my-game', 'createendlessroom', {
variant: 1,
// Room lifecycle callbacks
onRoomCreated: (status, room) => {
if (status) {
console.log('Room created:', room.roomID);
initializeGame(room);
showInvitationCode(room.roomID);
} else {
console.error('Failed to create room');
showCreationError();
}
},
onJoinedRoom: (status, room) => {
if (status) {
console.log('Joined room:', room.roomID);
syncWithRoomState(room);
enableGameControls();
} else {
console.error('Failed to join room');
showJoinError();
}
},
onLeftRoom: (status, roomID) => {
console.log('Left room:', roomID);
cleanupGameState();
showMainMenu();
},
onConnectedToRoom: (room) => {
console.log('Connected to room, ready to play');
startGameLoop();
announcePlayerJoin();
},
onDisconnectedFromRoom: (room) => {
console.log('Disconnected from room');
pauseGameLoop();
showReconnectDialog();
},
// Player management callbacks
onPeerJoined: (room, participantList) => {
console.log('Player joined. Total players:', participantList.length);
updatePlayerList(room.participants);
showJoinNotification(getLastJoinedPlayer(room));
},
onPeerLeft: (room, participantList) => {
console.log('Player left. Total players:', participantList.length);
updatePlayerList(room.participants);
showLeaveNotification(getLastLeftPlayer(room));
handlePlayerDisconnection(getLastLeftPlayer(room));
},
onPeerConnected: (room, participantList) => {
console.log('Player connected to room');
updateConnectionStatus(room.participants);
},
onPeerDisconnected: (room, participantList) => {
console.log('Player disconnected from room');
updateConnectionStatus(room.participants);
handlePlayerDisconnection(getDisconnectedPlayer(room));
},
// Reconnection callbacks
attemptingReconnect: () => {
console.log('Attempting to reconnect...');
showReconnectingIndicator();
},
reconnectSuccessful: () => {
console.log('Reconnection successful');
hideReconnectingIndicator();
syncWithServer();
},
// Message callback
onMessageReceived: (messageData, senderParticipantID, isReliable) => {
handleIncomingMessage(messageData, senderParticipantID, isReliable);
}
}, (result) => {
console.log('Room creation request sent:', result);
});
TypeScript Example
import MoitribeSDK from '@veniso/moitribe-js';
interface RoomCallbacks {
onRoomCreated?: (status: boolean, room: Room) => void;
onJoinedRoom?: (status: boolean, room: Room) => void;
onLeftRoom?: (status: boolean, roomID: string) => void;
onConnectedToRoom?: (room: Room) => void;
onDisconnectedFromRoom?: (room: Room) => void;
onPeerJoined?: (room: Room, participantList: string[]) => void;
onPeerLeft?: (room: Room, participantList: string[]) => void;
onPeerConnected?: (room: Room, participantList: string[]) => void;
onPeerDisconnected?: (room: Room, participantList: string[]) => void;
attemptingReconnect?: () => void;
reconnectSuccessful?: () => void;
onMessageReceived?: (messageData: ArrayBuffer, senderParticipantID: string, isReliable: boolean) => void;
}
class EndlessRoomManager {
private currentRoom: Room | null = null;
private playerStates = new Map<string, PlayerState>();
createRoom(variant: number): void {
const callbacks: RoomCallbacks = {
onRoomCreated: this.handleRoomCreated.bind(this),
onJoinedRoom: this.handleJoinedRoom.bind(this),
onLeftRoom: this.handleLeftRoom.bind(this),
onConnectedToRoom: this.handleConnectedToRoom.bind(this),
onDisconnectedFromRoom: this.handleDisconnectedFromRoom.bind(this),
onPeerJoined: this.handlePeerJoined.bind(this),
onPeerLeft: this.handlePeerLeft.bind(this),
onPeerConnected: this.handlePeerConnected.bind(this),
onPeerDisconnected: this.handlePeerDisconnected.bind(this),
attemptingReconnect: this.handleAttemptingReconnect.bind(this),
reconnectSuccessful: this.handleReconnectSuccessful.bind(this),
onMessageReceived: this.handleMessageReceived.bind(this)
};
MoitribeSDK('my-game', 'createendlessroom', {
variant,
...callbacks
});
}
private handleRoomCreated(status: boolean, room: Room): void {
if (status) {
this.currentRoom = room;
console.log(`Room created: ${room.roomID}`);
this.initializeGameState(room);
this.showRoomUI(room);
} else {
console.error('Room creation failed');
this.showCreationError();
}
}
private handleJoinedRoom(status: boolean, room: Room): void {
if (status) {
this.currentRoom = room;
console.log(`Joined room: ${room.roomID}`);
this.syncWithExistingRoom(room);
this.enableGameplay();
} else {
console.error('Failed to join room');
this.showJoinError();
}
}
private handleLeftRoom(status: boolean, roomID: string): void {
console.log(`Left room: ${roomID}`);
this.currentRoom = null;
this.cleanupGameState();
this.returnToMainMenu();
}
private handleConnectedToRoom(room: Room): void {
console.log('Fully connected to room');
this.startGameLoop();
this.broadcastPlayerJoin();
}
private handleDisconnectedFromRoom(room: Room): void {
console.log('Disconnected from room');
this.pauseGameLoop();
this.attemptReconnection();
}
private handlePeerJoined(room: Room, participantList: string[]): void {
console.log(`Player joined. Total: ${participantList.length}`);
this.updatePlayerList(room.participants);
this.showJoinNotification(this.getLastJoinedPlayer(room));
}
private handlePeerLeft(room: Room, participantList: string[]): void {
console.log(`Player left. Total: ${participantList.length}`);
this.updatePlayerList(room.participants);
this.handlePlayerDeparture(this.getLastLeftPlayer(room));
}
private handlePeerConnected(room: Room, participantList: string[]): void {
console.log('Player reconnected');
this.updateConnectionIndicators(room.participants);
}
private handlePeerDisconnected(room: Room, participantList: string[]): void {
console.log('Player disconnected');
this.updateConnectionIndicators(room.participants);
this.handlePlayerLoss(this.getDisconnectedPlayer(room));
}
private handleAttemptingReconnect(): void {
console.log('Attempting to reconnect...');
this.showReconnectingUI();
}
private handleReconnectSuccessful(): void {
console.log('Reconnection successful');
this.hideReconnectingUI();
this.resyncWithServer();
}
private handleMessageReceived(messageData: ArrayBuffer, senderParticipantID: string, isReliable: boolean): void {
this.processIncomingMessage(messageData, senderParticipantID, isReliable);
}
// Helper methods
private initializeGameState(room: Room): void {
// Initialize game state for new room
}
private syncWithExistingRoom(room: Room): void {
// Sync with existing room state
}
private updatePlayerList(participants: Participant[]): void {
// Update UI player list
}
private getLastJoinedPlayer(room: Room): Participant {
// Find most recently joined participant
return room.participants[room.participants.length - 1];
}
private getLastLeftPlayer(room: Room): Participant | null {
// Track who left (requires additional state tracking)
return null;
}
private getDisconnectedPlayer(room: Room): Participant | null {
// Find disconnected participant
return room.participants.find(p => !p.isConnected) || null;
}
}
Callback Patterns
State Management
const roomState = {
isConnected: false,
players: new Map(),
gameActive: false,
reconnectAttempts: 0
};
const callbacks = {
onConnectedToRoom: (room) => {
roomState.isConnected = true;
roomState.gameActive = true;
roomState.reconnectAttempts = 0;
// Initialize player states
room.participants.forEach(player => {
roomState.players.set(player.participantID, {
...player,
lastSeen: Date.now()
});
});
},
onDisconnectedFromRoom: (room) => {
roomState.isConnected = false;
roomState.gameActive = false;
// Mark all players as disconnected
roomState.players.forEach(player => {
player.isConnected = false;
});
},
onPeerJoined: (room, participantList) => {
// Add new player to state
const newPlayer = room.participants[room.participants.length - 1];
roomState.players.set(newPlayer.participantID, {
...newPlayer,
lastSeen: Date.now()
});
},
onPeerLeft: (room, participantList) => {
// Remove player from state
const leftPlayer = findLeftPlayer(room);
if (leftPlayer) {
roomState.players.delete(leftPlayer.participantID);
}
}
};
UI Updates
const uiCallbacks = {
onRoomCreated: (status, room) => {
if (status) {
showRoomScreen();
updateRoomInfo(room);
showInvitationDialog(room.roomID);
} else {
showError('Failed to create room');
}
},
onJoinedRoom: (status, room) => {
if (status) {
showGameScreen();
updatePlayerList(room.participants);
startLoadingGameAssets();
} else {
showError('Failed to join room');
}
},
onPeerJoined: (room, participantList) => {
const newPlayer = room.participants[room.participants.length - 1];
addPlayerToList(newPlayer);
showJoinNotification(newPlayer.name);
updatePlayerCount(participantList.length);
},
onPeerLeft: (room, participantList) => {
removePlayerFromList(findLeftPlayer(room));
updatePlayerCount(participantList.length);
showLeaveNotification();
},
attemptingReconnect: () => {
showReconnectingOverlay();
updateReconnectStatus('Attempting to reconnect...');
},
reconnectSuccessful: () => {
hideReconnectingOverlay();
showSuccessMessage('Reconnected successfully');
}
};
Error Handling
const errorHandlingCallbacks = {
onRoomCreated: (status, room) => {
if (!status) {
console.error('Room creation failed');
handleRoomCreationError(room?.msg);
}
},
onJoinedRoom: (status, room) => {
if (!status) {
console.error('Room join failed');
handleRoomJoinError(room?.msg);
}
},
onDisconnectedFromRoom: (room) => {
console.error('Unexpected disconnection');
handleUnexpectedDisconnection(room);
},
attemptingReconnect: () => {
roomState.reconnectAttempts++;
if (roomState.reconnectAttempts > MAX_RECONNECT_ATTEMPTS) {
console.error('Max reconnection attempts reached');
showFatalError('Unable to reconnect to room');
returnToMainMenu();
}
}
};
Advanced Patterns
Callback Chaining
function createCallbackChain() {
const callbacks = [];
return {
add: (callback) => callbacks.push(callback),
execute: (...args) => callbacks.forEach(cb => cb(...args))
};
}
// Usage
const onRoomCreatedChain = createCallbackChain();
onRoomCreatedChain.add((status, room) => updateUI(status, room));
onRoomCreatedChain.add((status, room) => logEvent(status, room));
onRoomCreatedChain.add((status, room) => analytics.track('room_created', { status }));
// In room creation
onRoomCreated: onRoomCreatedChain.execute
Conditional Callbacks
function createConditionalCallbacks(condition) {
return {
onRoomCreated: condition ? (status, room) => {
console.log('Conditional room created callback');
} : undefined,
onPeerJoined: condition ? (room, participantList) => {
console.log('Conditional peer joined callback');
} : undefined
};
}
// Usage
const isDebugMode = true;
const debugCallbacks = createConditionalCallbacks(isDebugMode);
MoitribeSDK('my-game', 'createendlessroom', {
...debugCallbacks,
// Other callbacks
});
Best Practices
Callback Cleanup
let roomCallbacks = null;
function createRoom() {
// Clean up previous callbacks
if (roomCallbacks) {
cleanupCallbacks(roomCallbacks);
}
roomCallbacks = {
onRoomCreated: handleRoomCreated,
onJoinedRoom: handleJoinedRoom,
// ... other callbacks
};
MoitribeSDK('my-game', 'createendlessroom', roomCallbacks);
}
function cleanupCallbacks(callbacks) {
// Cancel any pending operations
// Clear timers
// Reset state
console.log('Callbacks cleaned up');
}
Callback Debouncing
const debouncedCallbacks = {
onPeerJoined: debounce((room, participantList) => {
updatePlayerList(room.participants);
showJoinNotification();
}, 100),
onPeerLeft: debounce((room, participantList) => {
updatePlayerList(room.participants);
showLeaveNotification();
}, 100)
};
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
Next Steps
- Create Room - Set up room creation
- Join Room - Join existing rooms
- Send Messages - Implement communication
- Leave Room - Properly exit rooms
Pro Tip
Always implement proper error handling in callbacks, especially for network-related events like disconnections and reconnection attempts.