Systemic settlement and gameplay architecture
Shoni Island connects individual villager decisions to a settlement-wide economy. Villagers evaluate hunger, energy, shelter, injury, and social needs alongside assigned professions and player-created work. A UGlobalTaskManager world subsystem indexes tasks by identity, speciality, district, and associated world object; prevents duplicate work; enforces worker capacity; and turns district shortages and construction requirements into actionable AI tasks. Focused controller-owned components execute gathering, farming, construction, crafting, education, healing, fishing, and magic while durable identity and task state remain on the villager.
Code evidence — defensive task creation and indexed lookup:
FGuid UGlobalTaskManager::Internal_AddTask(FTaskData& NewTask)
{
if (!NewTask.TaskID.IsValid() || OutstandingTasks.Contains(NewTask.TaskID))
{
return FGuid();
}
NewTask.MaxWorkers = GetMaxWorkersFromTask(NewTask);
OutstandingTasks.Add(NewTask.TaskID, NewTask);
OutstandingTasksBySkill.FindOrAdd(NewTask.TaskSpeciality).Add(NewTask.TaskID);
OutstandingTasksByTotem.FindOrAdd(NewTask.DistrictTotemID).Add(NewTask.TaskID);
return NewTask.TaskID;
}
Source: Source/ShoniIsland/Framework/Subsystems/GlobalTaskManager.cpp
Evidence status: The task creation and indexing code is shown above. A correlated in-engine log connecting an order to assignment, collection, delivery, and completion remains to be recorded.
Persistent and recoverable world state
The save system reconstructs a live simulation in dependency order instead of treating persistence as a flat actor dump. It first spawns every saved actor so GUID references have valid targets, deserializes non-controller actors, restores framework state and global tasks, and only then restores AI controllers and possession. Conversations, weather, districts, and game-mode state are restored while load duration and unusually large payloads are reported.
Code evidence — explicit restoration stages:
// STEP 1: Spawn all actors so deserialization can resolve actor references.
for (const FActorSaveData& ActorData : AllActorData)
{
AActor* Actor = GetWorld()->SpawnActor<AActor>(
ActorData.ActorClass.LoadSynchronous(), ActorData.Transform, Params);
LoadedActors.Add(ActorData.GameID, Actor);
}
// STEP 2: Deserialize non-controller actors.
// STEP 3: Restore framework, conversations, tasks, game state and weather.
// STEP 4: Deserialize controllers after their referenced actors exist.
Source: Source/ShoniIsland/Framework/Subsystems/SaveLoadManager.cpp
Evidence status: The restoration sequence is shown above. A before/after state comparison is still needed to verify preserved work, inventories, relationships, weather, and construction progress in a recorded run.
Giving life to the world through NPC programming
Villagers possess persistent identity, needs, personality, work, social memory, opinions, and group affiliations. Conversations can concern personality traits, reputation, other villagers, professions, districts, or social groups; repeated encounters can create friendship, rivalry, isolation, competing loyalties, and group fervour.
A data-only Python simulator mirrors key relationship rules and can run 100 villagers over 200 simulated days. Seeded A/B runs vary harmony bias, interaction frequency, extroversion scaling, district structure, thresholds, and affiliation erosion, then measure average opinion, friends, foes, isolation, group membership, topic influence, power, fervour, and personality/outcome correlations. This turns balancing into a measurable study of how small parameter changes reshape a society over time.
Code evidence — long-horizon social metrics:
@dataclass
class DailyMetrics:
day: int
interactions: int
average_opinion: float
average_friends: float
average_foes: float
positive_group_memberships: int
negative_group_memberships: int
isolated_villagers: int
Source: Simulations/RelationshipSim.py
View full resolution ↗
Simulation verification and current parity limitation
View full resolution ↗
Camera control for settlement-scale play
An anchor-based strategy camera combines panning, orbiting, pitch adjustment, zoom, and villager following so players can move between overseeing the settlement and watching individual lives. A blended, head-mounted villager view also lets the player see the world from an NPC’s perspective. Scroll speed scales with zoom distance, while coordinated anchor updates support simultaneous movement, rotation, and zoom. Terrain height is interpolated independently to soften vertical changes; forward traces, sampled arcs around the anchor, district checks, and world bounds constrain camera travel.
The camera also participates in the interaction systems. God-hand movement can trigger edge scrolling or drag the camera, and changes in the camera anchor feed back into hand movement. Scripted location and rotation blends support guided moments before returning control to the player. A dedicated controller-owned component manages these behaviours, applies sensitivity and movement settings, and restores the saved camera transform through the same camera lifecycle.
Code evidence — sampling obstacles along the camera orbit:
void UCameraManager::GetObstacleHitAlongCurve(
const FVector& Anchor, const FVector& ArcDir)
{
ObstacleHit = FHitResult();
float DistTravelled = 0.f;
int32 i = 1;
while (DistTravelled < MAX_SAMPLE_DIST)
{
FVector End = GetCameraLocation() + ArcDir * SAMPLE_DIST_STEP * i;
End = Anchor + (End - Anchor).GetSafeNormal() * GetCameraDistance();
if (GetWorld()->LineTraceSingleByChannel(
ObstacleHit, Anchor, End, ECC_GameTraceChannel13))
{
return;
}
DistTravelled += SAMPLE_DIST_STEP;
i++;
}
}
Source: Source/ShoniIsland/Components/CameraManager.cpp, GetObstacleHitAlongCurve. Excerpt formatting adjusted for readability.
Interconnected weather, audio, and world presentation
Seasons, temperature, rain, snow, wind, time of day, environmental proximity, and live performances feed both gameplay and presentation. A gameplay-facing audio subsystem drives FMOD music and atmosphere parameters for weather, water, forests, dream-world state, and audience size. Parameter interpolation is centralized, and the subsystem only ticks while a transition is active.
Code evidence — event-driven audio interpolation:
void UAudioManager::SetRainActive(bool bIsActive, float LerpTime)
{
SetComponentParameter(
AtmosphereAudioComponent,
ParamRain,
bIsActive ? 1.f : 0.f,
LerpTime);
}
bool UAudioManager::IsTickable() const
{
return ParameterLerps.Num() > 0 && !HasAnyFlags(RF_ClassDefaultObject);
}
Source: Source/ShoniIsland/Framework/Subsystems/AudioManager.cpp
Evidence status: The weather and seasons video complements the FMOD code excerpt. Timestamped FMOD parameter logging remains a separate verification gap.
