Skip to main content

Send Message to Specific Player

Send messages to specific players in an endless room using their participant IDs. This is ideal for private messages, targeted game events, and player-specific updates.

Method

MoitribeSDK('game-id', 'endlessmessage', params, callback)

Parameters

ParameterTypeRequiredDescription
messageDataArrayBufferYesMessage data to send
participantIdsstring[]YesArray of participant IDs to send to
isReliablebooleanNoWhether message must be delivered (default: true)

Response Format

{
success: boolean;
msg?: string;
}

Examples

JavaScript Example

// Send private message to a specific player
function sendPrivateMessage(participantId, text) {
const encoder = new TextEncoder();
const messageData = encoder.encode(text);

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: [participantId],
isReliable: true
}, (result) => {
if (result.success) {
console.log('Private message sent to:', participantId);
} else {
console.error('Failed to send private message:', result.msg);
}
});
}

// Send game event to specific players
function sendGameEventToPlayers(participantIds, eventType, data) {
const eventData = {
type: eventType,
data: data,
timestamp: Date.now()
};

const encoder = new TextEncoder();
const messageData = encoder.encode(JSON.stringify(eventData));

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: participantIds,
isReliable: true
}, (result) => {
console.log(`Event sent to ${participantIds.length} players:`, result.success);
});
}

// Send power-up to specific player
function sendPowerUp(participantId, powerUpType) {
const buffer = new ArrayBuffer(2);
const view = new DataView(buffer);
view.setUint8(0, 1); // Message type: power-up
view.setUint8(1, powerUpType);

MoitribeSDK('my-game', 'endlessmessage', {
messageData: buffer,
participantIds: [participantId],
isReliable: true
}, (result) => {
if (result.success) {
console.log(`Power-up ${powerUpType} sent to player`);
}
});
}

TypeScript Example

import MoitribeSDK from '@veniso/moitribe-js';

// Send targeted game event
interface TargetedEvent {
type: 'damage' | 'heal' | 'powerup' | 'effect';
targetPlayerId: string;
value: number;
sourcePlayerId: string;
timestamp: number;
}

function sendTargetedEvent(event: TargetedEvent): void {
const messageData = encodeTargetedEvent(event);

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData,
participantIds: [event.targetPlayerId],
isReliable: true
}, (result: any) => {
if (result.success) {
console.log(`Targeted event sent: ${event.type} to ${event.targetPlayerId}`);
} else {
console.error('Failed to send targeted event:', result.msg);
}
});
}

// Send to multiple specific players
function sendTeamMessage(teamMemberIds: string[], message: string): void {
const encoder = new TextEncoder();
const messageData = encoder.encode(message);

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: teamMemberIds,
isReliable: true
}, (result: any) => {
console.log(`Team message sent to ${teamMemberIds.length} members:`, result.success);
});
}

// Helper function to encode targeted events
function encodeTargetedEvent(event: TargetedEvent): ArrayBuffer {
const json = JSON.stringify(event);
const encoder = new TextEncoder();
return encoder.encode(json).buffer;
}

// Usage examples
sendTargetedEvent({
type: 'damage',
targetPlayerId: 'player123',
value: 25,
sourcePlayerId: 'player456',
timestamp: Date.now()
});

Finding Participant IDs

From Room Object

// Get participant IDs from room object
function getParticipantIds(room) {
return room.participants.map(participant => participant.participantID);
}

// Get specific participant ID by player name
function getParticipantIdByName(room, playerName) {
const participant = room.participants.find(p => p.name === playerName);
return participant ? participant.participantID : null;
}

// Usage
onConnectedToRoom: (room) => {
const allPlayerIds = getParticipantIds(room);
const targetPlayerId = getParticipantIdByName(room, 'Alice');

if (targetPlayerId) {
sendPrivateMessage(targetPlayerId, 'Hello Alice!');
}
}

From Message Events

// Store participant IDs when they join
const participantMap = new Map();

onPeerJoined: (room, participantList) => {
room.participants.forEach(participant => {
participantMap.set(participant.playerID, participant.participantID);
});
};

onMessageReceived: (messageData, senderParticipantID, isReliable) => {
// senderParticipantID is the participant ID you can reply to
sendPrivateMessage(senderParticipantID, 'Message received!');
};

Use Cases

Private Chat System

function sendPrivateChat(recipientPlayerId, message) {
const recipientParticipantId = participantMap.get(recipientPlayerId);

if (!recipientParticipantId) {
console.error('Player not found in room');
return;
}

const chatData = {
type: 'private_chat',
message: message,
sender: getCurrentPlayerId(),
timestamp: Date.now()
};

const encoder = new TextEncoder();
const messageData = encoder.encode(JSON.stringify(chatData));

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: [recipientParticipantId],
isReliable: true
});
}

Team Communication

function sendTeamChat(teamId, message) {
const teamMembers = getTeamMembers(teamId);
const teamParticipantIds = teamMembers.map(member =>
participantMap.get(member.playerId)
).filter(Boolean);

const teamData = {
type: 'team_chat',
teamId: teamId,
message: message,
sender: getCurrentPlayerId(),
timestamp: Date.now()
};

const encoder = new TextEncoder();
const messageData = encoder.encode(JSON.stringify(teamData));

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: teamParticipantIds,
isReliable: true
});
}

Targeted Game Events

// Send damage to specific player
function dealDamage(targetPlayerId, damageAmount, sourcePlayerId) {
const targetParticipantId = participantMap.get(targetPlayerId);

if (!targetParticipantId) return;

const damageData = {
type: 'damage',
amount: damageAmount,
source: sourcePlayerId,
timestamp: Date.now()
};

const encoder = new TextEncoder();
const messageData = encoder.encode(JSON.stringify(damageData));

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: [targetParticipantId],
isReliable: true
});
}

// Send healing to specific player
function healPlayer(targetPlayerId, healAmount) {
const targetParticipantId = participantMap.get(targetPlayerId);

if (!targetParticipantId) return;

const healData = {
type: 'heal',
amount: healAmount,
timestamp: Date.now()
};

const encoder = new TextEncoder();
const messageData = encoder.encode(JSON.stringify(healData));

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: [targetParticipantId],
isReliable: true
});
}

Multiple Recipients

Send to Group

function sendToGroup(participantIds, data) {
const encoder = new TextEncoder();
const messageData = encoder.encode(JSON.stringify(data));

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: participantIds,
isReliable: true
}, (result) => {
console.log(`Message sent to ${participantIds.length} players:`, result.success);
});
}

// Usage
const selectedPlayers = ['participant1', 'participant2', 'participant3'];
sendToGroup(selectedPlayers, {
type: 'group_invite',
gameId: 'battle_royale_001'
});

Send to All Except One

function sendToAllExcept(excludeParticipantId, data) {
const allParticipantIds = Array.from(participantMap.values());
const recipients = allParticipantIds.filter(id => id !== excludeParticipantId);

const encoder = new TextEncoder();
const messageData = encoder.encode(JSON.stringify(data));

MoitribeSDK('my-game', 'endlessmessage', {
messageData: messageData.buffer,
participantIds: recipients,
isReliable: true
});
}

Error Handling

function sendTargetedMessageWithErrorHandling(participantIds, messageData, isReliable = true) {
MoitribeSDK('my-game', 'endlessmessage', {
messageData,
participantIds,
isReliable
}, (result) => {
if (!result.success) {
console.error('Targeted message failed:', result.msg);

// Handle specific errors
if (result.msg?.includes('invalid participant')) {
console.error('One or more participant IDs are invalid');
// Remove invalid participants from local cache
cleanupInvalidParticipants(participantIds);
} else if (result.msg?.includes('not in room')) {
showReconnectDialog();
}
}
});
}

Performance Considerations

Batch Targeted Messages

// Instead of sending multiple individual messages
function sendIndividualUpdates(players, updates) {
players.forEach((player, index) => {
sendPrivateMessage(player, updates[index]);
});
}

// Batch them when possible
function sendBatchedUpdates(players, updates) {
const batchData = {
type: 'batched_updates',
updates: players.map((player, index) => ({
playerId: player,
data: updates[index]
}))
};

// Send to all players and let them filter their own data
sendToAll(batchData);
}

Best Practices

Validate Participant IDs

function validateParticipantIds(participantIds) {
const allValidIds = Array.from(participantMap.values());
return participantIds.filter(id => allValidIds.includes(id));
}

// Usage
const requestedIds = ['id1', 'id2', 'invalid_id'];
const validIds = validateParticipantIds(requestedIds);

if (validIds.length > 0) {
sendToGroup(validIds, messageData);
}

Rate Limiting

const messageTimestamps = new Map();
const RATE_LIMIT_MS = 1000; // 1 second between messages to same player

function sendWithRateLimit(participantId, messageData) {
const now = Date.now();
const lastSent = messageTimestamps.get(participantId) || 0;

if (now - lastSent >= RATE_LIMIT_MS) {
MoitribeSDK('my-game', 'endlessmessage', {
messageData,
participantIds: [participantId],
isReliable: true
});

messageTimestamps.set(participantId, now);
} else {
console.log('Rate limited - message not sent');
}
}

Next Steps

Pro Tip

Keep a mapping of player IDs to participant IDs for easy targeting. Update this mapping whenever players join or leave the room.