M3.2 — Roles in practice (2 clients + 1 server)¶
What you'll learn
- The common role types — client, (dedicated) server, editor — and what distinguishes them.
- How a multi-role session is wired: launch order, connectivity, per-role arguments.
- How to design a role layout for a concrete multiplayer scenario.
How it applies (QA)
Multiplayer and live-service QA is mostly role-shaped: matchmaking, host migration, server authority, split-screen. The first thing you do for any such test is decide the role layout. Getting it wrong (server launched after clients, clients pointed at the wrong host) produces failures that look like game bugs but are session-config bugs.
Concepts¶
Role types¶
A UnrealSessionRole has a type that determines how its process runs and what it does:
- Client — a normal game client. Renders, takes input (or is driven), connects to a server. Most sessions have one or more.
- Server — usually a dedicated server: headless, authoritative, no rendering. Clients connect to it. Networked tests almost always have exactly one (sometimes more for multi-shard scenarios).
- Editor — an editor process. Used when the test needs editor capabilities (e.g.
UE.EditorAutomationruns in-engine tests inside an editor role).
The same build can usually be launched as different role types via its command line (e.g. a server
role adds the server switch); the role type drives the UnrealAppConfig for that participant.
Wiring a multi-role session¶
Three things must be right for clients to actually talk to a server:
- Launch order — the server generally must be up and listening before clients try to connect. Gauntlet sequences roles so this holds; a misordered custom config produces "connection refused" races.
- Connectivity — clients need the server's address/port. In a local session this is loopback;
across devices it's real IPs. Port allocation matters when multiple sessions run in parallel
(see
TestExecutor, M4.4). - Per-role arguments — each role gets its own args via its app config: the server gets the map to host and the server switch; clients get the connect target and any client-specific flags.
Heterogeneous roles¶
Roles in one session need not be identical. Common real layouts:
- 1 server + N clients on the same PC (cheap smoke of connectivity/logic).
- 1 server + N clients each on different devices (closer to production; catches per-device and real-network issues).
- Mixed platforms: a
Win64server withPS5andAndroidclients (cross-play).
The role abstraction is what makes "the same test, but each client on its own console" a configuration change rather than a rewrite.
Pitfall: the client-side symptom of a server-side cause
When a client logs "failed to connect" or "disconnected," the root cause is frequently the server: it crashed on startup, bound the wrong port, or wasn't ready yet. Diagnose connectivity failures from the server role first (M2.4). A clean client log next to a dead server is the signature.
Worked example — the 2-clients-plus-server layout¶
Goal: two clients complete a short match against a dedicated server; pass if both clients log
MatchComplete and nothing crashed.
Role layout:
| Role | Type | Device | Key args (conceptual) |
|---|---|---|---|
| Server | dedicated server | PC-A (or local) | host the test map; server switch; fixed port |
| Client 0 | client | PC-B (or local) | connect to Server; client id 0 |
| Client 1 | client | PC-C (or local) | connect to Server; client id 1 |
Sequence Gauntlet drives: launch Server → wait until it's listening → launch Client 0 and
Client 1 pointed at Server → run the match → collect each role's log → verdict = both clients
logged MatchComplete and no crash on any role.
Verify on a real build: the exact server/connect switches and how the address is injected are project-specific. The layout and ordering are the stable design.
Lab — Design a host-migration test layout
Design the role layout for: "When the host (server) dies mid-match, a client is promoted and the remaining clients continue." On paper:
- List the roles and their types.
- Decide devices (justify same-PC vs. per-device).
- State the launch order and the event you inject (killing the server) and when.
- Write the pass condition in one sentence — what each surviving client must log/do.
Exercise 1 — Order and blame
A 1-server/2-client session fails: both clients log "connection refused," server log is empty (zero bytes). Name the most likely cause and the role you'd open first.
Exercise 2 — Same PC or different?
Give one bug class that a same-PC 1s/2c layout will miss that a per-device layout catches, and one reason you'd still run the cheaper same-PC layout in CI.
Self-check — answers
Lab (sketch): Roles — 1 dedicated server + 3 clients (need ≥2 survivors to show "others
continue" after one is promoted). Devices — per-device is more honest for migration (real network
timing), but same-PC is acceptable for a first logic pass. Order — server up, clients connect,
match starts, then inject server kill at a defined mid-match moment. Pass — after the kill,
a client is promoted to host and every surviving client logs continued match progress (e.g.
MigrationComplete then MatchComplete) with no crash.
Exercise 1: Server log is empty → the server process never really started (or crashed
instantly before logging), so clients had nothing to connect to. Open the server role first
(its launch/crash, /Saved), not the clients — the clients are correct to refuse.
Exercise 2: Misses — real-network issues: latency, NAT, per-platform socket behavior, bandwidth (all loopback on one PC). Still run same-PC because it's fast, cheap, and isolates game/logic connectivity from hardware/network variables — a good first gate before paying for device pools.
Done when
- [ ] You can name the role types and what makes a server role different from a client.
- [ ] You can state the three things that must be right for clients to reach a server.
- [ ] You can design a role layout (roles, devices, order, pass condition) for a multiplayer scenario.
- [ ] You diagnose connectivity failures from the server role first.