Appearance
Steam Lobbies and P2P
Multiplayer features with Steam networking.
Lobbies
requestLobbyList()
Search for available lobbies. Returns an array of lobby ID strings.
javascript
const lobbies = await steam.requestLobbyList();
// ['109775241234567890', '109775241234567891', ...]Returns: string[] — array of lobby Steam IDs
createLobby(type, maxMembers)
Create a new lobby.
javascript
const lobbyId = await steam.createLobby(2, 4); // Public, 4 playersLobby Types:
0- Private1- Friends Only2- Public3- 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 IDsgetLobbyOwner()
Get the lobby owner's Steam ID (uses current lobby).
javascript
const owner = await steam.getLobbyOwner();
// '76561198012345678'Returns: Steam ID string, or empty string if no current lobby.
getLobbyMemberCount(lobbyId)
Get the number of members currently in a lobby.
javascript
const count = await steam.getLobbyMemberCount(lobbyId);Parameters:
lobbyId- Steam lobby ID string
Returns: number — member count (0 if lobby not found or not yet joined)
getLobbyMemberByIndex(lobbyId, index)
Get the Steam ID of a specific lobby member by index.
javascript
const memberId = await steam.getLobbyMemberByIndex(lobbyId, 0); // first memberParameters:
lobbyId- Steam lobby ID stringindex- Zero-based member index
Returns: Steam ID string, or empty string if index out of range.
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 when game starts
await steam.setLobbyJoinable(true); // ReopensetLobbyType(type)
Change lobby visibility at runtime.
javascript
await steam.setLobbyType(0); // Make private
await steam.setLobbyType(2); // Make public againTypes: 0 Private, 1 FriendsOnly, 2 Public, 3 Invisible
inviteUserToLobby(steamId)
Invite a user to the lobby. Opens Steam's invite overlay for them.
javascript
await steam.inviteUserToLobby('76561198012345678');Lobby discovery
requestLobbyList() now defaults to worldwide distance filter. If your previous lobbies weren't showing up for players in different regions, updating GemShell will fix it.
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- Unreliable1- Unreliable, no delay2- Reliable3- 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(maxPlayers = 4) {
// 0 = Private, 1 = FriendsOnly, 2 = Public, 3 = Invisible
const lobbyId = await steam.createLobby(2, maxPlayers);
if (lobbyId) {
console.log('Lobby created:', lobbyId);
const members = await steam.getLobbyMembers();
console.log('Members:', members);
}
return lobbyId ?? null;
}Browse Lobbies
javascript
async function findLobbies() {
const lobbies = await steam.requestLobbyList();
// lobbies is an array of lobby ID strings
const details = [];
for (const lobbyId of lobbies) {
const memberCount = await steam.getLobbyMemberCount(lobbyId);
details.push({ lobbyId, memberCount });
}
return details;
}Full Lobby Flow
javascript
async function lobbyDemo() {
// Create a public lobby for up to 4 players
const lobbyId = await steam.createLobby(2, 4);
if (!lobbyId) return;
// Check who joined
const members = await steam.getLobbyMembers();
const owner = await steam.getLobbyOwner();
console.log(`Owner: ${owner}, Members: ${members.join(', ')}`);
// Get count using explicit ID (useful when browsing lobbies)
const count = await steam.getLobbyMemberCount(lobbyId);
const first = await steam.getLobbyMemberByIndex(lobbyId, 0);
// Leave when done
steam.leaveLobby();
}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
- Use reliable for important data - Score updates, game state changes
- Use unreliable for frequent updates - Position, rotation
- Validate incoming data - Never trust client data
- Handle disconnections - Clean up player state
- Rate limit sends - Don't flood the network
