869 lines
40 KiB
Markdown
869 lines
40 KiB
Markdown
# Agrarian Technical Design Document
|
|
|
|
## Purpose
|
|
|
|
This document defines the technical shape of Agrarian at the foundation stage.
|
|
It translates the core design direction into practical architecture decisions,
|
|
runtime boundaries, data contracts, build lanes, and near-term implementation
|
|
rules.
|
|
|
|
Detailed designs for multiplayer/networking, persistence, Earth-scale terrain
|
|
streaming, economy/AGR, and art/code standards are intentionally split into
|
|
their own roadmap documents.
|
|
|
|
## Current Technical Baseline
|
|
|
|
Agrarian is an Unreal Engine 5.7 C++ project with Blueprint assets layered on
|
|
top for early gameplay content and testable prototype objects.
|
|
|
|
Current project direction:
|
|
|
|
- authoritative gameplay state lives on the server;
|
|
- clients receive replicated state for UI and presentation;
|
|
- core gameplay systems are C++ components or actors;
|
|
- content-facing configuration uses Data Assets where possible;
|
|
- MVP terrain starts with one real 1 km x 1 km Ground Zero tile;
|
|
- tile packages can be served from the MVP map tile server;
|
|
- Windows-Builder is the primary Unreal/Visual Studio build VM;
|
|
- Ubuntu-Codex is the source-control and automation workstation;
|
|
- Unraid `DevBox` hosts shared project storage and supporting VMs.
|
|
|
|
## Runtime Architecture
|
|
|
|
### Server Authority
|
|
|
|
The server is authoritative for gameplay outcomes.
|
|
|
|
Server-owned state includes:
|
|
|
|
- player survival values;
|
|
- inventory changes;
|
|
- crafting results;
|
|
- world time;
|
|
- weather state applied to gameplay;
|
|
- resource depletion/harvest results;
|
|
- wildlife state;
|
|
- placed structures;
|
|
- persistence save/load decisions.
|
|
|
|
Clients may request actions, but the server validates and applies results.
|
|
|
|
### Client Responsibilities
|
|
|
|
Clients are responsible for:
|
|
|
|
- player input;
|
|
- camera and local presentation;
|
|
- UI/HUD;
|
|
- local animation;
|
|
- local audio/visual feedback;
|
|
- displaying replicated survival, inventory, weather, and world state;
|
|
- local tile cache storage once streaming matures.
|
|
|
|
Clients should not directly call public weather APIs or mutate authoritative
|
|
world state.
|
|
|
|
### Gameplay System Boundaries
|
|
|
|
Early runtime systems should remain small and explicit:
|
|
|
|
- `AAgrarianGameState`: world time, weather, ambient temperature, replicated
|
|
environment state.
|
|
- `UAgrarianSurvivalComponent`: health, hunger, thirst, stamina, body
|
|
temperature, injury, and survival damage.
|
|
- Inventory component/classes: item stacks, item definitions, resource intake,
|
|
and crafting inputs/outputs.
|
|
- Crafting component/classes: recipes, validation, output creation. Current
|
|
primitive recipes include campfire, shelter parts, primitive shelter, basic
|
|
tool, bandage, and `simple_container`; the simple container is an inventory
|
|
craftable foundation for later placed storage and trade-container systems.
|
|
- Interaction component/classes: player-facing use/gather/build entry points.
|
|
- Resource actors: gatherable wood, stone, fiber, water, wildlife, and future
|
|
natural resources.
|
|
- Buildable actors: campfire, one-piece primitive shelter kits, and later
|
|
settlement infrastructure. For the version 0.1 MVP, shelter construction is
|
|
intentionally kit-based: frame, wall panel, and roof panel items are crafted
|
|
as inventory parts and then combined into a single placeable primitive
|
|
shelter actor. Fully modular wall-by-wall construction is deferred to
|
|
permanent structures so the first survival loop remains reliable.
|
|
- The MVP wall piece is `primitive_wall_panel`, a craftable inventory
|
|
construction part consumed by the primitive shelter recipe rather than an
|
|
independently placed wall actor.
|
|
- The MVP roof piece is `primitive_roof_panel`, a craftable inventory
|
|
construction part consumed by the primitive shelter recipe rather than an
|
|
independently placed roof actor.
|
|
- MVP primitive shelters use an open entrance and do not include an
|
|
interactive door. Door actors, locks, ownership permissions, and modular
|
|
openings are deferred to permanent structures.
|
|
- `AAgrarianShelterActor` includes a version 0.1 structure damage placeholder:
|
|
replicated current/max health, authority-only damage, repair, and
|
|
deconstruction hooks, `TakeDamage` integration, depletion destruction, and
|
|
persistent health state. This gives fire, weather, tools, and future
|
|
ownership systems a safe structure-health contract to extend.
|
|
- `UAgrarianBuildingPlacementComponent` owns the MVP placement preview. It
|
|
traces from the player view, snaps to the configured grid, validates distance
|
|
and collision, broadcasts Blueprint-readable preview state, and draws a
|
|
green/red wireframe ghost footprint in development builds so placement can be
|
|
tested before final mesh/material ghost assets exist.
|
|
- Persistence layer: save/load contracts for player and world state.
|
|
|
|
Blueprints can compose and expose these systems, but core replicated behavior
|
|
should remain in C++ as much as practical.
|
|
|
|
Inventory data is defined in `Docs/InventoryDataModel.md`. The MVP model uses
|
|
stable `ItemId` keys, design-time `FAgrarianItemDefinition` records, runtime
|
|
and save-game `FAgrarianItemStack` records, and a server-authoritative
|
|
`UAgrarianInventoryComponent` with replicated stack arrays. Pickup, drop,
|
|
splitting, item use, equipment, carry capacity, persistence, and UI work should
|
|
extend that contract rather than inventing parallel inventory state.
|
|
|
|
World pickups use `AAgrarianItemPickup`, an interactable replicated actor with a
|
|
static mesh and either a definition-backed or inline `FAgrarianItemStack`.
|
|
Player interaction already routes to the server through the Agrarian character,
|
|
so pickups validate authority, produce a valid stack, add it to the player's
|
|
inventory, and only then remove the pickup by destroying the world pickup actor.
|
|
If the inventory is full or the stack is invalid, the pickup remains in the
|
|
world for another attempt.
|
|
|
|
Developer item dropping is available through `AgrarianDropItem ItemId Quantity`.
|
|
The command routes to the server, extracts stack data before spawning so display
|
|
name and unit weight survive the drop, spawns an `AAgrarianItemPickup` in front
|
|
of the player, and restores the removed stack if pickup spawning fails. This is
|
|
the baseline behavior future UI-driven drop flows should call through rather
|
|
than duplicating inventory mutation logic on the client.
|
|
|
|
Stack splitting is available through `AgrarianSplitStack StackIndex SplitQuantity`
|
|
and `UAgrarianInventoryComponent::SplitStackByIndex`. Splitting is
|
|
server-authoritative, validates the source stack index, quantity, and free slot
|
|
capacity, copies the source stack metadata, reduces the source quantity, and
|
|
creates a separate inventory slot. It intentionally does not re-merge the split
|
|
stack through `AddItem`, because the UI needs an actual separate stack to
|
|
support later drag/drop and partial drop flows.
|
|
|
|
MVP item use is available through `AgrarianUseItem ItemId Quantity`. The command
|
|
routes to the server, extracts the requested stack quantity, applies a
|
|
whitelisted item effect, and restores the stack if the item is not usable yet.
|
|
For the first survival loop, `food` restores hunger, `meat` restores more hunger
|
|
but adds sickness risk because it is raw, and `bandage` is the MVP treatment
|
|
item: it reduces injury, bleeding, and sprain severity with a small health bump.
|
|
This gives UI item-use work a concrete authority path while leaving tools,
|
|
structures, and future complex consumables blocked until they have explicit
|
|
gameplay rules.
|
|
|
|
Dedicated equipment slots are intentionally deferred for the 0.1.E MVP. The
|
|
current `basic_tool` item can remain an inventory item until an implemented
|
|
system needs active hand, worn, backpack, armor, weapon, durability, animation,
|
|
or mesh-attachment state. When that need appears, equipment should be added as
|
|
server-authoritative, replicated, persisted slot state rather than as local UI
|
|
selection only.
|
|
|
|
Carry capacity is active as an MVP placeholder through stack `UnitWeight`,
|
|
inventory `GetTotalWeight`, and character movement penalties. The current
|
|
character uses `25.0` comfort and `60.0` heavy item-weight thresholds, scales
|
|
those thresholds by strength, and exposes current carried weight in the debug
|
|
HUD. Future backpacks, containers, awkward-object rules, and hard overload
|
|
limits should extend this total-weight path rather than creating a second carry
|
|
model.
|
|
|
|
The MVP inventory UI is a compact `AAgrarianDebugHUD` inventory panel, enabled
|
|
separately from the full developer HUD. It reads the replicated inventory stack
|
|
array, shows occupied slots, total carried weight, and a short visible stack
|
|
list, and leaves mutation actions on the existing server-authoritative commands
|
|
and RPCs until a full UMG inventory screen is introduced.
|
|
|
|
The MVP crafting UI is a compact `AAgrarianDebugHUD` crafting panel. The
|
|
Agrarian player Blueprint preloads primitive `KnownRecipeAssets`, and the HUD
|
|
reads those recipes plus the replicated inventory to show craftable status and
|
|
ingredient counts. Interactive UMG recipe browsing, hotkeys, and queued
|
|
crafting controls are deferred until the primitive loop settles.
|
|
|
|
Crafting debug tools live on the player controller. `AgrarianCraftStatus`
|
|
prints known recipes and current craftability, while `AgrarianCraft <RecipeId>`
|
|
requests a server-authoritative craft through `UAgrarianCraftingComponent`.
|
|
These commands are intended for smoke testing and investor-demo rehearsal until
|
|
proper UI input exists.
|
|
|
|
Inventory persistence saves `UAgrarianInventoryComponent::Items` into
|
|
`FAgrarianSavedPlayer::Inventory` and restores through
|
|
`UAgrarianInventoryComponent::RestoreSavedItems`. Restore broadcasts
|
|
`OnInventoryChanged`, which keeps the MVP HUD panel and future UI listeners in
|
|
sync after load while preserving total weight as a derived value.
|
|
|
|
## Time And Environment
|
|
|
|
The MVP gameplay calendar target is:
|
|
|
|
```text
|
|
4 real hours = 1 in-game day
|
|
```
|
|
|
|
The current C++ default is:
|
|
|
|
```text
|
|
GameHoursPerRealMinute = 0.1
|
|
```
|
|
|
|
That equals 6 in-game minutes per real minute, or 24 in-game hours over 4 real
|
|
hours.
|
|
|
|
Day/night presentation should mimic the represented Earth region's local solar
|
|
and weather context as the system matures. This means the gameplay calendar can
|
|
be compressed while visual lighting, seasonal direction, and weather mapping
|
|
still derive from the represented map tile.
|
|
|
|
Near-term technical work:
|
|
|
|
- add Ground Zero local time-zone metadata; completed for the current C++ game-state default.
|
|
- add sunrise/sunset lookup or approximation by latitude/longitude; completed as a tile-aware NOAA approximation in `AAgrarianGameState`.
|
|
- map real weather snapshots into internal Agrarian weather states;
|
|
- cache weather snapshots server-side;
|
|
- keep deterministic fallback weather when external data is unavailable.
|
|
|
|
The repeatable solar metadata data path is
|
|
`Scripts/generate_tile_solar_metadata.py`. It reads the tile registry and emits
|
|
metadata only for source-backed, generated, validated, packaged, or published
|
|
tiles with explicit time-zone data. Placeholder/unknown tiles are skipped so the
|
|
future Earth-scale registry does not generate or fetch data for theoretical
|
|
tiles that do not exist yet.
|
|
|
|
Calendar conversion helpers live in `AAgrarianGameState` and keep the MVP target
|
|
of `4 real hours = 1 in-game day`. The same game state now exposes replicated
|
|
calendar year/day, absolute-day, season, real-hour conversion, long-task
|
|
progress, and crop-season fit helpers. Crop checks use the active tile's
|
|
growing-zone profile, including frost-free days and a crop safety buffer, so a
|
|
long-maturity crop can be rejected or marked marginal in regions with short
|
|
seasons.
|
|
|
|
The repeatable growing-zone metadata data path is
|
|
`Scripts/generate_tile_growing_zone_metadata.py`. It reads the tile registry and
|
|
emits metadata only for source-backed, generated, validated, packaged, or
|
|
published tiles with explicit growing-zone data. Ground Zero currently uses a
|
|
conservative Pacifica coastal profile; later regional expansion should replace
|
|
or enrich these overrides with authoritative zone, climate, and temperature
|
|
datasets.
|
|
|
|
Temperature is authoritative on `AAgrarianGameState`. The MVP curve uses the
|
|
active tile's sunrise and solar noon to place the daily low near sunrise and the
|
|
daily high after solar noon, then applies weather modifiers for rain, cold wind,
|
|
and storms. Regional daily low/high values provide the deterministic fallback.
|
|
When a server-side weather adapter is available, it should set observed regional
|
|
temperature and blend weight through the game-state hook rather than allowing
|
|
clients to call public weather APIs directly. This keeps real-world temperature
|
|
and weather tied to the represented map tile while preserving a deterministic
|
|
fallback if an external provider is unavailable.
|
|
|
|
Primitive shelters expose a replicated protection volume and
|
|
`WeatherProtection` rating. Server-side survival ticks calculate the best
|
|
overlapping shelter protection for each character, replicate the current
|
|
protection value, reduce ambient weather exposure and cold damage by that
|
|
percentage, and trend the care-history shelter quality field toward the active
|
|
protection level. The dev HUD shows current shelter protection so weather
|
|
pressure can be tuned during MVP tests.
|
|
|
|
Weather exposure zones use `AAgrarianWeatherExposureZone` volumes placed by the
|
|
Ground Zero setup script. They describe local ridge, coastal-wind, and drainage
|
|
cooling effects with an exposure multiplier and temperature offset. Server-side
|
|
survival ticks select the strongest overlapping zone effect, replicate the
|
|
current multiplier and offset, then apply them to ambient body-temperature drift
|
|
and cold damage after shelter protection. This lets future generated tiles add
|
|
biome, slope, elevation, hydrology, and coastal modifiers without changing the
|
|
core survival calculation.
|
|
|
|
The safe Ground Zero spawn is selected by `Scripts/setup_ground_zero_demo_map.py`
|
|
from declared candidate coordinates and a known safe fallback coordinate. The
|
|
setup validates the selected player start against terrain elevation, terrain
|
|
slope, a minimum above-terrain Z offset, freshwater spacing, and resource-cluster
|
|
spacing before saving the map. `Scripts/verify_ground_zero_safe_spawn.py`
|
|
rechecks the placed `AGR_DemoPlayerStart` against the same constraints so future
|
|
map, resource, water, or terrain changes cannot silently move the player below
|
|
sea level, into steep terrain, into water, or into a dense resource cluster.
|
|
|
|
The Ground Zero map also contains `AGR_GroundZeroMapBoundary`, a native
|
|
`AAgrarianMapBoundaryVolume` centered on the 1 km x 1 km MVP tile. For the MVP,
|
|
the boundary clamps server-authoritative player pawns back inside the loaded
|
|
tile with a small padding rather than allowing players to walk into missing
|
|
neighbor terrain. The actor exposes a warning distance hook so later UI can
|
|
present an in-world or HUD notice before a clamp occurs.
|
|
|
|
Developer testing supports server-authoritative developer travel through
|
|
`AgrarianTravel X Y Z` on `AAgrarianGamePlayerController`. The command teleports
|
|
the controlled pawn to explicit Unreal world coordinates, stops any current
|
|
character movement, and reports the destination to the issuing player.
|
|
`AgrarianTravelHome` returns the player to the validated Ground Zero safe-spawn
|
|
fallback near `AGR_DemoPlayerStart`, above sea level and above terrain by the
|
|
same safe offset used by the map setup pass.
|
|
|
|
First-pass sky and lighting use `AAgrarianSkyLightingController`. The controller
|
|
owns movable sun, skylight, and exponential-height-fog components and reads the
|
|
replicated `AAgrarianGameState` time, active tile sunrise/sunset, weather state,
|
|
and mapped cloud cover. It adjusts sun pitch, sun intensity/color, sky-light
|
|
intensity, and fog density every tick so the Ground Zero demo visually tracks
|
|
the represented local day/night cycle and current weather without hard-coded
|
|
static light settings. The Ground Zero map setup script places this controller
|
|
and removes the earlier static demo sun/skylight/fog actors.
|
|
|
|
First-pass biome and weather audio uses `AAgrarianWeatherAudioController`. The
|
|
controller owns ambient, rain, wind, and storm audio components with assignable
|
|
loop sound slots. The ambient component is explicitly the Ground Zero
|
|
coastal-scrub biome bed through `BiomeAmbientLoopSound`, with separate day and
|
|
night volume targets so the map can carry wind, surf, insects, distant birds, or
|
|
other realistic low-level biome texture before final authored assets are
|
|
available. It reads replicated weather state, provider wind speed, provider
|
|
cloud data, and local night/day state, then fades component volumes so rain,
|
|
wind, and storm cues follow the same authoritative weather mapping used by
|
|
temperature and lighting. The current MVP can ship without final sound assets
|
|
because the controller is silent until loops are assigned; placeholder or final
|
|
audio can be added by setting the exposed sound properties on the placed
|
|
controller or a Blueprint child.
|
|
|
|
Player movement audio starts with native footstep placeholders on
|
|
`AAgrarianGameCharacter`. The character owns a spatialized
|
|
`FootstepAudioComponent` plus assignable walk, sprint, crouch, and prone sound
|
|
slots. Cadence is state-aware and driven by horizontal movement, so the MVP can
|
|
remain silent until placeholder or final surface-aware cues are assigned while
|
|
still giving designers a real hook for step audio in packaged builds.
|
|
|
|
Gathering audio is owned by `AAgrarianResourceNode`. Successful
|
|
server-authoritative harvests call a multicast placeholder cue so nearby
|
|
clients can hear the action without trusting client-side gathering requests.
|
|
Each resource node exposes `GatheringSound` and `DepletedGatheringSound` slots,
|
|
with a spatialized `GatheringAudioComponent`; the system remains silent until
|
|
resource-specific placeholder or final cues are assigned.
|
|
|
|
Campfire audio is split between a persistent spatialized loop and short
|
|
server-triggered event cues. `AAgrarianCampfire` exposes `FireLoopSound`,
|
|
`IgniteSound`, and `ExtinguishSound` slots. Replicated lit-state updates start
|
|
or stop the loop on clients, while the authoritative server multicasts ignition
|
|
and extinguish events so the audio follows the same state changes as light,
|
|
smoke, warmth, fuel, and persistence.
|
|
|
|
Campfires now track unattended and poorly maintained fire risk on the server.
|
|
`AAgrarianCampfire` records lit duration, seconds since maintenance, whether the
|
|
area has been cleared, whether the fire is contained, and a replicated
|
|
`FireRiskScore`. Risk grows after a fire has been left unattended, grows faster
|
|
when excessive fuel is burning, and is reduced by maintenance, cleared area,
|
|
containment, and wet weather. This first risk layer does not yet ignite nearby
|
|
vegetation or structures; later 0.1.P items consume the replicated risk score.
|
|
|
|
Grass and forest ignition checks consume that risk score. Campfires query
|
|
`AAgrarianFoliagePatch` for nearby grass, shrub, and tree instance counts inside
|
|
`VegetationIgnitionCheckRadius`. Unsafe placement near dry fuel accumulates
|
|
separate replicated grass/brush and forest ignition risk, adjusted by burn
|
|
duration, wind speed, current weather, cleared-area maintenance, and the
|
|
campfire's current risk ratio. Reaching the threshold marks the relevant
|
|
ignition flag, while later spread rules decide how active fires propagate.
|
|
|
|
Structure ignition risk uses the same server-authoritative campfire risk model.
|
|
Open fires check nearby primitive shelters plus flammable wood/fiber resource
|
|
nodes as MVP stand-ins for wood piles, flammable crafting stations, and future
|
|
settlement objects. Contained fires skip this structure check; otherwise
|
|
structure risk accumulates with distance-based fuel presence, burn duration,
|
|
weather/wind, and the current fire-risk ratio before setting a replicated
|
|
structure ignition flag.
|
|
|
|
Active fire spread is still server-authoritative at the campfire/open-flame
|
|
source. Once grass/brush, forest, or structure ignition flags are set, the server
|
|
updates replicated fire intensities and an active spread radius. The spread rule
|
|
uses nearby fuel, ignition distance implied by the existing checks, wind/weather
|
|
modifiers, and a suppression-pressure hook that future rain, carried water,
|
|
dirt/sand, firebreaks, and tools can drive. This establishes deterministic fire
|
|
state for clients without letting clients decide whether the world is burning.
|
|
|
|
Fire maintenance gameplay uses the same authority path as ignition and fuel.
|
|
Interacting with a lit campfire now presents as maintaining the fire; if the
|
|
player has wood it still adds fuel, and if not it watches/maintains the fire.
|
|
Native hooks also let future UI/actions explicitly clear the fire area or
|
|
contain the fire. Watched, cleared, contained, and extinguished fires reduce
|
|
risk, while neglected fires continue accumulating ignition and spread pressure.
|
|
|
|
Campfires expose native extinguish logic through `AAgrarianCampfire::Extinguish`.
|
|
Extinguishing clears remaining fuel, turns off replicated lit state, and reuses
|
|
the same visual update path as natural fuel depletion.
|
|
|
|
Campfires also expose a minimal replicated cooking placeholder. While lit and
|
|
enabled, `AAgrarianCampfire` advances `CookingProgressSeconds` toward
|
|
`CookingSecondsRequired` on the server and exposes `CanCook` plus a normalized
|
|
progress ratio for future recipe UI, food transformation, and interaction hooks.
|
|
|
|
Campfire visuals include an assetless `SmokeEffect` particle-system component
|
|
placeholder. It is attached above the fire, starts inactive, and follows the
|
|
same replicated lit-state visual update path as fire light intensity so final
|
|
smoke or ember assets can be assigned later without changing gameplay code.
|
|
|
|
Campfire persistence uses the shared `UAgrarianPersistentActorComponent` world
|
|
actor path. `AAgrarianCampfire` implements the persistence-state provider hook
|
|
to write lit state, remaining fuel, cooking enabled state, required cook time,
|
|
and cooking progress into numeric save state, then restores those values before
|
|
reapplying the fire visual state on load.
|
|
|
|
Campfires now read the replicated `AAgrarianGameState::Weather` value while
|
|
burning. Rain and storms increase fuel drain through tunable multipliers, and
|
|
wet weather can deterministically extinguish a low-fuel fire so weather affects
|
|
fire reliability without adding random outcomes to save/load or multiplayer
|
|
state.
|
|
|
|
The first real-weather adapter is `UAgrarianWeatherProviderSubsystem`. It uses
|
|
Open-Meteo forecast requests keyed by tile center latitude/longitude, parses the
|
|
current temperature, daily low/high, precipitation, wind, humidity, cloud cover,
|
|
pressure, provider timestamp, and weather code, then applies the mapped state to
|
|
`AAgrarianGameState` on the server. It is tile-driven rather than Ground-Zero
|
|
hard-coded: `Scripts/generate_tile_weather_manifest.py` emits every
|
|
source-backed, generated, validated, packaged, or published tile with center
|
|
coordinates, while placeholder/unknown tiles are skipped. Future source-backed
|
|
tiles therefore become weather-eligible when their registry entries are added.
|
|
|
|
Ground Zero weather lookup coordinates are explicit in the tile registry. The
|
|
current MVP tile `gz_us_ca_pacifica_utm10n_e544_n4160` uses its tile center,
|
|
latitude `37.5925` and longitude `-122.4995`, as the canonical real-world
|
|
weather lookup point. `Scripts/generate_tile_weather_manifest.py` reads
|
|
`weather_lookup_metadata` when present, falls back to the tile center for
|
|
source-backed tiles, and emits the provider routing used by the weather
|
|
subsystem.
|
|
|
|
Open-Meteo is the first global MVP weather source. The provider contract is
|
|
stored in `Data/Weather/open_meteo_mvp_source.json`, including the forecast
|
|
endpoint, requested current/daily variables, tile lookup rule, and Agrarian
|
|
mapping notes. `Scripts/verify_open_meteo_mvp_source.py` validates the static
|
|
contract and can perform a live Open-Meteo request for every source-backed tile
|
|
in `Data/Tiles/tile_weather_manifest.json`. This keeps the provider global for
|
|
all future real tiles instead of adding one-off Ground Zero weather code.
|
|
|
|
NOAA/NWS is the US-only fallback and enrichment path. The provider contract is
|
|
stored in `Data/Weather/noaa_nws_us_fallback.json`. The weather provider
|
|
subsystem can check whether an active tile center coordinate is inside the
|
|
approximate NWS coverage window, request `api.weather.gov/points/{lat},{lon}`,
|
|
follow `properties.forecastGridData`, and parse gridded temperature,
|
|
precipitation probability, and wind speed as fallback inputs. The NWS path is
|
|
only used for eligible US/NWS-covered tiles; Open-Meteo remains the global
|
|
source for all tiles.
|
|
|
|
Real-weather snapshots are cached server-side in
|
|
`UAgrarianWeatherProviderSubsystem::ServerWeatherSnapshotCache`. Cache keys use
|
|
provider plus tile ID, and the default TTL is 15 minutes. Server requests first
|
|
try to apply a fresh cached snapshot to `AAgrarianGameState`; only cache misses
|
|
call Open-Meteo or NOAA/NWS. Clients never call Open-Meteo or NOAA/NWS directly.
|
|
They receive weather, temperature, source, and state through replicated game
|
|
state fields.
|
|
|
|
Real-weather provider values are mapped into `FAgrarianMappedWeatherInputs`
|
|
before they affect gameplay. The mapped snapshot keeps tile ID, tile center
|
|
coordinate, temperature,
|
|
precipitation, wind, cloud cover, humidity, pressure, visibility, and provider
|
|
weather code available alongside the collapsed Agrarian weather state. Open-Meteo
|
|
fills those fields directly where available; NOAA/NWS fills them from grid data
|
|
where available and derives provisional visibility/weather-state values until a
|
|
deeper provider-specific mapping pass is added.
|
|
|
|
The applied weather state also has a replicated debug snapshot:
|
|
`FAgrarianWeatherDebugSnapshot`. It records the weather source, provider
|
|
timestamp, tile ID, tile center coordinate, provider weather code, input values,
|
|
and final in-game `EAgrarianWeatherType` after mapping. Save files persist both
|
|
the mapped inputs and the applied debug snapshot so weather issues can be traced
|
|
back to a specific provider response and tile without inferring those values from
|
|
separate systems.
|
|
|
|
Deterministic fallback weather keeps the game playable when external providers
|
|
are disabled, unreachable, or return unusable data. The fallback snapshot is
|
|
derived from tile ID and Agrarian day, then mapped through the same
|
|
`FAgrarianMappedWeatherInputs` path as live providers. It produces seasonal
|
|
daily low/high temperatures, current temperature, cloud cover, humidity, wind,
|
|
pressure, precipitation, visibility, and the collapsed Agrarian weather state.
|
|
Fallback snapshots use provider `deterministic-fallback` and are cached
|
|
server-side with the normal weather cache TTL.
|
|
|
|
## Terrain And Tile Delivery
|
|
|
|
### MVP Tile
|
|
|
|
The MVP starts with one real Ground Zero tile:
|
|
|
|
- 1 km x 1 km tile;
|
|
- real elevation data imported into Unreal;
|
|
- metadata tracked in JSON registry files;
|
|
- static delivery package available from the map tile server.
|
|
|
|
### Tile Server
|
|
|
|
Current MVP endpoint:
|
|
|
|
```text
|
|
http://maps.agrariangame.com:18080
|
|
```
|
|
|
|
Current backing VM:
|
|
|
|
```text
|
|
Agrarian-TileServer
|
|
```
|
|
|
|
The tile server currently serves static files through nginx:
|
|
|
|
- `/health`
|
|
- `/manifest.json`
|
|
- `/ground_zero_tiles.json`
|
|
- `/schemas/tile_registry.schema.json`
|
|
- `/tiles/<tile_id>/v<package_version>/...`
|
|
|
|
The current tile client verification script proves:
|
|
|
|
- manifest download;
|
|
- registry lookup;
|
|
- package file download;
|
|
- checksum validation;
|
|
- neighbor metadata presence;
|
|
- delete/redownload cache recovery.
|
|
|
|
### Long-Term Tile Direction
|
|
|
|
The long-term tile system should support:
|
|
|
|
- 1 km x 1 km canonical tile IDs;
|
|
- versioned tile packages;
|
|
- server-side registry and package metadata;
|
|
- client local tile cache;
|
|
- cache retention and scrub policy;
|
|
- package revalidation and redownload;
|
|
- tile adjacency/stitching contracts;
|
|
- safe terrain updates that do not corrupt persisted player/world state.
|
|
|
|
The first implementation should stay static and simple until gameplay proves
|
|
why a database-backed tile service is needed.
|
|
|
|
## Data Contracts
|
|
|
|
### Data Assets
|
|
|
|
Use Unreal Data Assets for designer-facing definitions such as:
|
|
|
|
- item definitions;
|
|
- recipes;
|
|
- gatherable resource configuration;
|
|
- wildlife configuration;
|
|
- buildable structure definitions;
|
|
- future skill/knowledge definitions.
|
|
|
|
Data Assets should describe content. Server code should enforce gameplay rules.
|
|
|
|
### Gatherable Resources
|
|
|
|
The 0.1.F resource baseline uses `AAgrarianResourceNode` for simple gatherable
|
|
world resources. Wood, fiber, stone, and edible plants each have item
|
|
definitions or yield definitions, resource Blueprints, deterministic Ground Zero
|
|
placements, replicated remaining harvest counts, and bare-hand gathering through
|
|
the shared interaction path.
|
|
|
|
Stone specifically is represented by `DA_Item_Stone` and
|
|
`BP_StoneResourceNode`. Ground Zero includes stone nodes in slope, exposed
|
|
terrain, and valley-edge positions so primitive tools, campfires, and early
|
|
construction recipes have an in-world source instead of relying on debug grants.
|
|
Edible plants are represented by `BP_EdiblePlantResourceNode`, which yields the
|
|
MVP `food` item from scrub, grassland, and drainage-candidate forage patches.
|
|
|
|
Freshwater gathering uses `AAgrarianWaterSource` instead of the depleting
|
|
resource-node class. The placed `BP_FreshWaterSource` is still an
|
|
`IAgrarianInteractable`, appears through the same focused interaction prompt,
|
|
and restores thirst through `UAgrarianSurvivalComponent::AddWater` on server
|
|
authority. This keeps drinking compatible with the existing replicated survival
|
|
component while leaving later container filling, water quality, and source
|
|
depletion rules for future water-system work.
|
|
|
|
For the MVP, renewable MVP resource nodes respawn only after they are fully
|
|
depleted. Wood, fiber, and edible plant nodes are renewable because they
|
|
represent surface materials and forage that should return during continued
|
|
prototype play. Stone remains nonrespawning because it represents a slower
|
|
geologic resource and should push players to explore once local easy stone is
|
|
gone. Respawn timing is configurable per Blueprint through
|
|
`bRespawnsForMvp`, `RespawnDelaySeconds`, and `MaxHarvests`; the native node
|
|
uses a server-side timer and restores replicated `RemainingHarvests` when the
|
|
delay expires.
|
|
|
|
Tool requirement rules remain inventory-based for the MVP because dedicated
|
|
equipment slots are deferred. A resource node can declare `RequiredToolItemId`,
|
|
`bAllowBareHandGathering`, and `ToolQuantityBonus`. Current Ground Zero wood,
|
|
fiber, and stone nodes still allow bare-hand gathering so the first survival
|
|
loop cannot deadlock before the player can craft a tool. When the player has a
|
|
`basic_tool` in inventory, those nodes grant an extra unit per harvest. Edible
|
|
plants remain pure bare-hand gathering. Later nodes can disable
|
|
`bAllowBareHandGathering` when the game has proper tool equipment, durability,
|
|
and feedback UI.
|
|
|
|
Resource node persistence is map/tile state, not a spawned-actor replay path.
|
|
`UAgrarianSaveGame` stores `FAgrarianSavedResourceNode` records keyed by
|
|
`AAgrarianResourceNode::PersistenceNodeId`, with the actor name as a fallback.
|
|
`UAgrarianPersistenceSubsystem` captures only resource nodes that exist in the
|
|
currently loaded world and restores matching existing nodes by stable id. This
|
|
keeps the MVP compatible with later Earth-scale tiles: a tile contributes
|
|
resource depletion state only when its resource actors actually exist, and tile
|
|
generation/placement scripts should assign deterministic node ids.
|
|
|
|
### Wildlife Navigation
|
|
|
|
MVP wildlife movement is server authoritative. `AAgrarianWildlifeBase` uses an
|
|
AI controller and Unreal navigation when nav data exists: wander targets are
|
|
chosen from reachable nav points, chase/flee targets are projected onto navmesh,
|
|
and movement requests use `MoveToLocation`. If a test map or early generated
|
|
tile has no nav data, wildlife falls back to direct movement input so damage,
|
|
flee, chase, and harvest loops remain functional while map navigation is being
|
|
authored.
|
|
|
|
### Wildlife Spawning
|
|
|
|
`AAgrarianWildlifeSpawnManager` owns MVP wildlife population seeding on the
|
|
server. Designers can assign a wildlife class, initial count, max active count,
|
|
spawn radius, and respawn interval. Spawn points optionally project to navigation
|
|
before spawning so the first wildlife prototype favors reachable positions while
|
|
still falling back cleanly on maps without complete nav data.
|
|
|
|
### Wildlife Performance Limits
|
|
|
|
MVP wildlife uses simple server-side performance guardrails before the later
|
|
AI-scaling pass. Nearby wildlife updates every tick for responsive flee/chase
|
|
behavior. Wildlife outside `FullUpdateRadius` batches server thinking on
|
|
`FarUpdateIntervalSeconds`, dead wildlife disables ticking, and spawn managers
|
|
enforce `MaxActiveWildlife` so prototype populations cannot grow without a cap.
|
|
|
|
### JSON Metadata
|
|
|
|
Use JSON files for external terrain/tile pipeline metadata while the pipeline is
|
|
still early:
|
|
|
|
- tile registry;
|
|
- terrain generation metadata;
|
|
- heightmap metadata;
|
|
- landform analysis;
|
|
- water/shoreline analysis;
|
|
- neighbor edge verification.
|
|
|
|
JSON metadata should have schemas when it becomes a contract. The tile registry
|
|
already has an MVP schema.
|
|
|
|
### Save Data
|
|
|
|
Save data must be treated as a long-term compatibility contract. Do not store
|
|
temporary prototype assumptions in a way that blocks future migration.
|
|
|
|
Persistence should include version fields for:
|
|
|
|
- save format;
|
|
- game build;
|
|
- tile package version;
|
|
- world state records;
|
|
- player records;
|
|
- placed object records.
|
|
|
|
## Persistence Strategy
|
|
|
|
Persistence should begin narrow and explicit.
|
|
|
|
MVP persistence scope:
|
|
|
|
- player survival snapshot;
|
|
- inventory snapshot;
|
|
- placed campfire/shelter/basic structures;
|
|
- depleted/changed resource nodes where needed;
|
|
- world time/weather state;
|
|
- active Ground Zero tile/package version.
|
|
|
|
Do not persist every temporary actor by default. Actors should opt into
|
|
persistence with a stable identifier and a clear serialization contract.
|
|
|
|
Future persistence design should address:
|
|
|
|
- server database vs file save split;
|
|
- migration/versioning;
|
|
- world partition state;
|
|
- tile package changes;
|
|
- player-owned structures;
|
|
- family/generation data;
|
|
- family and community NPC memory, relationships, teaching history, emotional
|
|
state, task state, and offline stewardship logs;
|
|
- economy and transaction records;
|
|
- settlement governance records.
|
|
|
|
## Family, Community NPC, And Offline Stewardship Intelligence
|
|
|
|
Long-term NPC and family behavior should be built as inspectable simulation
|
|
systems before relying on any generative AI layer.
|
|
|
|
Core rules:
|
|
|
|
- The server remains authoritative for NPC choices, movement, resource use,
|
|
combat, teaching, learning, economy effects, and offline character outcomes.
|
|
- Nearby characters can run fuller behavior/state-tree logic, while distant
|
|
settlement members use cheaper task simulation and ledger updates.
|
|
- Family and community characters need persistent needs, relationships,
|
|
memories, skills, roles, emotional state, task state, and contribution logs.
|
|
- Logged-off player characters may contribute locally from their last valid
|
|
home, claim, or assigned post, but should not explore, learn new skills,
|
|
complete major projects, accept strategic risk, or gain hidden progression.
|
|
- Core behavior must remain deterministic, debuggable, and functional without
|
|
model inference.
|
|
- Any AI model layer should be proprietary-first: local or self-hosted where
|
|
practical, privacy-safe, replaceable, and limited to optional dialogue
|
|
variation, event summarization, teaching flavor, memory compression, and
|
|
settlement reports unless explicitly promoted after review.
|
|
- External AI services must not receive private player history, unreleased world
|
|
state, economy data, or proprietary design context for core gameplay.
|
|
|
|
## Multiplayer Strategy
|
|
|
|
The MVP should prove at least two players on the same server.
|
|
|
|
Near-term rule:
|
|
|
|
- server validates gameplay actions;
|
|
- replicated state is kept minimal;
|
|
- client prediction is deferred unless interaction feels bad without it;
|
|
- RPCs should be narrow and action-specific;
|
|
- avoid letting Blueprint-only paths mutate critical authoritative state.
|
|
|
|
Detailed replication policy belongs in the multiplayer/networking design
|
|
document.
|
|
|
|
## Build And Automation
|
|
|
|
### Windows Editor Build
|
|
|
|
Primary build path:
|
|
|
|
```text
|
|
Scripts\BuildEditor-Windows.bat
|
|
```
|
|
|
|
Codex runs this through Windows-Builder using:
|
|
|
|
```text
|
|
/home/nathan/bin/winbuilder cmd 'set AGRARIAN_NO_PAUSE=1 && pushd \\DevBox\projects\AgrarianGameBulid && Scripts\BuildEditor-Windows.bat'
|
|
```
|
|
|
|
### Unreal Python Verification
|
|
|
|
Command-mode Unreal Python scripts are used for repeatable editor validation:
|
|
|
|
- map checks;
|
|
- Ground Zero terrain verification;
|
|
- playable Blueprint verification;
|
|
- resource and foliage placement checks.
|
|
|
|
These scripts should remain deterministic and safe to run repeatedly.
|
|
|
|
### Packaged Demo Builds
|
|
|
|
Investor/demo packages should be produced when a milestone version's roadmap
|
|
items are complete. The build should use Ground Zero as the default map and
|
|
include current splash/startup/copyright notices.
|
|
|
|
### Linux Dedicated Server
|
|
|
|
Dedicated server build instructions exist, but the MVP can continue proving
|
|
gameplay through the current available server path until dedicated server
|
|
packaging is required for closed testing.
|
|
|
|
## Infrastructure
|
|
|
|
Current supporting machines:
|
|
|
|
- `DevBox` Unraid: shared project storage and VM host.
|
|
- `Ubuntu-Codex`: source-control/automation machine.
|
|
- `Windows-Builder`: Unreal/Visual Studio/GPU build machine.
|
|
- `Agrarian-TileServer`: dedicated Ubuntu VM for MVP tile delivery.
|
|
|
|
Current public tile DNS:
|
|
|
|
```text
|
|
maps.agrariangame.com:18080
|
|
```
|
|
|
|
Infrastructure rules:
|
|
|
|
- do not run project application services directly on the Unraid OS;
|
|
- run services inside VMs or external hosts;
|
|
- keep the tile server small and static for MVP;
|
|
- keep GitHub/LFS usage within free-tier guardrails as long as practical;
|
|
- avoid committing generated build output, local caches, or secrets.
|
|
|
|
## Source Control And Assets
|
|
|
|
The repo uses Git plus Git LFS for Unreal binary assets.
|
|
|
|
Rules:
|
|
|
|
- commit source, config, docs, scripts, and curated assets;
|
|
- do not commit `Binaries/`, `Intermediate/`, `Saved/`, local build artifacts,
|
|
or generated packages;
|
|
- keep large generated terrain packages out of Git unless explicitly curated;
|
|
- prefer small, focused commits tied to roadmap items;
|
|
- do not commit credentials or machine-local configuration.
|
|
|
|
The project currently has unrelated `.uasset` modifications in the working tree
|
|
from prior editor activity. Do not stage those unless intentionally addressing
|
|
that content.
|
|
|
|
## Security And Secrets
|
|
|
|
Secrets must stay out of the repository and handoff files.
|
|
|
|
Examples:
|
|
|
|
- DigitalOcean API tokens;
|
|
- server passwords;
|
|
- Mailgun credentials;
|
|
- database passwords;
|
|
- private SSH keys;
|
|
- admin reset files.
|
|
|
|
Use environment variables, machine-local config, or secret managers for
|
|
credentials. Documentation may describe where a secret is expected, but should
|
|
not include secret values.
|
|
|
|
## Testing Gates
|
|
|
|
Minimum gate for code changes:
|
|
|
|
- relevant C++ compiles through Windows-Builder;
|
|
- relevant Unreal Python verification passes when touching maps/assets;
|
|
- targeted script checks pass when touching scripts/data;
|
|
- docs-only changes receive a text sanity check.
|
|
|
|
Minimum gate for milestone/demo builds:
|
|
|
|
- editor build succeeds;
|
|
- Ground Zero map check passes;
|
|
- playable loop smoke test passes;
|
|
- package launches on Windows test machine;
|
|
- current roadmap milestone is marked complete;
|
|
- known blockers are documented.
|
|
|
|
## Performance Profiling
|
|
|
|
Agrarian gameplay code exposes a dedicated Unreal stat group named
|
|
`STATGROUP_Agrarian`. Use `stat Agrarian` during editor or packaged sessions for
|
|
game-specific cycle counters, and capture Unreal Insights traces for matching
|
|
CPU scopes. The current markers cover authoritative game-state time/weather
|
|
ticking, survival ticking, sky-light refresh, weather-audio refresh, foliage
|
|
instance mutation, and weather-provider request/parse/fallback work.
|
|
|
|
## Near-Term Technical Priorities
|
|
|
|
Next technical foundation work should focus on:
|
|
|
|
- technical details for multiplayer/networking;
|
|
- persistence contract and versioning;
|
|
- Earth-scale tile streaming design;
|
|
- real-weather provider adapter;
|
|
- real-region day/night presentation;
|
|
- local tile cache layout and retention;
|
|
- MVP character-selection landing page;
|
|
- first closed-test readiness gate.
|
|
|
|
## Open Questions
|
|
|
|
- Should public tile serving remain on the LAN-hosted `Agrarian-TileServer` VM
|
|
during closed testing, or move to an external cloud host before testers join?
|
|
- Which persistence backend should replace or supplement file saves first?
|
|
- How much client prediction is needed for gathering, inventory, and building?
|
|
- What is the first stable dedicated server packaging target?
|
|
- Which systems need migration/versioning before the first closed test?
|
|
- How much real sunrise/sunset accuracy is needed before the MVP feels
|
|
regionally grounded?
|