
The complete multiplayer framework for every genre: skill-based matchmaking (Elo / Glicko-2), parties & ready checks, ranks & XP & battle pass, full stat tracking and leaderboards, seamless server travel with playlists — online through REST/EOS/PlayFab, or fully offline over LAN with shareable invite codes.
One Game Instance subsystem (UMMProSubsystem) drives the entire loop:
group players → get them on a server → rate the result → progress the account. Every method is
BlueprintCallable; every milestone fires a Blueprint-assignable event.
| Module | Type | Contents |
|---|---|---|
MatchmakingPRO | Runtime | Core, Queue, Rules, Rating, Session, Local, Match, Backend, Progression, Stats, Rewards, Blueprint — all gameplay-facing systems. |
MatchmakingPROEditor | Editor | Asset factories (Rule Set, Game Mode Profile, Travel Playlist) under a MatchmakingPRO content-browser category + the live debug panel (Window → Developer Tools → MatchmakingPRO Debug). Full editor-module docs ↗ |
Tickets enter named queues; each queue runs a greedy oldest-first matcher driven by a data-asset of rules. Parties are atomic — everyone on a ticket lands on the same team.
ExpansionIntervalSeconds their tolerances widen one level (up to MaxExpansionLevel).MinPlayersToStart with backfill/bots allowed), teams are built — snake draft to the weakest team with room, parties whole; FFA modes make each ticket its own team.bAllowBots is set.MinMatchQuality it is discarded. The native OnValidateProposal hook can veto it (anti-cheat / connection probes) — vetoed tickets re-queue.UMMProRuleSet asset| Rule | Checks | Loosens over time |
|---|---|---|
UMMProSkillRule | Average-rating window between tickets. New accounts get extra tolerance; suspected smurfs are treated as rated +SuspectedSmurfRatingBonus so they match upward; optional MaxLevelDifference keeps brand-new players away from veterans. | +ExpansionPerLevel rating / level |
UMMProLatencyRule | Worst-ping ceiling + max ping spread between tickets. Doubles as the pre-match connection-quality gate. | +PingExpansionPerLevel ms / level |
UMMProRegionRule | Same region required; configurable adjacent-region pairs always allowed. | Cross-region allowed at level ≥ RelaxAtExpansionLevel |
UMMProTeamBalanceRule | Final-proposal check: team average-rating spread + max premade-count imbalance between teams (premade-vs-solo fairness). | +SpreadExpansionPerLevel / level |
Rules are EditInlineNew UObjects — subclass UMMProMatchRule in C++ or
Blueprint for game-specific rules (role balance, vehicle class, crossplay pools…). Each rule set also
carries: bRankedQueue, RequiredMinLevel (queue gating), ExperimentTag
(A/B testing hook), and the FMMProMatchParams match shape.
| System | Behavior |
|---|---|
| Ready check | Everyone must AcceptMatch() within ReadyCheckTimeoutSeconds. Decliners and silent timeouts are penalized; innocent players re-queue automatically with their wait preserved. |
| Backfill | A live match calls OpenBackfillSlots(MatchId, Queue, Server, Slots, MinRating, MaxRating, Region); waiting tickets fill the longest-starved match first and travel straight to its server (bAllowJoinInProgress sessions). |
| Penalties | UMMProPenaltyManager — escalating queue bans for ready-check dodges (DodgePenaltySeconds) and match leavers (LeaverPenaltySeconds), offence counters decay after PenaltyDecaySeconds. Banned players cannot queue; admins can clear. |
| Admin force-match | ForceMatchNow(Queue) — pushes every waiting ticket to max expansion and fires a pass immediately. |
A unified travel layer: the game calls one API whether the match runs on a dedicated fleet, a listen host, or a LAN box.
| Path | Flow |
|---|---|
| Dedicated | Backend allocation reserves a server → IP / port / join-token handoff → automatic ClientTravel for every player. Allocation failure degrades gracefully to listen hosting. |
| Listen / P2P | The first player of team 0 is the designated host: creates an OSS session advertising the match id and travels ?listen. Clients find the session by match id and join via the resolved connect string. NAT punchthrough comes from the active OnlineSubsystem (EOS, Steam…). |
| Reconnect | The active match is persisted locally; TryReconnectToMatch() rejoins any time inside ReconnectWindowSeconds — survives client restarts. |
UMMProTravelManager — the unified layer| Feature | API / behavior |
|---|---|
| Seamless travel | ServerTravelToEntry(Index, bSeamless=true) sets bUseSeamlessTravel — players stay connected and PlayerState (stats components included) survives lobby → match → next round. |
| Mid-session rotation | UMMProPlaylistData asset: ordered maps/tracks/stadiums with per-entry game mode + URL options, looping or finite. TravelToNextInPlaylist() advances; OnPlaylistAdvanced fires. |
| Handoff token | FMMProTravelToken: match id, team index, rating, level, rank text and a free-form KV map (loadout, livery, formation) — signed with TravelTokenSecret, carried as ?MMProTravel=…. Destination GameMode calls ParseTravelToken(Options) in InitNewPlayer to restore full context. Tampered tokens fail verification. |
| Spectator travel | TravelAsSpectator() — same token with the spectator flag set; late joiners sync into the live match. |
| Graceful fallback | Hooks engine travel/network failures → routes the player to FallbackMapName (lobby/menu) → OnTravelFailed(Reason, bRouted) lets the game show UI and auto re-queue. |
Full multiplayer with zero internet and zero backend. Host on one machine; friends on the same Wi-Fi join by short code or pick from an auto-discovered list. Progress keeps counting and syncs later.
| Feature | Details |
|---|---|
| Code ↔ IP resolution | IPv4 + port + checksum packed into 12 Crockford-base32 chars — no O/I/L characters, decoder forgives common misreads. Encoding and decoding are purely local. |
| Same UX online | Codes that aren't valid LAN codes resolve through the backend (/codes/{code} → server address or session id). One "Join by Code" box covers both worlds; the resolver decides the route. |
| LAN discovery | UMMProLANDiscovery — hosts broadcast a UDP beacon (name, port, players, match id, code) every second on LANBroadcastPort; clients listen and surface a live "Local Games" list via OnSessionsUpdated. Silent hosts expire after 5 s. Works over phone hotspots. |
| Offline listen server | HostOfflineMatch(Map, GameMode, Name, MaxPlayers) — ServerTravel ?listen, start advertising, return the shareable code. No OSS login, no backend. |
| Offline bots | Combine with bAllowBots so a single LAN host still starts a full match. |
| Deferred sync | UMMProDeferredSyncQueue — stats/profiles/results/leaderboard writes that can't reach a backend persist to Saved/MatchmakingPRO/PendingSync.json and upload one-by-one when connectivity returns (30 s retry; SetNetworkMode(Online) flushes immediately). Newer stat snapshots supersede queued older ones. |
Auto — backend when configured, local otherwise ·
Online — full backend flow · Offline — never touches the internet. Switchable
at runtime with SetNetworkMode().UMMProXPCurve asset| Feature | Details |
|---|---|
| Level curve | Exponential per-level cost (BaseXPPerLevel × GrowthFactor^level) with optional explicit per-level overrides; MaxLevel configurable. |
| XP sources | Match completion · win bonus · objective score · minutes played · first-win-of-day bonus (UTC day-stamped). |
| Multipliers | Runtime booster via SetXPMultiplier() (events / weekends) stacking with the PremiumXPMultiplier setting. |
| Anti-grind caps | Optional daily and weekly XP caps with automatic UTC rollover. |
| Per-mode XP | Separate XP totals per queue/mode id. |
| Battle pass | Season track: XP feeds pass tiers (BattlePassXPPerTier, capped at BattlePassMaxTier); tier-ups grant pass unlocks. |
| Prestige | Prestige() at max level — resets to level 1, increments prestige, grants prestige cosmetics. Up to MaxPrestige. |
UMMProRankSystem + UMMProRankTierData asset| Feature | Details |
|---|---|
| Tiers & divisions | Default ladder Bronze → Silver → Gold → Platinum → Diamond → Master → Grandmaster; 3 divisions each (1 for Master+); per-tier RP thresholds and badge-icon slots. Fully replaceable via the data asset. |
| RP gain/loss | Base gain/loss scaled by Elo expectation against the opposing average MMR — upset wins pay more, expected losses cost more (UpsetScale). |
| Placements | PlacementMatchCount calibration matches; initial tier blends MMR distance from MedianRating with placement win rate. |
| Promo series | Best-of-PromoBestOf at tier boundaries; failing parks RP near the threshold. |
| Demotion | RP underflow drops a division, then a tier (arriving at the top division below). Ladder floor at Bronze. |
| Rank decay | Tiers flagged bDecays lose DecayRPPerDay per idle day past DecayGraceDays — applied on login. |
| Seasonal reset | Soft reset toward the baseline tier (SoftResetFactor), partial re-placement (PlacementsAfterReset), previous season archived, end-of-season rewards granted. Triggered by changing CurrentSeasonId or calling StartNewSeason(). |
| Display | Highest-rank-achieved tracking; GetRankDisplay() → "Gold II — 45 RP" / "Placements 3/5" / "Promos 1-0"; badge icon path for UI. |
Only queues flagged bRankedQueue (or results with bRanked) move the ladder —
casual play never costs RP. UMMProProgressionComponent (replicated) carries
level/prestige/rank to all clients for nameplates and scoreboards.
FMMProStatBlockKills / Deaths / AssistsK/D · KDA ScoreDamage dealt / taken / healed Shots fired / hit / headshotsAccuracy · HS% Objective captures / defends / scoreW / L / D · win rate Matches playedPlaytime (hours) Kill streak (best)Win streak (current / best) Avg kills · avg score
Every stat is addressable by key (GetStatByKey("KD")) — the
same keys drive achievements and per-stat leaderboards.
| Feature | Details |
|---|---|
| Live accumulation | UMMProStatsComponent on PlayerState — AddKill / AddShots / AddObjectiveCapture / AddDamageDealt…, replicated, kill-streak logic built in. CommitToSubsystem() stages the match block before SubmitMatchResult. |
| Rollups | Career totals + per-mode, per-map, per-character/hero/class, per-weapon/loadout aggregates; most-played mode/map/character lookups. |
| Match history | 50-entry ring with full stats, outcome, XP earned, RP delta and rating-after per match — the data behind a recent-performance graph. |
| Persistence | JSON to Saved/MatchmakingPRO/PlayerData_<id>.json, mirrored to the backend (PUT /stats/{id}); the backend copy wins on load. Per-season snapshots archive rank + career. |
| Anti-tamper | bServerAuthoritativeStats — match stats only count when recorded with network authority (dedicated / listen host). |
| Admin tools | AdminResetStats() (keeps progression/rank) · ResetAll() · ClearPlayerPenalties() · StartNewSeason(). |
UMMProLeaderboardService<stat>.<season>.<region>.GET/POST /leaderboards/{board}.GetPlayerCard() returns the complete profile card: level, prestige, rating, rank display +
badge icon, highest rank, career stat block, unlocked achievement badges, player-chosen showcase
slots (SetShowcaseSlots), most-played mode/map/character, and both currencies.
CompareCareerStat(Key, OtherBlock) diffs any stat against a friend or a global average.
| System | Details |
|---|---|
Unlock table — UMMProUnlockData | Weapons / skins / emotes / titles / banners / nameplates gated by account level, rank tier (end-of-season drop), prestige or battle-pass tier — each with display name + icon slot. |
| Currency | Soft + hard currency: per-match payout, win bonus, per-level-up grants, achievement rewards. Totals live on the player card. |
Achievements — UMMProAchievementSystem | Definitions target any stat key with a threshold (Kills ≥ 1000, WinRate ≥ 0.6, BestWinStreak ≥ 10, HoursPlayed ≥ 100…). Evaluated after every match; progress rows for UI; rewards (unlock + currency) auto-granted. |
Reward manager — UMMProRewardManager | Single grant pipeline for match end, each level-up, battle-pass tier-ups, prestige and end-of-season rank drops. Duplicate-safe. |
Matchmaking, travel and sessions never care about gameplay — they group players and get
them on a server. UMMProGameModeProfile bundles match shape + rule set + travel playlist;
pick a Preset in the editor and the asset fills itself, then tweak freely.
| Preset | Shape | Notable configuration |
|---|---|---|
| 🔫 Shooter — Team Deathmatch | 2 × 4 | Ready check, backfill, skill rating, round playlist travel |
| 🏎 Racing — 8-Player Grid | FFA × 8 | bFreeForAll, start at 4+, AI drivers fill the grid, rating = lap-time percentile, playlist = track rotation |
| ⚽ Football / Sports — 5v5 | 2 × 5 | Rating = club strength, no mid-half backfill, AI fills missing players, ranked |
| 🪂 Battle Royale — 100 | 25 squads × 4 | Drop at 60+, no backfill after the drop, no ready check, no mid-match travel |
| 🗡 MOBA — 5v5 | 2 × 5 | Strict ready check, ranked, level-10 queue gate, single map |
| 🤝 Co-op / PvE | 1 × 4 | Start solo, drop-in/drop-out backfill, bots, no skill matching |
| 🥋 Fighting — 1v1 | 2 × 1 | Ranked, best-of-N set via playlist rotation |
The abstractions that make it work: FMMProMatchParams (team count, players per team,
bFreeForAll, MaxPlayersOverride, bAllowBots, rating-type label),
UMMProRuleSet (which rules, how strict), a rating value that means whatever the game wants,
and a travel playlist the session rotates through. A racing game and a football game run the same core.
Content/GameModeProfiles/ → add to GameModeProfiles in Project Settings.
Binary .uasset files can't ship as source, so each preset is one click.One async interface — IMMProBackend — behind auth, tickets, allocation,
profiles, results, stats, leaderboards and invite codes. Every method has a safe no-op default, so custom
adapters implement only what their service supports.
| Adapter | Notes |
|---|---|
| LocalOnly | No backend at all. Matching runs locally, sessions via OSS listen hosts, stats persist to disk, deferred queue holds uploads. |
| REST | Complete generic client for your own service:POST /auth/login · POST /tickets · DELETE /tickets/{id} ·
POST /allocate · GET/PUT /profiles/{id} · POST /results ·
GET/PUT /stats/{id} · GET/POST /leaderboards/{board} ·
GET/PUT /codes/{code}.Bearer-token auth, configurable base URL and timeout. |
| EOS | Identity/auth from the active OnlineSubsystem (pairs with an EOS OSS plugin such as EOSpro); sessions through OSS; allocation falls back to listen hosting. Clean extension point for a custom EOS title backend. |
| PlayFab | REST conventions against https://{TitleId}.playfabapi.com — LoginWithCustomID (auto account creation), session-ticket or X-SecretKey auth. |
Project Settings → Game → MatchmakingPRO (UMMProSettings, saved to
DefaultGame.ini).
| Category | Settings |
|---|---|
| Queues | DefaultQueueName · QueueRuleSets (queue → rule-set asset map) · GameModeProfiles (profile assets registered at startup) · MatchmakingTimeoutSeconds · QueueTickIntervalSeconds |
| Backend | BackendType (LocalOnly/Rest/EOS/PlayFab) · RestBaseUrl · RestAuthToken · PlayFabTitleId · PlayFabSecretKey · BackendTimeoutSeconds |
| Network | NetworkMode (Auto/Online/Offline) · LANBroadcastPort (default 17777) |
| Travel | TravelTokenSecret (set per project!) · FallbackMapName |
| Rating | RatingModel (Elo/Glicko2) · EloKFactor · EloNewAccountKFactor · NewAccountGameThreshold |
| Match flow | ReadyCheckTimeoutSeconds · bUseDedicatedServers · ReconnectWindowSeconds |
| Penalties | DodgePenaltySeconds (escalating array) · LeaverPenaltySeconds · PenaltyDecaySeconds |
| Progression | XPCurveAsset · RankTierAsset · UnlockDataAsset · CurrentSeasonId (changing it = season rollover) · PremiumXPMultiplier |
| Stats / Integrity | bServerAuthoritativeStats |
| Smurf detection | SmurfKDThreshold · SmurfWinRateThreshold · SmurfMaxLevel |
| Player defaults | DefaultRegionId |
All Blueprint-assignable on UMMProSubsystem unless noted.
| Event | Payload | Fires when |
|---|---|---|
OnStateChanged | new EMMProState | any flow transition |
OnQueueStatusUpdated | position, elapsed, ETA, expansion level | every second while searching |
OnMatchFound | FMMProMatchSummary (teams, quality, avg rating) | a proposal includes your ticket |
OnReadyCheckStarted | summary + timeout seconds | accept/decline window opens |
OnMatchReady | FMMProServerInfo | server allocated, travel beginning |
OnMatchmakingFailed | EMMProFailReason + message | timeout / declined / banned / allocation failed… |
OnRatingsUpdated | local FMMProPlayerProfile | after rating recalculation |
OnXPGained / OnLevelUp | amount + level / new level | XP grant / level threshold crossed |
OnRankUpdated | FMMProRankState + display string | RP applied, promo/demotion, season reset |
OnUnlockGranted · OnCurrencyGranted | unlock id / amounts | (on UMMProRewardManager) |
OnAchievementUnlocked | achievement id | (on UMMProAchievementSystem) |
OnLeaderboardLoaded | board + entries | (on UMMProLeaderboardService) |
OnSessionsUpdated | LAN session list | (on UMMProLANDiscovery) |
OnInviteResolved | resolved server / match id | (on UMMProInviteCodeService) |
OnTravelFailed · OnPlaylistAdvanced | reason+routed / index+entry | (on UMMProTravelManager) |
OnValidateProposal | native, returns bool | pre-match veto hook — anti-cheat / connection checks |
| Folder | Classes |
|---|---|
Core/ | UMMProSubsystem · MMProTypes · FMMProMatchParams · UMMProGameModeProfile · UMMProSettings · FMMProTicket |
Queue/ | FMMProQueue · UMMProQueueManager · FMMProWaitTimeEstimator |
Rules/ | UMMProMatchRule · UMMProSkillRule · UMMProLatencyRule · UMMProRegionRule · UMMProTeamBalanceRule · UMMProRuleSet |
Rating/ | UMMProRatingSystem · UMMProEloRatingSystem · UMMProGlicko2RatingSystem · UMMProPlayerRatingComponent |
Session/ | UMMProSessionManager · UMMProServerAllocator · UMMProMatchTravelHandler · UMMProReconnectHandler · UMMProTravelManager · FMMProTravelToken · UMMProPlaylistData |
Local/ | UMMProLANDiscovery · UMMProInviteCodeService · UMMProOfflineSession · UMMProDeferredSyncQueue |
Match/ | FMMProMatchProposal · UMMProReadyCheckManager · UMMProBackfillManager · UMMProPenaltyManager |
Backend/ | IMMProBackend · FMMProBackendFactory · FMMProRestBackend · FMMProEOSBackend · FMMProPlayFabBackend |
Progression/ | UMMProProgressionComponent · UMMProXPCurve · UMMProRankSystem · UMMProRankTierData · MMProProgressionTypes |
Stats/ | UMMProStatsComponent · FMMProStatBlock · UMMProStatsManager · UMMProLeaderboardService |
Rewards/ | UMMProRewardManager · UMMProAchievementSystem · UMMProUnlockData |
Blueprint/ | UMMProBlueprintLibrary — plus every subsystem method is BlueprintCallable |
| Editor module | Asset factories + "MatchmakingPRO" content category (Rule Set, Game Mode Profile, Travel Playlist) · SMMProDebugPanel live debug tab |
// C++ — identical Blueprint nodes exist for everything auto* MM = UMMProSubsystem::Get(this); MM->OnMatchFound.AddDynamic(this, &UMyMenu::HandleMatchFound); MM->OnMatchReady.AddDynamic(this, &UMyMenu::HandleMatchReady); // travel happens automatically after this MM->StartMatchmaking("Ranked1v1"); // or StartPartyMatchmaking(Queue, PartyProfiles) // during the ready check: MM->AcceptMatch(); // or DeclineMatch()
// HOST — returns a shareable code like PRO-7H2K9C3FA0 FString Code = MM->GetOfflineSession()->HostOfflineMatch(this, "/Game/Maps/Arena", "", "Garage Party", /*MaxPlayers=*/8); // FRIEND — join by code (same box works online; the resolver decides the route) auto* Codes = MM->GetInviteCodeService(); Codes->OnInviteResolved.AddDynamic(this, &UMyMenu::HandleInvite); Codes->ResolveCode(EnteredCode); // in HandleInvite: GetOfflineSession()->JoinLANSession(this, Invite.Server.Address, Invite.Server.Port) // or browse instead of typing: MM->GetLANDiscovery()->StartListening(); // → OnSessionsUpdated → "Local Games" list
// UMMProStatsComponent on your PlayerState: Stats->AddKill(); Stats->AddShots(12, 9, /*headshots=*/2); Stats->AddObjectiveCapture(); Stats->ModeId = "Ranked1v1"; Stats->CharacterId = "Ryu"; Stats->CommitToSubsystem(this); // stage before SubmitMatchResult
FMMProMatchResult Result; Result.MatchId = ActiveMatchId; Result.QueueName = "Ranked1v1"; Result.bRanked = true; Result.DurationSeconds = 540.f; Result.Teams.Add(UMMProBlueprintLibrary::MakeTeamResult({MyId}, EMMProMatchOutcome::Win, 3)); Result.Teams.Add(UMMProBlueprintLibrary::MakeTeamResult({OppId}, EMMProMatchOutcome::Loss, 1)); MM->SubmitMatchResult(Result); // → Glicko-2 rating → XP (+first-win bonus) → RP/promos → career stats + history // → currency → achievements → leaderboards → save → backend (or deferred sync)
MM->GetTravelManager()->SetPlaylist(TrackPlaylist); MM->GetTravelManager()->TravelToNextInPlaylist(this, /*bSeamless=*/true); // destination GameMode::InitNewPlayer — restore each player's context: FMMProTravelToken Token; if (UMMProTravelManager::ParseTravelToken(Options, Token)) { AssignTeam(NewPlayer, Token.TeamIndex); LoadLoadout(NewPlayer, Token.CustomData["Loadout"]); }
BP_MatchmakingPRO_Catalog is the reference Blueprint that exercises every node the plugin exposes — one demo graph per category. Drop it in a level (or just browse below) to learn the whole API. Every node here is real and callable from Blueprint: blue = Callable, green = Pure, purple = Event, gold = Component. Filter by category, search, and page through the gallery.