# Advanced Replication and Networking

Advanced networking patterns beyond the basics in gameframework.md. Covers Net Dormancy, conditional replication, push model, Iris, and multiplayer architecture.

## Replication conditions (DOREPLIFETIME with conditions)
```cpp
void AMyActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    // Always replicate:
    DOREPLIFETIME(AMyActor, Health);

    // Only to owner (e.g., ammo count — only owning player needs it):
    DOREPLIFETIME_CONDITION(AMyActor, AmmoCount, COND_OwnerOnly);

    // Only to non-owner (e.g., cosmetic state — owner already knows):
    DOREPLIFETIME_CONDITION(AMyActor, bIsAiming, COND_SkipOwner);

    // Only on initial replication (static data):
    DOREPLIFETIME_CONDITION(AMyActor, TeamId, COND_InitialOnly);

    // Never (use for properties that are gameplay-relevant but manually synced):
    DOREPLIFETIME_CONDITION(AMyActor, CachedValue, COND_Never);

    // Custom condition (advanced — with custom replicated lifetime):
    DOREPLIFETIME_CONDITION(AMyActor, SecretData, COND_Custom);
}
```

## All COND_ values
Discover all replication conditions at runtime:
Use `query_ue_api` to discover all lifetime replication condition enum values at runtime.
Most common: COND_None (always), COND_InitialOnly (first rep), COND_OwnerOnly (to owner), COND_SkipOwner (everyone else), COND_Never (disabled).

## Push Model replication (UE5 optimization)
```cpp
// In Build.cs, ensure bWithPushModel is true (engine default in UE5)

// Header:
#include "Net/UnrealNetwork.h"
#include "Net/Core/PushModel/PushModel.h"

UPROPERTY(Replicated)
float Health;

// Instead of changing and waiting for next net update, mark dirty:
void AMyActor::SetHealth(float NewHealth)
{
    if (Health != NewHealth)
    {
        Health = NewHealth;
        MARK_PROPERTY_DIRTY_FROM_NAME(AMyActor, Health, this);
        // Only sends network update when actually changed
    }
}
```

## Net Dormancy (pause replication for static actors)
```cpp
// In constructor:
NetDormancy = DORM_DormantAll;  // Don't replicate until woken

// When actor needs to update:
void AMyActor::OnDamaged()
{
    FlushNetDormancy();  // Wake up — start replicating
    Health -= Damage;
    MARK_PROPERTY_DIRTY_FROM_NAME(AMyActor, Health, this);
    // After changes stabilize, actor returns to dormant automatically
}

// Discover all dormancy states via query_ue_api
// Key values: DORM_Never (always replicated), DORM_DormantAll (paused for all)
```

## RPC patterns (Server, Client, NetMulticast)
```cpp
// SERVER RPC — client calls, server executes
UFUNCTION(Server, Reliable, WithValidation)
void Server_RequestAttack(FVector Target);

void AMyCharacter::Server_RequestAttack_Implementation(FVector Target)
{
    // Runs on server — validate and execute
    if (CanAttack()) ExecuteAttack(Target);
}

bool AMyCharacter::Server_RequestAttack_Validate(FVector Target)
{
    return Target.Size() < MaxAttackRange; // Anti-cheat validation
}

// CLIENT RPC — server calls, specific client executes
UFUNCTION(Client, Reliable)
void Client_ShowDamageNumber(float Damage, FVector Location);

// MULTICAST RPC — server calls, ALL clients execute
UFUNCTION(NetMulticast, Unreliable)  // Unreliable for cosmetic effects
void Multicast_PlayHitEffect(FVector HitLocation);
```

## Reliable vs Unreliable
- **Reliable**: Guaranteed delivery, ordered. Use for: state changes, ability activations, important gameplay events
- **Unreliable**: May be dropped, not ordered. Use for: cosmetic effects, frequent position updates, non-critical feedback
- **Rule of thumb**: If gameplay breaks without it → Reliable. If it's just visual → Unreliable.

## Network relevancy and prioritization
```cpp
// Override to control when actor is relevant to a connection:
virtual bool IsNetRelevantFor(const AActor* RealViewer,
    const AActor* ViewTarget,
    const FVector& SrcLocation) const override
{
    float DistSq = FVector::DistSquared(GetActorLocation(), SrcLocation);
    return DistSq < NetCullDistanceSquared;
}

// Net priority (higher = more frequent updates):
NetPriority = 3.0f;  // Default is 1.0, Characters are 3.0
NetUpdateFrequency = 100.f;  // Default is 100 Hz, reduce for less important actors
MinNetUpdateFrequency = 2.f;  // Minimum when bandwidth-starved
```

## Multiplayer architecture best practices
- **Authority model**: Server is authoritative for gameplay state. Clients predict, server validates.
- **Client prediction**: Move locally, send input to server, server validates and corrects.
- **Listen server**: One player is both client and server — check `HasAuthority()` everywhere.
- **Dedicated server**: No rendering — use `#if !UE_SERVER` for client-only code.
- **GameState**: Replicated to all — scores, match time, team info.
- **PlayerState**: Replicated to all — player name, score, team. One per player.
- **GameMode**: Server only — never replicated. Handles rules, spawning, match flow.

## Common networking patterns for games
- **Weapon fire**: Client → Server_Fire() → validate → apply damage → Multicast_PlayEffect()
- **Health**: Replicated with RepNotify, COND_None → Client updates UI in OnRep_Health
- **Inventory**: Server-authoritative, replicate to owner only (COND_OwnerOnly)
- **Score**: In PlayerState, replicated to all via GameState
- **Cosmetics**: NetMulticast Unreliable for VFX, animations, sounds

## Critical rules
- Always validate Server RPCs with `WithValidation` for anti-cheat
- Never trust client data — server must validate all gameplay-affecting inputs
- Use COND_ conditions to minimize bandwidth — don't replicate everything to everyone
- Use Push Model + MARK_PROPERTY_DIRTY for optimal bandwidth usage
- Use Net Dormancy for static world actors (doors, pickups, switches)
- GameMode is SERVER ONLY — never access it on clients
- Test with `Net PktLag=200` console command to simulate real network conditions
- Use `execute_python` with `[p.get_name() for p in unreal.find_class('Actor').get_all_properties() if 'Replic' in p.get_name()]` to discover replication API
