Matchmaking Manager - ArtyProf/steamworks-ffi-node GitHub Wiki
Complete reference for Steam Matchmaking (Lobby) functionality in Steamworks FFI.
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:
- Creating lobbies: Host multiplayer sessions with configurable privacy
- Searching lobbies: Find and filter lobbies based on metadata
- Managing lobby data: Store game state and searchable metadata
- Lobby chat: Send and receive messages between members
- Player management: Track members, ready states, and ownership
| 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
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
}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
Functions for joining and leaving lobbies.
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');
}
}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');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!');
}Functions for finding lobbies with filters.
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}`);
}
}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
);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
);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);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);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);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);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);Functions for getting and setting lobby metadata.
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}`);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
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');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}`);
}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`);Functions for managing lobby members.
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}`);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
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);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'}`);
}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;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);
}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}`);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');Functions for sending and receiving messages in lobbies.
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
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);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 FPSSubscribes 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();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}`);
}
}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');
}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
Functions for configuring lobby settings.
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);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');Functions for associating dedicated servers with lobbies.
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);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}`);
}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);
});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);
});Run the matchmaking tests using two Steam accounts:
Terminal 1 (Host):
# TypeScript
npm run test:matchmaking:host:ts
# JavaScript
npm run test:matchmaking:host:jsTerminal 2 (Client):
# TypeScript
npm run test:matchmaking:join:ts
# JavaScript
npm run test:matchmaking:join:jsDirect join with lobby ID:
npx ts-node tests/ts/test-matchmaking-join.ts <lobbyId>- Always set metadata - Set searchable data immediately after creating a lobby
- Use version filtering - Filter by game version to prevent incompatible matches
-
Limit search results - Use
addRequestLobbyListResultCountFilter()to cap results -
Poll callbacks regularly - Call
runCallbacks()andpollChatMessages()frequently - Clean up properly - Stop chat polling and leave lobbies before shutdown
-
Handle all join responses - Check
EChatRoomEnterResponsefor specific errors
| 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 |
- Friends Manager - For inviting friends
- Overlay Manager - For invite dialogs
- Networking Sockets Manager - For P2P connections after matchmaking
- Networking Utils Manager - For ping estimation