Add MVP network relevancy rules

This commit is contained in:
2026-05-18 15:14:58 -07:00
parent ebc7aa1ec6
commit d4ea10c628
11 changed files with 89 additions and 1 deletions
+4 -1
View File
@@ -718,7 +718,10 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe
- [x] Add replicated weather. - [x] Add replicated weather.
- [x] Add replicated resource nodes. - [x] Add replicated resource nodes.
- [x] Add replicated build pieces. - [x] Add replicated build pieces.
- [ ] Add network relevancy rules. - [x] Add network relevancy rules. Added explicit MVP net cull distances for
pickups, resources, campfires, shelters, wildlife, water sources, weather
exposure zones, and wildlife spawn managers, with the matching relevancy
strategy documented for Ground Zero multiplayer tests.
- [ ] Add basic latency testing. - [ ] Add basic latency testing.
- [ ] Add disconnect/reconnect handling. - [ ] Add disconnect/reconnect handling.
+12
View File
@@ -224,6 +224,18 @@ Near-term rules:
- not replicated as gameplay actors: static terrain package files and large - not replicated as gameplay actors: static terrain package files and large
tile metadata payloads. tile metadata payloads.
MVP actor cull distances:
- item pickups: 30 meters;
- resource nodes: 45 meters;
- campfires, shelters, and wildlife: 60 meters;
- water sources and weather exposure zones: 65 meters;
- wildlife spawn managers: 80 meters.
These are intentionally conservative prototype values. They prevent the first
Ground Zero multiplayer test from replicating every interactable to every
client while still keeping nearby survival objects responsive.
Future rules should align with World Partition, tile boundaries, settlement Future rules should align with World Partition, tile boundaries, settlement
density, and player population. density, and player population.
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""Validate MVP network relevancy rules."""
from pathlib import Path
import sys
ROOT = Path(__file__).resolve().parents[1]
def read(relative_path: str) -> str:
path = ROOT / relative_path
if not path.exists():
raise AssertionError(f"Missing required file: {relative_path}")
return path.read_text(encoding="utf-8")
def require(content: str, needle: str, context: str) -> None:
if needle not in content:
raise AssertionError(f"Missing {needle!r} in {context}")
def main() -> int:
errors: list[str] = []
checks = {
"Source/AgrarianGame/AgrarianItemPickup.cpp": ["NetCullDistanceSquared = FMath::Square(3000.0f);"],
"Source/AgrarianGame/AgrarianResourceNode.cpp": ["NetCullDistanceSquared = FMath::Square(4500.0f);"],
"Source/AgrarianGame/AgrarianCampfire.cpp": ["NetCullDistanceSquared = FMath::Square(6000.0f);"],
"Source/AgrarianGame/AgrarianShelterActor.cpp": ["NetCullDistanceSquared = FMath::Square(6000.0f);"],
"Source/AgrarianGame/AgrarianWildlifeBase.cpp": ["NetCullDistanceSquared = FMath::Square(6000.0f);"],
"Source/AgrarianGame/AgrarianWaterSource.cpp": ["NetCullDistanceSquared = FMath::Square(6500.0f);"],
"Source/AgrarianGame/AgrarianWeatherExposureZone.cpp": ["NetCullDistanceSquared = FMath::Square(6500.0f);"],
"Source/AgrarianGame/AgrarianWildlifeSpawnManager.cpp": ["NetCullDistanceSquared = FMath::Square(8000.0f);"],
"Docs/MultiplayerNetworkingDesign.md": [
"MVP actor cull distances",
"item pickups: 30 meters",
"resource nodes: 45 meters",
"campfires, shelters, and wildlife: 60 meters",
"water sources and weather exposure zones: 65 meters",
"wildlife spawn managers: 80 meters",
],
"AGRARIAN_DEVELOPMENT_ROADMAP.md": [
"[x] Add network relevancy rules.",
"explicit MVP net cull distances",
],
}
for relative_path, needles in checks.items():
try:
content = read(relative_path)
for needle in needles:
require(content, needle, relative_path)
except AssertionError as exc:
errors.append(str(exc))
if errors:
for error in errors:
print(f"ERROR: {error}", file=sys.stderr)
return 1
print("PASS: MVP network relevancy rules are wired and documented.")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+1
View File
@@ -16,6 +16,7 @@ AAgrarianCampfire::AAgrarianCampfire()
{ {
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bCanEverTick = true;
bReplicates = true; bReplicates = true;
NetCullDistanceSquared = FMath::Square(6000.0f);
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
RootComponent = Mesh; RootComponent = Mesh;
@@ -9,6 +9,7 @@
AAgrarianItemPickup::AAgrarianItemPickup() AAgrarianItemPickup::AAgrarianItemPickup()
{ {
bReplicates = true; bReplicates = true;
NetCullDistanceSquared = FMath::Square(3000.0f);
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
RootComponent = Mesh; RootComponent = Mesh;
@@ -12,6 +12,7 @@
AAgrarianResourceNode::AAgrarianResourceNode() AAgrarianResourceNode::AAgrarianResourceNode()
{ {
bReplicates = true; bReplicates = true;
NetCullDistanceSquared = FMath::Square(4500.0f);
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
RootComponent = Mesh; RootComponent = Mesh;
@@ -9,6 +9,7 @@
AAgrarianShelterActor::AAgrarianShelterActor() AAgrarianShelterActor::AAgrarianShelterActor()
{ {
bReplicates = true; bReplicates = true;
NetCullDistanceSquared = FMath::Square(6000.0f);
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
RootComponent = Mesh; RootComponent = Mesh;
@@ -9,6 +9,7 @@
AAgrarianWaterSource::AAgrarianWaterSource() AAgrarianWaterSource::AAgrarianWaterSource()
{ {
bReplicates = true; bReplicates = true;
NetCullDistanceSquared = FMath::Square(6500.0f);
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
RootComponent = Mesh; RootComponent = Mesh;
@@ -6,6 +6,7 @@
AAgrarianWeatherExposureZone::AAgrarianWeatherExposureZone() AAgrarianWeatherExposureZone::AAgrarianWeatherExposureZone()
{ {
bReplicates = true; bReplicates = true;
NetCullDistanceSquared = FMath::Square(6500.0f);
ExposureVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("ExposureVolume")); ExposureVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("ExposureVolume"));
RootComponent = ExposureVolume; RootComponent = ExposureVolume;
@@ -14,6 +14,7 @@ AAgrarianWildlifeBase::AAgrarianWildlifeBase()
{ {
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bCanEverTick = true;
bReplicates = true; bReplicates = true;
NetCullDistanceSquared = FMath::Square(6000.0f);
AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned; AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;
AIControllerClass = AAIController::StaticClass(); AIControllerClass = AAIController::StaticClass();
@@ -9,6 +9,7 @@ AAgrarianWildlifeSpawnManager::AAgrarianWildlifeSpawnManager()
{ {
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bCanEverTick = true;
bReplicates = true; bReplicates = true;
NetCullDistanceSquared = FMath::Square(8000.0f);
SetReplicatingMovement(false); SetReplicatingMovement(false);
} }