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
View full resolution ↗
Archetype tuning in the offline NPC simulator
View full resolution ↗
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
View full resolution ↗
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
View full resolution ↗
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
View full resolution ↗
Soak results and source report excerpts
View full resolution ↗
View full resolution ↗
View full resolution ↗
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
View full resolution ↗
Insights data, provisional A/B measurements, and animation-budget instrumentation
View full resolution ↗
View full resolution ↗
View full resolution ↗
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
View full resolution ↗
Readable StateTree authoring summary
View full resolution ↗