Docs
Everything to go from an empty folder to a running multiplayer game.
Quickstart
From an empty folder to a running server and a connected client in five steps.
Crossplay generates a complete, ready-to-run project: a .NET server that composes only the pieces you pick, and a Unity client wired to match. You never edit the framework β you snap pieces on and plug your own game into the sockets they expose.
- 1Create a project.Open New project, give it a name, choose a database (SQLite is zero-config and the default), and pick a transport. Everything else has a sensible default.
- 2Choose your pieces.Tick the features your game needs β Characters, World, Movement, Chat, Inventory, and so on. Dependencies are pulled in for you; a card game and an MMO start from the very same kernel.
- 3Generate & run the server.Create the project, then run the generated server. It boots on your chosen port and persists to your chosen database out of the box.
dotnet run --project Server - 4Open the Unity client.Open the generated Unity project. The Crossplay client packages are already referenced and the bootstrap flow is generated to match your pieces: connect β sign in β pick a character β enter the world.
- 5Drop in a panel & play.Every piece ships a drag-and-drop UI panel (e.g. the chat window or the inventory grid). Drag its prefab into a scene, press Play, and you're talking to your server.
Prefer real auth from the start? Pick a sign-in method (Username/Password, Steam, Google, β¦) when you create the project. The generated flow then waits for the Login panel and the Character panel instead of auto-signing-in β a real game flow, not a demo shortcut.
What you get
- A .NET 10 dedicated server composed of exactly the pieces you chose β nothing more.
- A Unity 6.3 client project with the matching packages and a generated bootstrap flow.
- Durable persistence on your chosen database, with account and character data saved out of the box.
- A drag-and-drop UI panel for every feature piece, ready to place in a scene.
Where the API docs live
The server pieces install as compiled DLLs, and each one ships its XML doc file beside it. Your IDE picks that up automatically β hover any Crossplay type in Rider, Visual Studio or VS Code and you get the same prose you see in the API reference. Nothing to configure.
How it works
The one mental model that makes everything else fall into place.
Crossplay moves data and syncs state. It does not know what game you are making.
The kernel β Core β is genre-agnostic. It gives you transport, identity, sessions, rooms, and a messaging SDK, and nothing else. It works unchanged for a card game, hide-and-seek, an MMO, or a rhythm game.
Pieces stack downward
Every feature is a piece that depends only on lower pieces, never higher ones. World builds on Characters; Movement builds on World; feature pieces like Chat depend on Core alone. You compose the ones you want and leave the rest out β removing a piece never breaks the others.
Movement β World β Characters β Coredependencies flow downward onlyEvery piece is the same trio
A piece is Contracts (the wire protocol both sides share), a Server half (.NET), and a Client half (a Unity UPM package). You add the server half with one line and reference the client package β the Hub does both when it generates your project.
services.AddCrossplayChat();server: one line composes the piecePresentation is always yours
Pieces sync abstract state β ids, numbers, and opaque blobs β never models, animations, or sounds. An emote is an id and a payload: one game renders it as a chat line, another as a UI sticker, another as a full 3D dance. The piece cannot tell the difference, and it just works under any of them. You bind meaning through the SPIs each piece exposes.
- The wire carries ids, numbers, and opaque blobs.
- The client gives you events and SPI sockets.
- The look β models, animators, UI, controls β is 100% your game's.
Composition recipes
Different games, the same kernel. Start here and add only what the genre needs.
Because pieces compose, you assemble a game by taking the kernel plus the handful of pieces the genre calls for. Here are three starting points β notice they share the same Core.
π Card / turn-based game
No avatars, no world, no movement. Just the kernel, matchmaking to pair players, and your own card messages on top. Add the meta pieces (Economy, Achievements, Leaderboards) freely β they no longer require Characters.
Core + Matchmaking + (your card messages)
π Hide & seek / party game
Now you want bodies in a space. Add Characters, World, and Movement, then layer your own role and tag messages. Emotes and Voice snap on for presence.
Core + Characters + World + Movement + (roles, tag)
πΊοΈ MMO / persistent world
The full spatial stack plus the persistent-world pieces: zones and instancing, the Director for instance placement across nodes, Inventory and the Container family, Guild, Mail, and the combat family. Everything persists to your database and scales out over Redis.
Core + Characters + World + Movement + Director + Inventory + Guild + Combat β¦
Unsure which pieces a genre needs? Open any piece's API reference β each one lists what it depends on, the seams it expects you to implement, and the services it hands you.
Implementing an SPI
The pieces ship as compiled DLLs. The SPIs are where your game plugs in.
Crossplay runs the universal machinery β validation, ordering, persistence, broadcast β and calls out to your game whenever a decision is genuinely yours. Those call-outs are SPIs: interfaces Crossplay calls and you implement. Every piece ships an inert or permissive default, so a piece works the moment you install it and gets its meaning the moment you replace the default.
A service is something you CALL. An SPI is something you IMPLEMENT. The API reference labels every interface, so you never have to guess.
The two kinds of seam
- Game SPI β implementing it changes a game rule. IAbilityRules decides whether a cast is legal; IQuestCatalog decides what quests exist; IProgressionCurve decides what level 40 costs.
- Provider β implementing it changes infrastructure, never a rule. IDocumentStore decides which database the bytes land in; ICharacterStore decides where characters persist; IServerTransport decides how they move.
Register before you compose
Every piece registers its default with TryAdd, which means the first registration wins. Register your implementation BEFORE the piece's AddCrossplay* call and yours is the one that gets used. Register it after, and the default has already claimed the slot.
// your rules win because they are registered first
services.AddSingleton<IAbilityRules, MyAbilityRules>();
services.AddCrossplayAbilities();the TryAdd seam: register first, and the shipped default steps asideA worked example
Abilities handles the parts every game shares: the entity is in the world, the payload is a sane size, the cooldown has elapsed, and the observers get told. What an ability MEANS β damage, hit detection, combos, ammo β is the one thing only your game knows. So that is the seam.
public sealed class MyAbilityRules : IAbilityRules
{
public AbilityDecision Decide(ISession actor, WorldEntity self, ushort abilityId, byte[] targetData)
{
if (!_mana.TrySpend(actor.AccountId, Cost(abilityId)))
return AbilityDecision.Reject();
return AbilityDecision.Accept();
}
}the framework already ran the universal gates before calling youFinding the seams you need
Open a piece in the API reference. Its SPIs are listed first, split into the two kinds above, each with the prose from the source. Because the reference is generated from the same build that produces the DLL you installed, it can never describe a version you do not have.
You do not need the website to read these. Each shipped DLL carries its XML doc file beside it, so hovering an SPI in Rider, Visual Studio or VS Code shows the same text inline.
Piece reference
All 82 pieces. Open one for its generated API reference β the seams you implement, the services you call, and every public type.
Generated from the same build that produces the DLLs you install, so the reference can never describe a version you don't have. Each shipped DLL also carries its .xml doc file, so the identical text appears on hover in Rider, Visual Studio and VS Code. Looking for what to implement? See every seam, grouped by category.
Core
zenject Zenject DI Container The Zenject/Extenject dependency-injection container the whole client stack binds through. A must for Core β auto-installed, cannot be unselected. Client-only.
init Init & DI Framework The client initialization + DI framework: the [Singleton*]/IAppInitializable attributes, context-scoped installers, and the app bootstrap every Crossplay client package registers into. A must for Core β auto-installed, cannot be unselected. Client-only.
core Core Multiplayer 32 seams The always-on kernel: connect, login, sessions, rooms/groups, and the messaging SDK.
content Game Content 2 seams Genre-agnostic authored-content store: define content types + records (entities, items, levels, classes, quests, anything) over a metaschema β every domain type is DATA, not code. Saved in the DB, served to clients on demand (manifest -> lazy fetch -> live push), asset-load-path binding. A must for Core β auto-installed, cannot be unselected.
editor Crossplay for Unity (Editor) The free in-Editor companion window (Window -> Crossplay): sign in, browse the live catalog + guides, ask Relay in-Editor, wire client options, hand installs to the Hub. Includes the 'Multiplayer Test' tab (launch 2-4 local clients from one checkout β cloned Editors or standalone copies, each pinned to a distinct instance id β with one-click start/stop of the local .NET server) and, whenever the content piece is installed, the 'Content Sync' tab (two-way sync of authored Game Content between the game server and Unity ScriptableObjects: typed SO classes generated per content type, version-guarded publish back β the server store is master). Editor-only tooling, no runtime code. A must for Core β auto-installed, cannot be unselected.
Spatial
characters Characters 3 seams Create / select / roster of characters with an opaque appearance blob (ICharacterFactory SPI).
world World 8 seams Enter-world, spawn/despawn, spatial interest, zones/instancing, server entities, bounds.
movement Movement 4 seams Server-authoritative movement: input, 20Hz broadcast, prediction/reconciliation, interpolation.
culling Network Culling (LOD) Per-pair broadcast-rate rings so distant entities cost less bandwidth. Off by default.
navigation Navigation (A*) Server-side pathfinding over the world bounds masks for your game's AI. Server-only.
emotes Emotes Abstract game-defined emote/action events fanned out to observers as opaque data.
voice Voice Chat Relays opaque game-encoded audio frames by proximity (World interest) or voice channel; the framework never decodes β codec + playback are the game's.
interactions Interactions 1 seams "Player used entity X": a validated verb pipeline; the game's policy SPI decides meaning.
entitystate Entity State Mutable opaque per-entity state blob, broadcast on change and replayed on interest reveal.
rigidbodies Rigid Bodies Optimized networked transform sync for non-player physics bodies (crates/vehicles/debris/doors): quantized position + smallest-three quaternion + velocity, sleep-gated, interest-culled, batched. The game runs its own physics; this only syncs the result.
zonestate Zone State Mutable opaque per-zone blob (weather/time/siege), broadcast on change, replayed on entry.
worldgrid World Grid Shared spatial cell grid: per-zone chunked opaque cells (terrain edits, tiles, build pieces), streamed to each player's chunk window and delta-batched on change. Seed + persistence SPIs; server-set only.
triggers Triggers 1 seams Spatial enter/exit/dwell volumes over the world. Server-only.
spawner Spawner Population spawners over server entities: keep N alive in an area, respawn on removal. Server-only.
loot Loot Dropped-item entities: opaque payload, atomic first-claim, timed expiry. Server-only.
agents Agents (NPC AI) 2 seams NPC behavior drivers: wander/patrol/chase built-ins + an IAgentBehavior game SPI. Server-only.
dungeons Dungeons 1 seams Instanced-zone lifecycle: create/seed via IDungeonContent, complete/reset, abandon sweep. Server-only.
mounts Mounts 1 seams A rideable STATE on an entity: mount id + opaque look blob + speed multiplier (applied through Movement's speed seam via a Hosting bridge). Horses, hoverboards, sprint stances, transformation forms β same state machine, the game's render. Ownership/eligibility = IMountPolicy; broadcast on change + replayed on interest reveal; empty catalog = inert.
travel Travel & Respawn 6 seams Bind/recall points, a warp destination table, and deathβrespawn location resolution through an ORDERED strategy chain (bind β nearest zone point β your own IRespawnStrategy). WHEN travel is allowed is the game's policy SPIs (the default DENIES client respawns until one is composed β the Stats-depletion bridge supplies the classic 'dead may go home'); moves ride the ITravelMover seam (Movement's prediction-aware Teleport when composed).
possession Possession Input redirection to server entities (vehicles / mind-control / GM drive) via Movement's seam.
pets Pets Companion entities: summon with an opaque look; follow / zone-travel / owner-leave handled. Server-only.
Combat
stats Stats Numbered clamped stats with thresholds and regen.
abilities Abilities 4 seams Opaque verbs with server-tracked cooldowns and an IAbilityRules SPI.
projectiles Projectiles 1 seams Kinematic projectile entities with deterministic client rendering + click-frame prediction: one launch event per volley, no interpolation buffer.
statuseffects Status Effects Timed opaque markers (buffs/debuffs) applied to entities.
hostility Hostility (PvP Flags) 1 seams WHO MAY HARM WHOM, answered in one place: consent stances (opt-in verb), combat flags on aggression, escalation tiers on innocent kills, safe zones β one IHarmResolver seam every combat consumer asks (Crossplay:Hostility:DriveTargeting bridges Targeting). PvE pairs pass through untouched; defaults = the classic no-PvP baseline.
threat Threat / Aggro Server-only accumulated threat tables ("who do I hate most"): first-seen bonus, exact exponential decay, forget threshold, TargetChanged hooks. Feeding (damage/taunts) and consuming (Targeting selector, Agents brains) are composition bridges β Crossplay:Threat:DriveTargeting flips Targeting to highest-threat-first. Zero wire; inert until fed.
targeting Auto-Targeting 4 seams Server-only auto-attack driver: enrolled attackers acquire a target (ITargetSelector) and attack on a cadence (IAttackAction) over World β survivors/auto-shooter auto-fire, turrets, sentries, pet auto-attack. Genre-neutral defaults (nearest-in-cone selection, two-faction PvE hostility, inert attack); zero wire.
combathud Combat HUD Pooled nameplates + eased HP bars + effect chips + cooldown pips over the combat clients. Client-only UI.
Economy
container Container 3 seams The generic opaque-item-container engine every item piece sits on: containerId-keyed slots/stacks, policy SPI, persistence, and atomic cross-container moves. Server-only; inventory/bank/vault/equipment are thin roles over it.
inventory Inventory 2 seams The character's bag β a container role over the Container engine (opaque item blobs, policy SPI, persistence).
bank Bank / Stash 1 seams A personal item-storage container β a role over the Container engine (opaque item blobs; atomic bag<->bank deposit/withdraw via TryExchange; policy SPI; persistence). Depends on Container, not Inventory.
equipment Equipment 1 seams Worn/active gear in typed slots β a container role over the Container engine (opaque items + opaque slot ids, IEquipmentPolicy SPI). World-optional visible loadout broadcast; item effects via Equipped/Unequipped events (never references Stats).
trade Trade Escrowed player-to-player exchange (atomic TryExchange over Inventory).
crafting Crafting 2 seams Validated recipe execution (opaque in/out, all-or-nothing) over Inventory; catalog is a game SPI.
economy Economy (Currencies) 3 seams Atomic, policy-gated, ledgered currencies; read-only on the wire.
market Market 3 seams Escrowed listings + lock-guarded buyout over Inventory + Economy, with durable Scheduler expiry.
shop Shop / Vendors 5 seams System-owned stores selling/buying OPAQUE items for game currencies: catalog stock, per-buyer daily caps, finite stock, buyback ring. Currency/access/appraisal/pricing are seams (Economy bridges the wallet); WHAT a shop is β NPC, vending machine, terminal β is the game's. Server-only wire verbs; empty catalog = inert.
mail Mail 3 seams Offline delivery with escrowed item attachments.
guildvault Guild Vault Shared guild inventory of opaque item blobs with per-rank deposit/withdraw/view permissions and an audit trail.
purchases Purchases 1 seams Data-driven purchase catalog: wallet stat, per-buyer live price (stored as a stat, so it replicates) with growth, and capped stat effects. Server-only wire verb; empty catalog = inert.
upgrades Upgrades 2 seams Coin-priced, persistent, server-authoritative meta-upgrades: price from the buyer's stored tier (ceil(InitialPrice*Growth^tier)), atomic currency debit, tier persisted per-character. Currency + persistence via seams bridged to Economy + PlayerData.
Social
chat Chat 2 seams Channels and whispers over Core, with profanity masking and rate caps.
guild Guild 1 seams Persistent guilds: officer ranks, MOTD, invites/kicks, leader handoff.
party Party 2 seams Ephemeral parties: leader, ready checks, kicks.
teams Teams 1 seams Server-authoritative in-match sides per game-defined scope: opaque team ids, members, a rankable score + opaque blob, team-scoped broadcast, optional policy-gated self-service joins.
friends Friends 1 seams Friend lists, requests, and online presence.
matchmaking Matchmaking 3 seams Queue-based matchmaking with team/role quotas and MMR.
lobbies Lobbies 1 seams Create/join/list lobbies with slots and metadata.
director Instance Director 5 seams Allocate game instances (zone/room/lockstep) on match/lobby formation across nodes, hand each player a single-use join token, run the lifecycle, and return them to the hub.
Progression
leaderboards Leaderboards 2 seams Persistent ranked boards: keep-best, around-me, rolling seasons.
dailyrewards Daily Rewards Interval claims with grace-window streaks; reward is an IDailyRewardGrantor game SPI.
achievements Achievements 3 seams Server-reported counters against game-defined thresholds; catalog/reward are game SPIs.
progression Progression (XP/Levels) 3 seams Multi-track server-granted xp/levels; curve is config exponential or an IProgressionCurve SPI.
quests Quests 4 seams Accept/track/turn-in over game-defined objectives; catalog/policy/reward are game SPIs.
dialogs Dialogs 4 seams Server-resolved conversation graphs: opaque node/choice payloads, per-choice conditions evaluated SERVER-side and stripped from the wire, choice actions via game SPIs. NPC talk, visual novels, tutorials, quest givers β one engine; Core-only, stateless, empty graph table = inert.
Meta
playerdata Player Data Per-player key/value store of opaque blobs.
matches Matches 2 seams Match lifecycle (countdown/duration/return-zone) with results bridged to Leaderboards.
rounds Rounds 1 seams Server-authoritative phase/round state machine per game-defined scope: opaque phase ids, per-phase deadlines, IRoundFlow SPI transitions, and an authoritative elimination set. No client verbs (unforgeable).
voting Voting 1 seams Server-opened proposals over opaque choice ids: one ballot per eligible voter, live anonymous tallies, deadline/everyone-voted close, outcome decided by an IVoteRules SPI (plurality default). The game acts on Closed; the piece never executes outcomes.
roles Roles (Hidden/Asymmetric) 1 seams Server-assigned opaque role ids with per-viewer visibility filtering (a hidden assignment never touches the wire), per-holder private payloads, role-scoped sends, and an end-of-game reveal. IRoleVisibilityPolicy SPI; no client verbs (unforgeable).
draft Draft (Pick/Ban) Server-authoritative timed ordered selection over opaque option ids: the game supplies the step order (snake/alternating/captains β all just step lists) and the pool; the piece runs the clocks, validates turn + availability, resolves timeouts, and pushes idempotent snapshots.
remoteconfig Remote Config Live tuning values pushed to clients.
scheduler Scheduler 3 seams Persistent fire-at-time callbacks that survive restarts. Server-only.
analytics Analytics 1 seams Genre-agnostic gameplay-event pipeline: server-authoritative Track + a rate-capped client wire, batched off-thread to the game's IAnalyticsSink SPI (Segment/Amplitude/BigQuery/β¦). Ships inert (null sink counts + drops).
reports Reports 2 seams Report-a-player: rate-capped, recorded, surfaced via an admin decorator.
lockstep Lockstep (Rollback Netcode) 1 seams Server = input authority (order/relay/ack/checksum); client RollbackEngine + IDeterministicSim SPI.
tournaments Tournaments 4 seams Single-elimination brackets: winners reported by server code (never client-trusted); join policy + champion reward are game SPIs.
gameflow Game Flow Genre-agnostic boot -> connect -> auth -> character -> world lifecycle FSM (IGameFlow); the game binds its screens to StateChanged. Client-only, Core-only.
localization Localization Resolves keys (notification codes etc.) to localized, interpolated strings with locale fallback; strings are game data via ILocalizationCatalog. Client-only, Core-only.
replay Replay 1 seams Record broadcasts server-side (archive) + play a .cdrp recording back through the live client dispatch with play/pause/speed/seek.
Infra
pooling Object Pooling Generic rent/return instance pooling on the client. Client-only.
diagnostics Diagnostics Overlay Net/sim overlay: RTT, rates, interp delay, prediction error, cull tiers. Client-only.
ugui uGUI Panel Toolkit The MVP uGUI panel toolkit the client UI packages build on. Client-only.
audio Audio Service Channel/one-shot/music service over asset keys. Client-only.
input Input Schemes FPS/MMO/click-to-move/ARPG/cards control schemes over the intent SPI. Client-only.
assets Addressables Service Ref-counted Addressables asset service with load scopes. Client-only.
Browse and buy any piece in the store, or download the ones you own from downloads.