← Engineering

Multiplayer casino platform

Casinoverse

A server-authoritative social venue combining autonomous visitors, backend-integrated games, deterministic presentation, and production-scale verification.

  • Multiplayer
  • NPC AI
  • Backend Integration
  • Testing
  • Performance
  • Camera Systems

Autonomous visitors that make a venue feel inhabited

StateTree, AI perception, Smart Objects, provider-owned claims, navigation, table adapters, and population services allow NPCs to arrive, choose between socialising, drinking, spectating, wandering, and gambling, claim real locations, obey capacity and betting deadlines, react to human demand, and leave safely. Configurable archetypes vary risk, stakes, bankroll use, activity weights, timing, and visit length. An offline NPCSim model replays seeded table visits, human arrivals, seat demand, latency, timeouts, drunkenness, and table availability without launching Unreal.

Code evidence — a complete table-visit lifecycle:

enum class ENPCTableVisitState : uint8
{
    Idle,
    Approaching,
    Joining,
    Observing,
    Deciding,
    CommandPending,
    AwaitingSettlement,
    PlayingRound,
    Leaving,
    Cooldown
};

Source: Source/Casino/Public/AI/NPCTableSessionComponent.h

Chronological anonymised server log follows one NPC through admission, elevator gating, accepted wagering, settlement, and completed retirement. View full resolution ↗
Recorded visitor journey · 4 November 2026 Selected lines follow the same controller through admission, elevator arrival gating, skin readiness, a table visit, an accepted wager, settlement, and retirement after financial draining. Timestamps are preserved and identifiers anonymised. Human seat demand and Smart Object claim/release require a separate aligned capture.
Archetype tuning in the offline NPC simulator
Offline NPCSim results compare visits, rounds, mean stake, and total table time for Quiet Regular, Sociable Visitor, and Enthusiastic Player. View full resolution ↗
Recorded tuning results · identical seed 731905 Over 1,800 simulated seconds, Quiet Regular, Sociable Visitor, and Enthusiastic Player complete 343, 437, and 397 rounds with rounded mean stakes of 613, 1,609, and 4,005 cents. The native input hashes matched. Table time is summed across NPCs; this approximation does not exercise Unreal navigation, animation, backend, or replication.

Server-authoritative multiplayer and backend integration

Unreal replication is integrated with asynchronous HTTP services for Blackjack, Baccarat, and Roulette. The server owns membership, seat reservations, wager requests, accepted-state reconciliation, versioned snapshots, final betting state, settlement, reconnection, and departure. Responses are parsed and validated before state changes are staged; snapshot revisions and request identities prevent stale responses from replacing newer state.

Code evidence — transactional final-snapshot staging:

bool ATableGameBase::TryLockFinalBetSnapshot(
    const TMap<int32, FSeatFinalBetSnapshot>& FinalSeats)
{
    const auto* Layout = AssetLayoutData.Get();
    if (!HasAuthority() || !Layout) return false;
    if (bFinalChipBetsLocked) return true;

    // Stage all ledger changes before committing any seat.
    auto ReconciledLedgers = PlayerChipLedgers;
    TMap<TWeakObjectPtr<ACasinoPlayerState>, TMap<FString, float>> FinalAmounts;
    TArray<FTableChipStackSnapshot> FinalStacks;
    // Validation completes before retained state is replaced.
    return true;
}

Source: Source/Casino/Private/Actors/Games/TableGameBase.cpp

Successful automation entries cover accepted ledgers, commit atomicity, replication contracts, snapshots and jitter, and settlement authority. View full resolution ↗
Recorded contract tests · 13 November 2026 Selected entries from a 31-test run with no failures cover accepted ledgers, atomic commits, replication contracts, snapshots/jitter, and settlement authority. They support the state-management implementation. Matching final snapshot versions and contents from two live clients remain to be captured.

Deterministic Roulette simulation and presentation

Roulette combines 157 legal betting boxes, calls, neighbour bets, exact-money positions, rebet, double, clear, deadlines, membership reconciliation, and transactional snapshots with deterministic presentation. Ball motion is a pure function of a replicated schedule and elapsed time, progressing through orbit, authored descent, deflector contacts, capture, and final pocket placement. Version checks and fallbacks keep clients synchronized when an authored motion profile is unavailable or incompatible.

Code evidence — time-based deterministic evaluation:

FRouletteMotionFrame Casino::Roulette::Motion::Evaluate(
    const FRouletteSpinSchedule& Schedule, double Time)
{
    FRouletteMotionFrame Frame;
    Frame.WheelAngle = WheelAngle(Schedule, Time);
    const FBallRings Rings = BallRings(Schedule.Model);

    if (Schedule.bFallback || Schedule.MotionVersion != CurrentMotionVersion)
    {
        Frame.BallLocal = Ring(
            Schedule.Model,
            Rings.PocketRadius,
            Rings.PocketHeight,
            Frame.WheelAngle + PocketAngle(Schedule));
        return Frame;
    }

    // Orbit, descent and contacts depend only on the schedule and time.
    return Frame;
}

Source: Source/Casino/Private/Actors/Games/Presentation/RouletteTrajectory.cpp

Evidence status: The deterministic evaluator is shown above. Existing NPC roulette tests exercise wagering and journey logic; a two-client log with aligned schedule time, phase, and pocket is still needed to verify synchronized ball presentation.

Networked locomotion and character interaction

Custom movement prediction adds curve-driven starts, stops and pivots, saved locomotion requests, rollback/replay restoration, foot-plant signals, obstacle handling, gait transitions, landing braking, dodge, and significance-aware throttling. Table entry layers Motion Warping, chair movement, hand grips, foot IK, pelvis locking, collision management, and recovery watchdogs onto that foundation.

Code evidence — deterministic state during prediction replay:

void FSavedMove_Casino::PrepMoveFor(ACharacter* Character)
{
    Super::PrepMoveFor(Character);
    if (auto* Movement = Cast<UCasinoMovementComponent>(
            Character->GetCharacterMovement()))
    {
        Movement->ApplyReplayedMoveState(CasinoMoveFlags, IntendedMoveDirection);
        Movement->PendingFootPlant = FootPlant;
        Movement->MoveLocomotionRequest = LocomotionRequest;
        Movement->MoveFiredFootTimedAction = FiredFootTimedAction;
    }
}

Source: Source/Casino/Private/Components/CasinoMovementComponent.cpp

Successful seat-entry analysis tests cover foot plants, warp alignment, contact timing, leg stretch, warp shares, and unchanged sockets. View full resolution ↗
Recorded seat-entry analysis · 12 November 2026 The full report contains 243 successful tests, including 14 with warnings, and no failures. Selected checks cover foot plants, warp timing, contact time, leg stretch, and socket immutability. A run under network emulation with foot/pelvis overlays and correction counters remains outstanding.

Camera transitions and readable table play

A local-player camera component coordinates first-person, third-person, and dedicated table views. Interpolated zoom transitions between character perspectives, while table-view blends hand the view target to the active game and reposition card-value labels for readability. Optional follow rotation adapts to movement speed, and sensitivity and axis inversion support player preferences. Seat entry coordinates the camera with animation: it temporarily locks look, zoom, and view switching, eases a third-person camera out and behind the character, then hands over to first person at the entry handoff. Aborted entry restores the previous third-person zoom target.

Visibility and presentation cost are handled alongside those transitions. The spring arm probes the ground to prevent floor clipping, while traces to the character’s shoulders drive material parameters that let opted-in environment materials mask obstructing geometry. A gradual zoom-out ramp when leaving first person gives grooms time to load. Camera direction and body LOD also select cheaper groom materials and face mip levels, with hysteresis to avoid repeated swaps at the viewing-angle threshold.

Code evidence — eased seat-entry zoom and quaternion rotation:

EntrySwingElapsed += DeltaTime;
const float Progress = EntrySwingSeconds > UE_KINDA_SMALL_NUMBER
    ? FMath::Clamp(EntrySwingElapsed / EntrySwingSeconds, 0.f, 1.f)
    : 1.f;
const float Eased = FMath::InterpEaseInOut(0.f, 1.f, Progress, 2.f);

CurrentZoomDistance = FMath::Lerp(
    EntrySwingStartZoom, MaxCameraZoomDistance, Eased);
TargetZoomDistance = MaxCameraZoomDistance;
CameraBoom->TargetArmLength = CurrentZoomDistance;
OwningController->SetControlRotation(
    FQuat::Slerp(
        EntrySwingStartRotation.Quaternion(),
        EntrySwingTargetRotation.Quaternion(), Eased).Rotator());
bEntrySwingActive = Progress < 1.f;

Source: Source/Casino/Private/Player/Camera/CameraManager.cpp, TickEntrySwing (interpolation excerpt). Formatting adjusted for readability.

Automated testing and gameplay QA

Casinoverse contains approximately 79,600 lines of test code and an inventory of 1,596 registered Unreal automation tests across 301 C++ test files. Coverage spans unit, integration, network, asset, performance, and world-journey tests, including deep suites for NPC play, movement, significance, Roulette, table stations, Blackjack, animation, seating, faces, and chip logic. Native tests share deterministic vectors with the offline NPC simulator, while packaged Gauntlet/Horde workflows and NPC soak tools exercise complete environments.

Code evidence — native/Python parity contracts:

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
    FNPCSimulationGoldenContractTest,
    "Casino.NPCPlay.Simulation.SharedGoldenVectors",
    EAutomationTestFlags::EditorContext |
    EAutomationTestFlags::ProductFilter)

Source: Source/CasinoTests/Private/Unit/NPC_SimulationContract.spec.cpp

Automation summary shows 666 successful NPC-prefixed tests, zero failures, and 33 successes with warnings. View full resolution ↗
Recorded regression suite · 5 November 2026 All 666 tests with the Casino.NPC prefix, including Casino.NPCPlay, succeeded; 33 contain warnings and none report errors. The complete report took 214.6 seconds. This is evidence of that dated run rather than a fresh result for the current working tree.
Soak results and source report excerpts
Passing baccarat soak summary shows ten NPCs spawned and seated, 86 settled rounds, 15 resolved avoidance encounters, and zero reported known issues. View full resolution ↗
Recorded baccarat soak · 4 November 2026 The scenario runner passed with 10/10 NPCs spawned and seated, 86 settled rounds, and 15/15 avoidance encounters resolved. It reported no stuck, blocked, orphaned, or never-seated cases. Its observer log also contains a handled PSO-precache ensure; a newer 9 November run reports stuck/blocked and interrupted-activity failures that require follow-up.
Original baccarat QA report excerpt lists zero tracked seating and navigation failures and records the passing scenario metrics. View full resolution ↗
Source report excerpt · scenario-scoped verdict Original report text preserves the findings and thresholds; the long pinch-point inventory is omitted for readability. The visitor timeline in the NPC section shows the corresponding admission, wagering, settlement, and retirement milestones.
Source-derived JSON counts and selected successful NPC automation entries, including atomic snapshots and human demand before roulette double. View full resolution ↗
Source-derived automation entries The exact prefix filter, counts, warnings, and representative test entries are retained alongside the summary. A current-build suite and soak rerun are needed before describing today's build as passing.

Performance, scalability, and Pixel Streaming

Performance work uses repeatable hardware fingerprints, matrix runs, soak tests, Unreal Insights, GPU profiling, memory telemetry, and explicit CPU/GPU/VRAM/encoder thresholds. Controlled A/B tests measure screen percentage, skeletal LOD, hair rendering, significance tiers, animation budgets, and server-only cosmetic stripping. Runtime profiles cover desktop, mobile, and dedicated-server roles, with a sustained-frame-drop monitor able to fall back to a cheaper profile.

Code evidence — measured runtime fallback:

if (!FrameDropMonitor.Update(DeltaSeconds))
{
    return true;
}

const ECharacterPerfProfile From = ActiveProfileType.GetValue();
const ECharacterPerfProfile To = GetFallbackProfile(From);
if (To != From)
{
    ApplyProfileType(To);
}

Source: Source/Casino/Private/Config/PlatformProfileSubsystem.cpp

Validated Mobile Medium baseline compares one and two clients at 720p and 60 fps cap with target population 50, showing a host CPU limit at two clients. View full resolution ↗
Recorded capacity baseline · 8 November 2026 On the recorded RTX 5070 / Ryzen 5 7500F host, the Mobile Medium profile passes aggregate validity across two repeats at target population 50. One client meets the harness budget; two exceed its 85% host CPU threshold, reaching 89.74% p95. This is a measured capacity result for the recorded host and settings.
Insights data, provisional A/B measurements, and animation-budget instrumentation
Unreal Insights CSV excerpt shows timer names, counts, and inclusive and exclusive timings from a retained trace. View full resolution ↗
Recorded Unreal Insights export The timing export and six full traces are retained, including three Mobile Medium captures. This pictured CSV comes from a Mobile High run whose aggregate repeat-spread check fails; it demonstrates the profiling workflow rather than the accepted capacity result. Traces need inspection before public release.
Historical render A/B table records GPU timing changes for skeletal LOD bias, disabled hair strands, and 75 percent screen percentage on two clients, with the original invalid verdict preserved. View full resolution ↗
Historical A/B measurements · revalidation required Existing measurements cover skeletal LOD, hair strands, and screen percentage against paired baselines on two clients. The original outcome rejected priority value 32, which Windows defines as Normal; the current harness handles that conversion. The archived verdict must be revalidated before these deltas support an accepted benchmark. A controlled NPC-count sweep remains outstanding.
Original in-game Animation Budget Allocator overlay shows 21 registered components and six ticked components. View full resolution ↗
Original gameplay debug capture · animation budget The unmodified overlay shows budget participation with 21 registered and six ticked components. It demonstrates runtime instrumentation; a paired baseline is needed to quantify an improvement.

Editor tooling, build structure, and deployment

Runtime, editor, developer-test, tools, and dedicated-server targets are separated. The editor module contains custom AnimGraph nodes, animation modifiers, seat-entry analysis, authoring libraries, and an NPC StateTree authoring commandlet. Native and packaged test runners, performance harnesses, local backend management, environment configuration, and deployment scripts keep development-only code outside shipping builds while automating repetitive authoring and verification.

Code evidence — editor-only tooling dependencies:

PrivateDependencyModuleNames.AddRange(new string[]
{
    "Casino",
    "AnimGraph",
    "AnimationModifiers",
    "AnimationBlueprintLibrary",
    "BlueprintGraph",
    "UnrealEd",
    "StateTreeModule",
    "StateTreeEditorModule"
});

Source: Source/CasinoEditor/CasinoEditor.Build.cs

Original StateTree authoring log records the saved asset, result zero, 22 warnings, and an invalid gameplay tag warning. View full resolution ↗
Recorded StateTree commandlet · 9 November 2026 The apply command saved ST_NPC.uasset, wrote its text dump, and returned result 0 in 2.23 seconds. The original completion lines retain 22 warnings, including invalid tag AI.Activity.Sitting. A current rehearsal and editor graph screenshot are still needed.
Readable StateTree authoring summary
StateTree log summary shows activity reconsideration and spectating transitions followed by asset save and commandlet completion. View full resolution ↗
Recorded authoring summary · warnings retained The summary connects generated states and transitions to the saved asset and successful commandlet exit. The invalid tag, warning set, and earlier rehearsal crash remain follow-up items.

Start a conversation

Building ambitious systems in Unreal?

For technical leadership, Unreal Engine 5, C++, gameplay systems, and production delivery.

Email Sean