Skip to content

Steam Lobbies and P2P

Multiplayer features with Steam networking.

Lobbies

requestLobbyList()

Search for available lobbies.

javascript
const count = await steam.requestLobbyList();

createLobby(type, maxMembers)

Create a new lobby.

javascript
const lobbyId = await steam.createLobby(2, 4); // Public, 4 players

Lobby Types:

  • 0 - Private
  • 1 - Friends Only
  • 2 - Public
  • 3 - Invisible

joinLobby(lobbyId)

Join an existing lobby.

javascript
await steam.joinLobby(lobbyId);

leaveLobby()

Leave current lobby.

javascript
await steam.leaveLobby();

getLobbyData(key)

Get lobby metadata from current lobby.

javascript
const mapName = await steam.getLobbyData('map');

setLobbyData(key, value)

Set lobby metadata (owner only).

javascript
await steam.setLobbyData('map', 'forest');
await steam.setLobbyData('mode', 'deathmatch');

getLobbyMembers()

Get list of members in current lobby.

javascript
const members = await steam.getLobbyMembers();
// Array of Steam IDs

getLobbyOwner()

Get the lobby owner's Steam ID.

javascript
const owner = await steam.getLobbyOwner();

getLobbyMemberLimit()

Get maximum number of members allowed.

javascript
const max = await steam.getLobbyMemberLimit();

setLobbyJoinable(joinable)

Set whether the lobby can be joined.

javascript
await steam.setLobbyJoinable(false); // Lock lobby

inviteUserToLobby(steamId)

Invite a user to the lobby.

javascript
await steam.inviteUserToLobby('76561198012345678');

P2P Networking

sendP2PPacket(steamId, data, type)

Send data to another player.

javascript
const packet = JSON.stringify({ type: 'move', x: 100, y: 200 });
await steam.sendP2PPacket(targetSteamId, packet, 2);

Channel Types:

  • 0 - Unreliable
  • 1 - Unreliable, no delay
  • 2 - Reliable
  • 3 - Reliable, buffered

readP2PPacket()

Read incoming packet.

javascript
const packet = await steam.readP2PPacket();
if (packet) {
  const data = JSON.parse(packet.data);
  const sender = packet.steamId;
}

acceptP2PSessionWithUser(steamId)

Accept incoming connection.

javascript
await steam.acceptP2PSessionWithUser(steamId);

closeP2PSessionWithUser(steamId)

Close connection.

javascript
await steam.closeP2PSessionWithUser(steamId);

Examples

Host Game

javascript
async function hostGame(settings) {
  const lobbyId = await steam.createLobby(2, settings.maxPlayers);
  
  if (lobbyId) {
    await steam.setLobbyData('map', settings.map);
    await steam.setLobbyData('mode', settings.mode);
    await steam.setLobbyData('name', settings.name);
    
    return lobbyId;
  }
  return null;
}

Browse Lobbies

javascript
async function findLobbies() {
  // Optional: add filters before requesting
  await steam.addRequestLobbyListStringFilter('mode', 'deathmatch', 0);
  await steam.addRequestLobbyListResultCountFilter(20);
  
  const count = await steam.requestLobbyList();
  const lobbies = [];
  
  for (let i = 0; i < count; i++) {
    const lobbyId = await steam.getLobbyByIndex(i);
    if (lobbyId) {
      lobbies.push(lobbyId);
    }
  }
  
  return lobbies;
}

Lobby List Filters

javascript
// Filter by string value
await steam.addRequestLobbyListStringFilter('map', 'forest', 0);

// Filter by number
await steam.addRequestLobbyListNumericalFilter('minLevel', 10, 2); // >= 10

// Filter by distance
await steam.addRequestLobbyListDistanceFilter(2); // 0=Close, 1=Default, 2=Far, 3=Worldwide

// Filter by available slots
await steam.addRequestLobbyListFilterSlotsAvailable(1);

// Limit results
await steam.addRequestLobbyListResultCountFilter(50);

Network Loop

javascript
function networkUpdate() {
  // Process incoming packets
  let packet;
  while ((packet = steam.readP2PPacket())) {
    handlePacket(packet.steamId, JSON.parse(packet.data));
  }
}

function handlePacket(sender, data) {
  switch (data.type) {
    case 'move':
      updatePlayerPosition(sender, data.x, data.y);
      break;
    case 'chat':
      addChatMessage(sender, data.message);
      break;
    case 'action':
      handlePlayerAction(sender, data.action);
      break;
  }
}

// Send position update
function sendPosition(x, y) {
  const packet = JSON.stringify({ type: 'move', x, y });
  for (const playerId of connectedPlayers) {
    steam.sendP2PPacket(playerId, packet, 1); // Unreliable, no delay
  }
}

Reliable Messages

javascript
async function sendReliableMessage(steamId, data) {
  const packet = JSON.stringify(data);
  await steam.sendP2PPacket(steamId, packet, 2); // Reliable
}

// Use for important events
async function onPlayerScored(steamId, points) {
  await sendReliableMessage(steamId, {
    type: 'score',
    points,
    timestamp: Date.now()
  });
}

Best Practices

  1. Use reliable for important data - Score updates, game state changes
  2. Use unreliable for frequent updates - Position, rotation
  3. Validate incoming data - Never trust client data
  4. Handle disconnections - Clean up player state
  5. Rate limit sends - Don't flood the network