logo

Babylon.js Market

By Lawrence

5 minutes

You now have every piece the networked table needs. There is a room server. There is a WebRTC mesh you built from the handshake up. There is a System that drops a remote fold onto the bus. And since last lesson, there is a deck that four browsers agree on from one secret seed, with each player seeing their own hole cards. But open the game and you still sit down to a solo table against a bot. Nothing has called those pieces in order yet. The Net entity in the scene still holds the placeholder room: roomCode: "table-7", autoConnect: false. No code has looked up a real room. This lesson does the last step. It turns I joined a room into the table is live for four people.

Resolve the room before the scene loads

The catch is timing. The moment the P2PNetwork component enters the world, its System reads mySeat, myPlayerId, occupiedSeats, and existingPlayers right off it. Then it opens the mesh. So connect() fires the instant the component attaches, not on some later frame. PokerMultiplayer grabs its own mySeat and occupiedSeats the same way. That means the real values must be on the components before loadScene runs. Otherwise the mesh offers channels to nobody, and it seats you at a seat you don't have yet.

This sets the whole boot order: resolve, inject, then load. Here is a main.ts you assemble:

// src/main.ts — the room is resolved BEFORE the scene attaches.
import scene from './scenes/poker.scene.json';
import {
  resolvePlayerId, joinRoom, buildNetConfig,
} from './components/PokerMultiplayer/roomClient';

const roomCode = new URLSearchParams(location.search).get('room')!;
const playerId = resolvePlayerId();              // stable across reloads
const join = await joinRoom(roomCode, playerId); // → { seat, seed, players }
const cfg = buildNetConfig(roomCode, join, playerId);

// Inject the resolved inputs over the scene's placeholders…
Object.assign(scene.entities.Dealer.components.DeckDealer, cfg.deckDealer);
Object.assign(scene.entities.Net.components.P2PNetwork, cfg.network);
Object.assign(scene.entities.Net.components.PokerMultiplayer, cfg.multiplayer);

// …THEN load. P2PNetwork attaches with a real seat and auto-connects the mesh.
const game = new ArcadeGame(new BabylonAdapter(), canvas);
await game.loadScene(scene);

buildNetConfig sits in the middle of that sequence. It is the one function that turns a raw join result into three component-shaped blocks. You met it in Lesson 4. Here is where its output actually lands.

From the room client:

src/components/PokerMultiplayer/roomClient.ts
export function buildNetConfig(
  roomCode: string,
  join: RoomJoinResult,
  myPlayerId: string,
): NetConfig {
  const occupiedSeats = occupiedSeatsFrom(join.players);
  return {
    deckDealer: {
      roomCode: join.seed,
      handNumber: 0,
      playerCount: join.players.length,
      mySeat: join.seat,
      occupiedSeats,
    },
    network: {
      roomCode,
      mySeat: join.seat,
      myPlayerId,
      occupiedSeats,
      existingPlayers: join.players,
      autoConnect: true,
    },
    multiplayer: {
      roomCode,
      mySeat: join.seat,
      occupiedSeats,
      handNumber: 0,
    },
  };
}

Give it the public code, the join result, and your id. The three blocks then drop straight onto their components:

const cfg = buildNetConfig('AB12CD', join, playerId);
// cfg.deckDealer → { roomCode: 'secret-seed', mySeat: 2, handNumber: 0,
//                    playerCount: 4, occupiedSeats: [0, 1, 2, 3] }
// cfg.network    → { roomCode: 'AB12CD', mySeat: 2, myPlayerId: '…',
//                    occupiedSeats: [0, 1, 2, 3], existingPlayers: [...],
//                    autoConnect: true }
// cfg.multiplayer→ { roomCode: 'AB12CD', mySeat: 2,
//                    occupiedSeats: [0, 1, 2, 3], handNumber: 0 }
Object.assign(scene.entities.Net.components.P2PNetwork, cfg.network);
Object.assign(scene.entities.Net.components.PokerMultiplayer, cfg.multiplayer);
// the Net placeholders ('table-7', autoConnect:false) are now the real room —
// P2PNetwork opens the mesh the moment it attaches.

Look at the roomCode fields again. deckDealer.roomCode is the secret seed. network.roomCode and multiplayer.roomCode are the public code. The split from Lesson 4 now feeds three components. The deck seeds its shuffle from the value nobody can read off the link. The mesh signals over the code you share.

Continue reading

Unlock the Full Course

Every lesson, the runnable examples, and the finished build — yours to keep.

$9one-time

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search