Skip to content

Matchmaking Manager

Artur Khutak edited this page Jan 11, 2026 · 1 revision

Matchmaking Manager API Documentation

Complete reference for Steam Matchmaking (Lobby) functionality in Steamworks FFI.

Overview

The SteamMatchmakingManager provides access to Steam's ISteamMatchmaking API, enabling multiplayer lobby functionality for peer-to-peer matchmaking. This allows you to create, search, join, and manage game lobbies.

This manager is useful for:

  1. Creating lobbies: Host multiplayer sessions with configurable privacy
  2. Searching lobbies: Find and filter lobbies based on metadata
  3. Managing lobby data: Store game state and searchable metadata
  4. Lobby chat: Send and receive messages between members
  5. Player management: Track members, ready states, and ownership

Quick Reference

Category Functions Description
Lobby Creation 1 Create new lobbies
Lobby Joining 3 Join, leave, invite
Lobby Searching 8 Search with filters
Lobby Data 5 Get/set metadata
Lobby Members 8 Member management
Lobby Chat 7 Messaging system
Lobby Management 2 Type and joinability
Game Server 2 Server association

Total: 36 Functions


Lobby Types

Understanding lobby types is important for matchmaking:

enum ELobbyType {
  Private = 0,        // Only joinable via invite
  FriendsOnly = 1,    // Joinable by friends of members
  Public = 2,         // Visible in search, anyone can join
  Invisible = 3,      // Returned by search, not visible in friend list
  PrivateUnique = 4   // Private lobby with unique key
}

Lobby Creation

createLobby(lobbyType, maxMembers)

Creates a new lobby asynchronously.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_CreateLobby() - Create lobby

Parameters:

  • lobbyType: ELobbyType - Visibility type of the lobby
  • maxMembers: number - Maximum number of players (1-250)

Returns: Promise<LobbyCreateResult>

Type:

interface LobbyCreateResult {
  success: boolean;    // Whether creation succeeded
  lobbyId?: string;    // Steam ID of the created lobby
  error?: string;      // Error message if failed
}

Example:

import SteamworksSDK, { ELobbyType } from 'steamworks-ffi-node';

const steam = SteamworksSDK.getInstance();
steam.init({ appId: 480 });

// Create a public lobby for 4 players
const result = await steam.matchmaking.createLobby(ELobbyType.Public, 4);

if (result.success) {
  const lobbyId = result.lobbyId!;
  console.log(`✅ Lobby created: ${lobbyId}`);
  
  // Set searchable metadata
  steam.matchmaking.setLobbyData(lobbyId, 'gameMode', 'deathmatch');
  steam.matchmaking.setLobbyData(lobbyId, 'map', 'arena');
  steam.matchmaking.setLobbyData(lobbyId, 'version', '1.0.0');
} else {
  console.error(`❌ Failed to create lobby: ${result.error}`);
}

Notes:

  • You automatically join the lobby you create
  • Set lobby data immediately after creation for searchability
  • The creator becomes the lobby owner

Lobby Joining

Functions for joining and leaving lobbies.

joinLobby(lobbyId)

Joins an existing lobby asynchronously.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_JoinLobby() - Join lobby

Parameters:

  • lobbyId: string - Steam ID of the lobby to join

Returns: Promise<LobbyJoinResult>

Type:

interface LobbyJoinResult {
  success: boolean;                    // Whether join succeeded
  lobbyId?: string;                    // Steam ID of the joined lobby
  response: EChatRoomEnterResponse;    // Detailed response code
  locked: boolean;                     // Whether the lobby is locked
  error?: string;                      // Error message if failed
}

enum EChatRoomEnterResponse {
  Success = 1,
  DoesntExist = 2,
  NotAllowed = 3,
  Full = 4,
  Error = 5,
  Banned = 6,
  Limited = 7,
  ClanDisabled = 8,
  CommunityBan = 9,
  MemberBlockedYou = 10,
  YouBlockedMember = 11,
  RateLimited = 12
}

Example:

const result = await steam.matchmaking.joinLobby(lobbyId);

if (result.success) {
  console.log(`✅ Joined lobby: ${result.lobbyId}`);
  
  // Start receiving chat messages
  steam.matchmaking.startChatPolling(result.lobbyId!);
} else {
  console.error(`❌ Failed to join: ${result.error}`);
  
  // Handle specific errors
  if (result.response === 4) {
    console.log('Lobby is full');
  } else if (result.response === 6) {
    console.log('You are banned from this lobby');
  }
}

leaveLobby(lobbyId)

Leaves a lobby you are currently in.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_LeaveLobby() - Leave lobby

Parameters:

  • lobbyId: string - Steam ID of the lobby to leave

Returns: void

Example:

// Stop chat polling before leaving
steam.matchmaking.stopChatPolling(lobbyId);

// Leave the lobby
steam.matchmaking.leaveLobby(lobbyId);
console.log('Left lobby');

inviteUserToLobby(lobbyId, steamIdInvitee)

Invites a user to the lobby via Steam.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_InviteUserToLobby() - Send invite

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • steamIdInvitee: string - Steam ID of the user to invite

Returns: boolean - true if invite was sent

Example:

// Invite a friend to the lobby
const friendSteamId = '76561198012345678';
const invited = steam.matchmaking.inviteUserToLobby(lobbyId, friendSteamId);

if (invited) {
  console.log('✅ Invite sent!');
}

Lobby Searching

Functions for finding lobbies with filters.

requestLobbyList()

Searches for lobbies matching previously set filters.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_RequestLobbyList() - Request lobby list

Returns: Promise<LobbyListResult>

Type:

interface LobbyListResult {
  success: boolean;      // Whether search succeeded
  lobbies: string[];     // Array of lobby Steam IDs
  error?: string;        // Error message if failed
}

Example:

// Set filters before searching
steam.matchmaking.addRequestLobbyListStringFilter(
  'gameMode', 'deathmatch', ELobbyComparison.Equal
);
steam.matchmaking.addRequestLobbyListResultCountFilter(20);

// Search for lobbies
const result = await steam.matchmaking.requestLobbyList();

if (result.success) {
  console.log(`Found ${result.lobbies.length} lobbies`);
  
  for (const lobbyId of result.lobbies) {
    const members = steam.matchmaking.getNumLobbyMembers(lobbyId);
    const maxMembers = steam.matchmaking.getLobbyMemberLimit(lobbyId);
    const gameMode = steam.matchmaking.getLobbyData(lobbyId, 'gameMode');
    console.log(`Lobby ${lobbyId}: ${members}/${maxMembers} - ${gameMode}`);
  }
}

addRequestLobbyListStringFilter(key, value, comparison)

Adds a string-based filter for lobby search.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter() - Add string filter

Parameters:

  • key: string - Lobby data key to filter on
  • value: string - Value to compare against
  • comparison: ELobbyComparison - Comparison type

Comparison Types:

enum ELobbyComparison {
  EqualToOrLessThan = -2,
  LessThan = -1,
  Equal = 0,
  GreaterThan = 1,
  EqualToOrGreaterThan = 2,
  NotEqual = 3
}

Returns: void

Example:

import { ELobbyComparison } from 'steamworks-ffi-node';

// Only find lobbies with matching game mode
steam.matchmaking.addRequestLobbyListStringFilter(
  'gameMode', 'coop', ELobbyComparison.Equal
);

// Only find lobbies with matching version
steam.matchmaking.addRequestLobbyListStringFilter(
  'version', '1.0.0', ELobbyComparison.Equal
);

addRequestLobbyListNumericalFilter(key, value, comparison)

Adds a numerical filter for lobby search.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter() - Add numerical filter

Parameters:

  • key: string - Lobby data key to filter on
  • value: number - Numeric value to compare against
  • comparison: ELobbyComparison - Comparison type

Returns: void

Example:

// Find lobbies with at least 2 players
steam.matchmaking.addRequestLobbyListNumericalFilter(
  'playerCount', 2, ELobbyComparison.EqualToOrGreaterThan
);

// Find lobbies with skill rating within range
steam.matchmaking.addRequestLobbyListNumericalFilter(
  'skillRating', 1500, ELobbyComparison.EqualToOrGreaterThan
);

addRequestLobbyListNearValueFilter(key, valueToBeCloseTo)

Sorts results by proximity to a target value.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter() - Add near value filter

Parameters:

  • key: string - Lobby data key to filter on
  • valueToBeCloseTo: number - Target value to sort by proximity

Returns: void

Example:

// Find lobbies with skill rating closest to player's rating
const mySkillRating = 1200;
steam.matchmaking.addRequestLobbyListNearValueFilter('skillRating', mySkillRating);

addRequestLobbyListFilterSlotsAvailable(slotsAvailable)

Filters lobbies by available slots.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable() - Add slots filter

Parameters:

  • slotsAvailable: number - Minimum open slots required

Returns: void

Example:

// Only find lobbies with at least 2 open slots (for party of 2)
steam.matchmaking.addRequestLobbyListFilterSlotsAvailable(2);

addRequestLobbyListDistanceFilter(distanceFilter)

Filters lobbies by geographic distance.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter() - Add distance filter

Parameters:

  • distanceFilter: ELobbyDistanceFilter - Distance preference

Distance Filter Types:

enum ELobbyDistanceFilter {
  Close = 0,      // Same immediate region
  Default = 1,    // Same or nearby regions
  Far = 2,        // Same continent
  Worldwide = 3   // No distance filtering
}

Returns: void

Example:

import { ELobbyDistanceFilter } from 'steamworks-ffi-node';

// Prefer nearby lobbies for lower latency
steam.matchmaking.addRequestLobbyListDistanceFilter(ELobbyDistanceFilter.Close);

// Search worldwide if no local lobbies found
steam.matchmaking.addRequestLobbyListDistanceFilter(ELobbyDistanceFilter.Worldwide);

addRequestLobbyListResultCountFilter(maxResults)

Limits the number of lobbies returned.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter() - Add result count filter

Parameters:

  • maxResults: number - Maximum number of lobbies to return

Returns: void

Example:

// Only get top 20 lobbies
steam.matchmaking.addRequestLobbyListResultCountFilter(20);

addRequestLobbyListCompatibleMembersFilter(steamId)

Filters lobbies to only return those where the specified user can join.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter() - Add compatible members filter

Parameters:

  • steamId: string - Steam ID to check compatibility for

Returns: void

Example:

// Only show lobbies my friend can also join
steam.matchmaking.addRequestLobbyListCompatibleMembersFilter(friendSteamId);

Lobby Data

Functions for getting and setting lobby metadata.

getLobbyData(lobbyId, key)

Gets a specific metadata value from a lobby.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyData() - Get lobby data

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • key: string - Metadata key to retrieve

Returns: string - Value for the key, or empty string if not found

Example:

const gameMode = steam.matchmaking.getLobbyData(lobbyId, 'gameMode');
const map = steam.matchmaking.getLobbyData(lobbyId, 'map');
const version = steam.matchmaking.getLobbyData(lobbyId, 'version');

console.log(`Game Mode: ${gameMode}`);
console.log(`Map: ${map}`);
console.log(`Version: ${version}`);

setLobbyData(lobbyId, key, value)

Sets lobby metadata (owner only).

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_SetLobbyData() - Set lobby data

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • key: string - Metadata key to set
  • value: string - Value to set

Returns: boolean - true if successfully set

Example:

// Set game configuration data
steam.matchmaking.setLobbyData(lobbyId, 'gameMode', 'deathmatch');
steam.matchmaking.setLobbyData(lobbyId, 'map', 'arena');
steam.matchmaking.setLobbyData(lobbyId, 'status', 'waiting');
steam.matchmaking.setLobbyData(lobbyId, 'version', '1.0.0');

// Update status when game starts
steam.matchmaking.setLobbyData(lobbyId, 'status', 'in_game');

Notes:

  • Only the lobby owner can set lobby data
  • Data is automatically synced to all members
  • Use for searchable metadata and game state

deleteLobbyData(lobbyId, key)

Removes a metadata key from the lobby.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_DeleteLobbyData() - Delete lobby data

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • key: string - Metadata key to delete

Returns: boolean - true if successfully deleted

Example:

steam.matchmaking.deleteLobbyData(lobbyId, 'tempKey');

getAllLobbyData(lobbyId)

Gets all lobby metadata as an object.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyDataCount() - Get data count
  • SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex() - Get data by index

Parameters:

  • lobbyId: string - Steam ID of the lobby

Returns: Record<string, string> - All key-value pairs

Example:

const allData = steam.matchmaking.getAllLobbyData(lobbyId);
console.log('Lobby Data:', allData);
// { gameMode: 'deathmatch', map: 'arena', status: 'waiting', version: '1.0.0' }

// Iterate over all data
for (const [key, value] of Object.entries(allData)) {
  console.log(`  ${key}: ${value}`);
}

getLobbyDataCount(lobbyId)

Gets the number of metadata entries.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyDataCount() - Get data count

Parameters:

  • lobbyId: string - Steam ID of the lobby

Returns: number - Number of metadata entries

Example:

const count = steam.matchmaking.getLobbyDataCount(lobbyId);
console.log(`Lobby has ${count} metadata entries`);

Lobby Members

Functions for managing lobby members.

getNumLobbyMembers(lobbyId)

Gets the current number of members in the lobby.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetNumLobbyMembers() - Get member count

Parameters:

  • lobbyId: string - Steam ID of the lobby

Returns: number - Current member count

Example:

const memberCount = steam.matchmaking.getNumLobbyMembers(lobbyId);
const maxMembers = steam.matchmaking.getLobbyMemberLimit(lobbyId);
console.log(`Players: ${memberCount}/${maxMembers}`);

getLobbyMemberLimit(lobbyId)

Gets the maximum member limit.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit() - Get member limit

Parameters:

  • lobbyId: string - Steam ID of the lobby

Returns: number - Maximum member limit


setLobbyMemberLimit(lobbyId, maxMembers)

Sets the maximum member limit (owner only).

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit() - Set member limit

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • maxMembers: number - New maximum member limit

Returns: boolean - true if successfully set

Example:

// Expand lobby for more players
steam.matchmaking.setLobbyMemberLimit(lobbyId, 8);

getLobbyMemberByIndex(lobbyId, memberIndex)

Gets a member's Steam ID by index.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex() - Get member by index

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • memberIndex: number - Index of the member (0-based)

Returns: string - Steam ID of the member

Example:

// List all lobby members
const memberCount = steam.matchmaking.getNumLobbyMembers(lobbyId);
console.log('Lobby Members:');

for (let i = 0; i < memberCount; i++) {
  const memberId = steam.matchmaking.getLobbyMemberByIndex(lobbyId, i);
  const name = steam.friends.getFriendPersonaName(memberId);
  const isReady = steam.matchmaking.getLobbyMemberData(lobbyId, memberId, 'ready');
  console.log(`  ${i + 1}. ${name} - ${isReady === 'true' ? '✅ Ready' : '⏳ Not Ready'}`);
}

getLobbyOwner(lobbyId)

Gets the lobby owner's Steam ID.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyOwner() - Get owner

Parameters:

  • lobbyId: string - Steam ID of the lobby

Returns: string - Steam ID of the lobby owner

Example:

const ownerId = steam.matchmaking.getLobbyOwner(lobbyId);
const ownerName = steam.friends.getFriendPersonaName(ownerId);
console.log(`Host: ${ownerName}`);

// Check if current user is the owner
const myId = steam.core.getSteamId();
const isHost = ownerId === myId;

setLobbyOwner(lobbyId, newOwnerId)

Transfers lobby ownership (owner only).

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_SetLobbyOwner() - Set owner

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • newOwnerId: string - Steam ID of the new owner

Returns: boolean - true if successfully transferred

Example:

// Transfer ownership before leaving
const memberCount = steam.matchmaking.getNumLobbyMembers(lobbyId);
if (memberCount > 1) {
  const newOwner = steam.matchmaking.getLobbyMemberByIndex(lobbyId, 1);
  steam.matchmaking.setLobbyOwner(lobbyId, newOwner);
}

getLobbyMemberData(lobbyId, steamIdUser, key)

Gets a member's personal data.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyMemberData() - Get member data

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • steamIdUser: string - Steam ID of the member
  • key: string - Data key to retrieve

Returns: string - Value for the key

Example:

// Check if a member is ready
const isReady = steam.matchmaking.getLobbyMemberData(lobbyId, memberId, 'ready');
const character = steam.matchmaking.getLobbyMemberData(lobbyId, memberId, 'character');

console.log(`Player ready: ${isReady === 'true'}`);
console.log(`Selected character: ${character}`);

setLobbyMemberData(lobbyId, key, value)

Sets your own member data that others can read.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_SetLobbyMemberData() - Set member data

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • key: string - Data key to set
  • value: string - Value to set

Returns: void

Example:

// Set ready status
steam.matchmaking.setLobbyMemberData(lobbyId, 'ready', 'true');

// Set character selection
steam.matchmaking.setLobbyMemberData(lobbyId, 'character', 'warrior');

// Set team preference
steam.matchmaking.setLobbyMemberData(lobbyId, 'team', 'red');

Lobby Chat

Functions for sending and receiving messages in lobbies.

startChatPolling(lobbyId)

Starts tracking chat messages for a lobby.

Parameters:

  • lobbyId: string - Steam ID of the lobby

Returns: void

Example:

// Call after joining a lobby
await steam.matchmaking.joinLobby(lobbyId);
steam.matchmaking.startChatPolling(lobbyId);

Notes:

  • Call this immediately after joining a lobby
  • Required for receiving chat messages

stopChatPolling(lobbyId)

Stops tracking chat messages for a lobby.

Parameters:

  • lobbyId: string - Steam ID of the lobby

Returns: void

Example:

// Call before leaving a lobby
steam.matchmaking.stopChatPolling(lobbyId);
steam.matchmaking.leaveLobby(lobbyId);

pollChatMessages()

Polls for new chat messages in all tracked lobbies.

Returns: number - Number of new messages found

Example:

// In your game loop
function gameLoop() {
  steam.runCallbacks();
  steam.matchmaking.pollChatMessages();
  // ... other game logic
}

setInterval(gameLoop, 16); // ~60 FPS

onChatMessage(handler)

Subscribes to chat message events.

Parameters:

  • handler: (event: LobbyChatMessageEvent) => void - Event handler

Returns: () => void - Unsubscribe function

Type:

interface LobbyChatMessageEvent {
  lobbyId: string;           // Lobby where message was sent
  senderId: string;          // Steam ID of sender
  chatId: number;            // Message index
  entryType: EChatEntryType; // Type of chat entry
  message?: string;          // Message content
}

enum EChatEntryType {
  Invalid = 0,
  ChatMsg = 1,        // Regular chat message
  Typing = 2,         // User is typing
  InviteGame = 3,     // Game invite
  Emote = 4,          // Emote
  LeftConversation = 6,
  Entered = 7,        // User entered
  WasKicked = 8,
  WasBanned = 9,
  Disconnected = 10,
  HistoricalChat = 11,
  LinkBlocked = 14
}

Example:

// Subscribe to chat messages
const unsubscribe = steam.matchmaking.onChatMessage((event) => {
  if (event.entryType === 1) { // ChatMsg
    const senderName = steam.friends.getFriendPersonaName(event.senderId);
    console.log(`[${senderName}]: ${event.message}`);
  } else if (event.entryType === 7) { // Entered
    console.log(`Player joined the lobby`);
  }
});

// Later, stop receiving events
unsubscribe();

getPendingChatMessages()

Gets and clears all queued chat messages.

Returns: LobbyChatMessageEvent[] - Array of pending messages

Example:

// Alternative to event handlers
steam.matchmaking.pollChatMessages();
const messages = steam.matchmaking.getPendingChatMessages();

for (const msg of messages) {
  if (msg.message) {
    console.log(`${msg.senderId}: ${msg.message}`);
  }
}

sendLobbyChatMsg(lobbyId, message)

Sends a text message to the lobby.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_SendLobbyChatMsg() - Send chat message

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • message: string - Message text to send

Returns: boolean - true if sent successfully

Example:

// Send a chat message
const sent = steam.matchmaking.sendLobbyChatMsg(lobbyId, 'Hello everyone!');

if (sent) {
  console.log('Message sent');
}

getLobbyChatEntry(lobbyId, chatId)

Reads a specific chat message by index.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyChatEntry() - Get chat entry

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • chatId: number - Chat message index

Returns: LobbyChatEntry | null

Type:

interface LobbyChatEntry {
  senderId: string;       // Steam ID of sender
  message: string;        // Message text
  chatEntryType: number;  // Type of chat entry
}

Notes:

  • Usually called internally by pollChatMessages()
  • Chat IDs start at 0 and increment

Lobby Management

Functions for configuring lobby settings.

setLobbyType(lobbyId, lobbyType)

Changes the lobby type (owner only).

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_SetLobbyType() - Set lobby type

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • lobbyType: ELobbyType - New lobby type

Returns: boolean - true if successfully changed

Example:

import { ELobbyType } from 'steamworks-ffi-node';

// Make lobby friends-only after enough players join
if (memberCount >= 2) {
  steam.matchmaking.setLobbyType(lobbyId, ELobbyType.FriendsOnly);
}

// Make private when game starts
steam.matchmaking.setLobbyType(lobbyId, ELobbyType.Private);

setLobbyJoinable(lobbyId, joinable)

Sets whether the lobby can be joined (owner only).

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_SetLobbyJoinable() - Set joinable

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • joinable: boolean - Whether to allow new joins

Returns: boolean - true if successfully set

Example:

// Lock the lobby when game starts
steam.matchmaking.setLobbyJoinable(lobbyId, false);
console.log('🔒 Lobby locked');

// Unlock when returning to lobby
steam.matchmaking.setLobbyJoinable(lobbyId, true);
console.log('🔓 Lobby unlocked');

Game Server

Functions for associating dedicated servers with lobbies.

setLobbyGameServer(lobbyId, gameServerIP, gameServerPort, steamIdGameServer)

Associates a game server with the lobby.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_SetLobbyGameServer() - Set game server

Parameters:

  • lobbyId: string - Steam ID of the lobby
  • gameServerIP: number - Server IP as 32-bit integer
  • gameServerPort: number - Server port
  • steamIdGameServer: string - Server's Steam ID (or "0" if none)

Returns: void

Example:

// Convert IP string to integer
function ipToInt(ip: string): number {
  const parts = ip.split('.').map(Number);
  return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
}

// Set game server info
const serverIP = ipToInt('192.168.1.100');
steam.matchmaking.setLobbyGameServer(lobbyId, serverIP, 27015, serverSteamId);

getLobbyGameServer(lobbyId)

Gets the game server associated with a lobby.

Steamworks SDK Functions:

  • SteamAPI_ISteamMatchmaking_GetLobbyGameServer() - Get game server

Parameters:

  • lobbyId: string - Steam ID of the lobby

Returns: LobbyGameServer | null

Type:

interface LobbyGameServer {
  ip: number;        // Server IP as 32-bit integer
  port: number;      // Server port
  steamId: string;   // Server's Steam ID
}

Example:

const server = steam.matchmaking.getLobbyGameServer(lobbyId);

if (server) {
  // Convert IP integer to string
  function intToIP(int: number): string {
    return [
      (int >> 24) & 255,
      (int >> 16) & 255,
      (int >> 8) & 255,
      int & 255
    ].join('.');
  }
  
  console.log(`Server: ${intToIP(server.ip)}:${server.port}`);
  console.log(`Steam ID: ${server.steamId}`);
}

Complete Example

Host (Server)

import SteamworksSDK, { ELobbyType } from 'steamworks-ffi-node';

const steam = SteamworksSDK.getInstance();
steam.init({ appId: 480 });

let lobbyId: string | null = null;

async function createLobby() {
  const result = await steam.matchmaking.createLobby(ELobbyType.Public, 4);
  
  if (result.success) {
    lobbyId = result.lobbyId!;
    console.log(`✅ Lobby created: ${lobbyId}`);
    
    // Set lobby metadata
    steam.matchmaking.setLobbyData(lobbyId, 'gameMode', 'coop');
    steam.matchmaking.setLobbyData(lobbyId, 'map', 'forest');
    steam.matchmaking.setLobbyData(lobbyId, 'version', '1.0.0');
    steam.matchmaking.setLobbyData(lobbyId, 'status', 'waiting');
    
    // Start chat polling
    steam.matchmaking.startChatPolling(lobbyId);
    
    // Subscribe to chat
    steam.matchmaking.onChatMessage((event) => {
      if (event.message) {
        const name = steam.friends.getFriendPersonaName(event.senderId);
        console.log(`[${name}]: ${event.message}`);
      }
    });
    
    // Set host as ready
    steam.matchmaking.setLobbyMemberData(lobbyId, 'ready', 'true');
    
    return lobbyId;
  }
  return null;
}

// Game loop
function gameLoop() {
  steam.runCallbacks();
  steam.matchmaking.pollChatMessages();
  
  if (lobbyId) {
    const members = steam.matchmaking.getNumLobbyMembers(lobbyId);
    console.log(`Players: ${members}/4`);
  }
}

// Main
createLobby().then(() => {
  setInterval(gameLoop, 1000);
});

// Cleanup
process.on('SIGINT', () => {
  if (lobbyId) {
    steam.matchmaking.stopChatPolling(lobbyId);
    steam.matchmaking.leaveLobby(lobbyId);
  }
  steam.shutdown();
  process.exit(0);
});

Client (Joiner)

import SteamworksSDK, { ELobbyComparison, ELobbyDistanceFilter } from 'steamworks-ffi-node';

const steam = SteamworksSDK.getInstance();
steam.init({ appId: 480 });

let currentLobby: string | null = null;

async function findAndJoinLobby() {
  // Set search filters
  steam.matchmaking.addRequestLobbyListStringFilter(
    'gameMode', 'coop', ELobbyComparison.Equal
  );
  steam.matchmaking.addRequestLobbyListDistanceFilter(ELobbyDistanceFilter.Default);
  steam.matchmaking.addRequestLobbyListResultCountFilter(10);
  
  // Search
  const result = await steam.matchmaking.requestLobbyList();
  
  if (!result.success || result.lobbies.length === 0) {
    console.log('No lobbies found');
    return null;
  }
  
  console.log(`Found ${result.lobbies.length} lobbies`);
  
  // Display lobbies
  for (const lobbyId of result.lobbies) {
    const members = steam.matchmaking.getNumLobbyMembers(lobbyId);
    const max = steam.matchmaking.getLobbyMemberLimit(lobbyId);
    const map = steam.matchmaking.getLobbyData(lobbyId, 'map');
    console.log(`  ${lobbyId}: ${members}/${max} - ${map}`);
  }
  
  // Join first lobby
  const joinResult = await steam.matchmaking.joinLobby(result.lobbies[0]);
  
  if (joinResult.success) {
    currentLobby = joinResult.lobbyId!;
    console.log(`✅ Joined lobby: ${currentLobby}`);
    
    // Start chat
    steam.matchmaking.startChatPolling(currentLobby);
    steam.matchmaking.onChatMessage((event) => {
      if (event.message) {
        const name = steam.friends.getFriendPersonaName(event.senderId);
        console.log(`[${name}]: ${event.message}`);
      }
    });
    
    // Set ready
    steam.matchmaking.setLobbyMemberData(currentLobby, 'ready', 'true');
    
    // Say hello
    steam.matchmaking.sendLobbyChatMsg(currentLobby, 'Hello!');
    
    return currentLobby;
  }
  
  return null;
}

// Game loop
function gameLoop() {
  steam.runCallbacks();
  steam.matchmaking.pollChatMessages();
}

// Main
findAndJoinLobby().then(() => {
  setInterval(gameLoop, 100);
});

// Cleanup
process.on('SIGINT', () => {
  if (currentLobby) {
    steam.matchmaking.stopChatPolling(currentLobby);
    steam.matchmaking.leaveLobby(currentLobby);
  }
  steam.shutdown();
  process.exit(0);
});

Testing

Run the matchmaking tests using two Steam accounts:

Terminal 1 (Host):

# TypeScript
npm run test:matchmaking:host:ts

# JavaScript
npm run test:matchmaking:host:js

Terminal 2 (Client):

# TypeScript
npm run test:matchmaking:join:ts

# JavaScript
npm run test:matchmaking:join:js

Direct join with lobby ID:

npx ts-node tests/ts/test-matchmaking-join.ts <lobbyId>

Best Practices

  1. Always set metadata - Set searchable data immediately after creating a lobby
  2. Use version filtering - Filter by game version to prevent incompatible matches
  3. Limit search results - Use addRequestLobbyListResultCountFilter() to cap results
  4. Poll callbacks regularly - Call runCallbacks() and pollChatMessages() frequently
  5. Clean up properly - Stop chat polling and leave lobbies before shutdown
  6. Handle all join responses - Check EChatRoomEnterResponse for specific errors

Error Handling

Response Code Value Meaning Solution
Success 1 Joined successfully -
DoesntExist 2 Lobby no longer exists Refresh lobby list
NotAllowed 3 Permission denied Check lobby type
Full 4 Lobby is full Find another lobby
Error 5 Unexpected error Retry
Banned 6 User is banned Cannot join
Limited 7 Limited account Full Steam account required
RateLimited 12 Too many requests Wait and retry

Related Documentation

Clone this wiki locally