Server Authority¶
Summary: All gameplay-critical operations use server-authoritative patterns with
Server_prefixed RPCs. Authority checks useHasAuthority()andGetLocalRole(). Item operations use GUID-based validation to detect desync and prevent duplication. Clients use optimistic prediction with server correction.
Table of Contents¶
- Why Server Authority
- Authority Model
- Server RPC Patterns
- Authority Checks
- Validation Patterns
- Desync Detection
- Client Prediction
- Anti-Cheat Patterns
- Source References
- Related Systems
- Recent Changes
Why Server Authority¶
The Trust Problem¶
In multiplayer games, clients cannot be trusted. A malicious client could: - Claim to have items they do not possess - Report damage values higher than possible - Move faster than allowed - Execute actions on cooldown
Server authority solves this by making the server the single source of truth for all gameplay state.
Design Principles¶
| Principle | Implementation |
|---|---|
| Server owns state | All authoritative data lives on server |
| Clients request | Clients send RPCs asking server to act |
| Server validates | Every request is verified before execution |
| Server broadcasts | Results replicate to all clients |
Authority Model¶
Authority Flow¶
+----------------+ +----------------+
| CLIENT | | SERVER |
+----------------+ +----------------+
| |
| 1. User Action |
| (click item) |
| |
| 2. HasAuthority()? |
| NO |
| |
| 3. Server_RPC() ------------> |
| |
| 4. Validate Request
| - Item exists?
| - Player owns it?
| - Space available?
| |
| 5. Execute or Reject
| |
| <--------------------------- 6. Replicate Result
| |
| 7. OnRep_ Callback |
| UI Updates |
| |
Authority Hierarchy¶
Server (HasAuthority = true)
|
+-- Owns all gameplay state
+-- Validates all requests
+-- Executes all mutations
+-- Broadcasts results
|
v
Clients (HasAuthority = false)
|
+-- ROLE_AutonomousProxy (owning client)
| - Local prediction allowed
| - Receives corrections
|
+-- ROLE_SimulatedProxy (other clients)
- Interpolates replicated state
- No local prediction
Server RPC Patterns¶
Standard Pattern¶
All server RPCs follow a consistent pattern:
Client Call Path:
if (!HasAuthority())
Server_DoAction(params)
return optimistic_result
Server Execution:
Server_DoAction_Implementation(params)
- Validate request
- Execute if valid
- Reject if invalid (MarkArrayDirty for correction)
RPC Contract Table¶
| RPC | Parameters | Validation | Result |
|---|---|---|---|
Server_TryAddItemToContainer |
UItemObject* |
Item valid, space available | Item added or rejected |
Server_SwapItems |
Items, Indices, Target | Items at claimed positions | Swap or correction |
Server_PlaceItemById |
FGuid, Index |
GUID lookup, space check | Place or correction |
Server_DropItem |
UItemObject*, Count |
Item owned, count valid | Item dropped |
Server_ApplyDamage |
AActor*, FHitResult |
Target valid, in range | Damage applied |
Server_Move |
FVector |
Direction magnitude | Movement applied |
GUID-Based RPCs¶
Item pointers can be spoofed. GUID-based RPCs are more secure:
Client:
Item->InitializeInstanceId() // Generate GUID locally
Server_PlaceItemById(Item->GetInstanceId(), TargetIndex)
Server:
UItemObject* Item = Registry->FindItemByInstanceId(ItemId)
if (Item)
PlaceItem_Implementation(Item, TargetIndex)
Authority Checks¶
Check Methods¶
| Method | Returns True When | Use Case |
|---|---|---|
HasAuthority() |
Actor owned by this process | Server-only logic |
GetLocalRole() == ROLE_Authority |
This is the server | Same as HasAuthority |
GetLocalRole() == ROLE_AutonomousProxy |
This is the owning client | Client prediction |
GetLocalRole() == ROLE_SimulatedProxy |
This is a remote client | Interpolation |
Authority Check Patterns¶
Pattern 1: Server-Only Execution
+-------------------+
| if (!HasAuthority) |-----> return / send RPC
+-------------------+
|
v (server continues)
Execute Logic
Pattern 2: Role-Based Behavior
+--------------------------------+
| switch (GetLocalRole()) |
| ROLE_Authority: full logic |
| ROLE_AutonomousProxy: predict|
| ROLE_SimulatedProxy: display |
+--------------------------------+
Where to Check Authority¶
| Location | Why |
|---|---|
| Component initialization | Server grants abilities, applies attributes |
| State mutations | Only server modifies authoritative state |
| Collision processing | Server handles all hit detection |
| Container creation | Server creates subobjects |
Validation Patterns¶
Pointer Validation¶
| Macro | Use Case | Behavior |
|---|---|---|
ensure() |
Expected-valid pointers | Logs if null, continues |
check() |
Must-be-valid pointers | Crashes if null |
IsValid() |
Runtime checks | Returns bool |
Validation Flow¶
Server_SwapItems_Implementation(HoverItem, HoverIndex, ClickedItem, ClickedIndex, TargetIndex)
|
+-- Basic Validation
| IsValid(HoverItem)?
| IsValid(ClickedItem)?
|
+-- Authority Lookup
| HoverEntry = FindEntryAtIndex(HoverIndex)
| ClickedEntry = FindEntryAtIndex(ClickedIndex)
|
+-- Desync Check
| HoverEntry->Item == HoverItem?
| ClickedEntry->Item == ClickedItem?
|
+-- Space Validation
| IsSpaceAvailable(dimensions, target, excludes)?
|
+-- Execute or Reject
Desync Detection¶
Why Desync Happens¶
Desync occurs when client and server state diverge: - Network latency - Prediction errors - Packet loss - Race conditions
Detection Strategy¶
Client Claims Server Reality
+----------------+ +----------------+
| Item A at 0 | | Item A at 0 | <-- Match
| Item B at 5 | | Item C at 5 | <-- DESYNC!
+----------------+ +----------------+
|
v
MarkArrayDirty()
Force full resync
Correction Flow¶
Server detects desync:
1. Log warning for debugging
2. MarkArrayDirty() on FastArray
3. Return without executing
4. Client receives corrected state via replication
5. Client OnRep_ rebuilds local state
Client Prediction¶
Optimistic Return Pattern¶
Clients assume success for better UX:
Client:
Server_TryAddItem(Item)
return true // Optimistic - assume it works
[Show item in UI immediately]
Server (if fails):
MarkArrayDirty() // Force correction
Client (on next replication):
OnRep_InventoryList() // Corrects UI
Movement Interpolation¶
Remote players use smooth interpolation instead of snapping:
OnRep_ReplicatedServerPosition():
|
+-- GetLocalRole() == ROLE_SimulatedProxy?
|
NO --> Do nothing (local player)
|
YES --> Interpolate:
CurrentLocation --VInterpTo--> ServerPosition
(smooth over time)
Prediction Limits¶
| Can Predict | Cannot Predict |
|---|---|
| Local movement | Other player actions |
| Ability activation | Damage results |
| UI state | Item creation |
| Visual effects | Container changes |
Anti-Cheat Patterns¶
Server-Only Damage¶
Damage is never calculated on clients:
Server:
AProjectileBase::OnCollisionOverlap
|
+-- HasAuthority()? NO --> return
|
+-- ProcessHit
ApplyDamageToTarget(Target)
ApplyPoiseDamage(Target)
TriggerImpactEffects(Hit)
The One Deliberate Exception: Dev Cheat Relay¶
AEternalPlayer::Server_ExecuteCheat lets a client hand a command string to the server, which is exactly
the shape "clients never drive server-side state" forbids. It exists because authority-requiring dev
cheats are otherwise unreachable from a client on a dedicated session. Four guards keep it from becoming
a hole:
| Guard | Effect |
|---|---|
Requires a server-side CheatManager to exist |
Cheats must be enabled on that server (always in PIE; -EnableCheats otherwise). That existence check is the authorization gate |
Dispatch through ProcessConsoleExec on the cheat manager |
Only declared cheat functions are reachable — never arbitrary engine console commands |
| 256-character command cap | Bounds abuse of the reliable channel |
| Compiled out of Shipping | The relay does not exist in a shipping build at all |
Treat it as a dev-build affordance, not a precedent — nothing in gameplay should take a command string from a client.
Collision Authority¶
Only the server processes meaningful collisions:
Projectile Collision Flow:
+------------------+
| OnCollisionOverlap |
+------------------+
|
v
+------------------+
| HasAuthority()? |----NO----> return (client ignores)
+------------------+
| YES
v
+------------------+
| State == Active? |----NO----> return
+------------------+
| YES
v
+------------------+
| HandleHit() |
+------------------+
Container Creation Authority¶
Subobjects can only be created on the server:
GetGlyphContainerForPlate(StonePlateItem):
|
+-- HasAuthority()?
|
NO --> return nullptr (clients cannot create)
|
YES --> CreateContainer()
Source References¶
Authority Checks¶
UItemContainerComponent::AddItemAtPosition_Implementation- Source/ProjectEternal/Private/Inventory/Components/ItemContainerComponent.cppAEternalCharacter::InitAbilityActorInfo- Source/ProjectEternal/Private/Character/EternalCharacter.cppAProjectileBase::OnCollisionOverlap- Source/ProjectEternal/Private/Combat/Projectiles/ProjectileBase.cpp
Server RPCs¶
UItemContainerComponent::Server_SwapItems_Implementation- Source/ProjectEternal/Private/Inventory/Components/ItemContainerComponent.cppUItemContainerComponent::Server_PlaceItemById_Implementation- Source/ProjectEternal/Private/Inventory/Components/ItemContainerComponent.cppAEternalPlayer::Server_Move_Implementation- Source/ProjectEternal/Private/Character/EternalPlayer.cpp
Validation¶
UItemContainerComponent::CanAddItemAt_Implementation- Source/ProjectEternal/Private/Inventory/Components/ItemContainerComponent.cpp- Desync detection in
Server_SwapItems- Source/ProjectEternal/Private/Inventory/Components/ItemContainerComponent.cpp
GUID Operations¶
UItemObject::InitializeInstanceId- Source/ProjectEternal/Private/Inventory/Items/ItemObject.cppUPlayerGlyphComponent::TryEquipStonePlateAtSlot- Source/ProjectEternal/Private/Glyph/Components/PlayerGlyphComponent.cpp
Related Systems¶
- Replication Overview - Property replication patterns
- API Layer - Backend communication
- Inventory System - Item operations in detail
- Combat System - Damage application
Recent Changes¶
| Date | Change | Reason |
|---|---|---|
| - | Initial documentation | Document server authority patterns |
| 2026-07-03 | Fixed PlayerGlyphComponent.cpp path; stripped line numbers from Source References | Accurate, non-brittle references |
Future Considerations¶
| Enhancement | Benefit | Complexity |
|---|---|---|
| Rate Limiting | Prevent RPC spam | Low |
| Movement Validation | Detect speed hacks | Medium |
| Audit Logging | Track suspicious activity | Low |
| Hit Verification | Server-side replay validation | High |
| GUID Encryption | Prevent GUID spoofing | Medium |