Skip to main content

Reliable vs Unreliable Messaging

In real-time multiplayer games, you can choose between reliable and unreliable message delivery based on your game's requirements. Each type has specific use cases and performance characteristics.

Message Reliability Types

Reliable Messages

Reliable messages are guaranteed to be delivered in order, but may have higher latency due to retransmission and acknowledgment mechanisms.

Use Cases:

  • Game state changes
  • Turn-based actions
  • Chat messages
  • Score updates
  • Critical game events

Unreliable Messages

Unreliable messages are sent without guarantees of delivery or order, providing lower latency but potentially dropping packets.

Use Cases:

  • Player position updates
  • Continuous movement data
  • Transient game states
  • Real-time animations
  • Frequent sensor data

Implementation

The SDK provides message reliability through the isReliable parameter when sending messages.

JavaScript Example

// Send reliable message (game state change)
MoitribeSDK('my-game', 'sendmsg', {
message: gameStateData,
isReliable: true
}, (result) => {
console.log('Reliable message sent:', result.success);
});

// Send unreliable message (position update)
MoitribeSDK('my-game', 'sendmsg', {
message: positionData,
isReliable: false
}, (result) => {
console.log('Unreliable message sent:', result.success);
});

TypeScript Example

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

interface GameState {
playerTurn: string;
action: 'move' | 'attack' | 'defend';
}

interface Position {
x: number;
y: number;
z: number;
}

// Send reliable message with typed data
const gameState: GameState = {
playerTurn: 'player1',
action: 'move'
};

MoitribeSDK('my-game', 'sendmsg', {
message: JSON.stringify(gameState),
isReliable: true
}, (result: { success: boolean }) => {
console.log('Game state sent:', result.success);
});

// Send unreliable message with position data
const position: Position = { x: 100, y: 50, z: 0 };

MoitribeSDK('my-game', 'sendmsg', {
message: JSON.stringify(position),
isReliable: false
}, (result: { success: boolean }) => {
console.log('Position update sent:', result.success);
});

Receiving Messages

When receiving messages, the isReliable parameter indicates how the message was sent:

// Message callback setup
const messageCallback = (messageData, senderParticipantID, isReliable) => {
console.log(`Message from ${senderParticipantID}`);
console.log(`Reliable: ${isReliable}`);

if (isReliable) {
// Handle critical game data
const gameState = JSON.parse(messageData);
processGameState(gameState);
} else {
// Handle transient data like positions
const position = JSON.parse(messageData);
updatePlayerPosition(senderParticipantID, position);
}
};

Performance Considerations

Network Impact

Message TypeLatencyBandwidthCPU Usage
ReliableHigherHigherHigher
UnreliableLowerLowerLower

When to Use Each Type

Best Practice

Use reliable messages for anything that affects game logic or player experience if lost. Use unreliable messages for data that can be safely discarded or quickly outdated.

Choose Reliable for:

  • Game-critical events (player death, level completion)
  • Turn-based game moves
  • Chat and communication
  • Score and achievement updates
  • Inventory changes

Choose Unreliable for:

  • Real-time position updates (30+ times per second)
  • Animation states
  • Temporary visual effects
  • Sensor data that becomes stale quickly
  • Redundant data streams

Hybrid Approach

Many games use both types strategically:

// Example: Real-time action game
function sendGameUpdate() {
// Unreliable: Position (sent frequently)
MoitribeSDK('my-game', 'sendmsg', {
message: JSON.stringify({
type: 'position',
x: player.x,
y: player.y
}),
isReliable: false
});

// Reliable: Action (sent only when needed)
if (player.actionChanged) {
MoitribeSDK('my-game', 'sendmsg', {
message: JSON.stringify({
type: 'action',
action: player.currentAction
}),
isReliable: true
});
player.actionChanged = false;
}
}

Common Patterns

Interpolation for Unreliable Data

Since unreliable messages may be dropped, implement interpolation:

let lastPosition = { x: 0, y: 0 };
let targetPosition = { x: 0, y: 0 };

function handlePositionUpdate(data) {
lastPosition = { ...targetPosition };
targetPosition = JSON.parse(data);
}

function interpolate() {
// Smooth movement between last and target positions
const currentX = lastPosition.x + (targetPosition.x - lastPosition.x) * 0.1;
const currentY = lastPosition.y + (targetPosition.y - lastPosition.y) * 0.1;

renderPlayer(currentX, currentY);
requestAnimationFrame(interpolate);
}

Acknowledgment for Critical Messages

For extra reliability, implement acknowledgment patterns:

const pendingMessages = new Map();

function sendCriticalMessage(data) {
const messageId = generateId();
pendingMessages.set(messageId, {
data,
timestamp: Date.now(),
retries: 0
});

MoitribeSDK('my-game', 'sendmsg', {
message: JSON.stringify({
id: messageId,
...data
}),
isReliable: true
});
}

function handleAcknowledgment(data) {
const { messageId } = JSON.parse(data);
pendingMessages.delete(messageId);
}

Error Handling

MoitribeSDK('my-game', 'sendmsg', {
message: gameData,
isReliable: true
}, (result) => {
if (!result.success) {
console.error('Message failed:', result.msg);

// Retry logic for critical messages
if (result.msg.includes('connection')) {
setTimeout(() => {
sendReliableMessage(gameData);
}, 1000);
}
}
});

Next Steps