Urban Vitality series · P1 · Pedestrian Scheduling
Previous article (series overview): Rebuilding a City That Runs Itself in UE5. This article develops the crowd and population systems introduced in that overview.
The subject is how street populations are created, placed, represented, and reclaimed. It covers population orchestration, stable stubs, three runtime cost layers, spawn budgets, and crowd flow on a lane graph. Kinematics, animation, and visual crowd presentation belong to a later article in the presentation half of the series.
Introduction: Crowds Come from Orchestration, Not Independent AI at Scale
An urban crowd cannot be implemented as a large collection of fully autonomous NPCs. If every pedestrian continuously ran a complete perception, decision, and behavior stack, a few hundred visible objects would impose substantial CPU cost.
The reference implementation, from a mature large-scale open-world RPG, places a dedicated population orchestration system between authored community data and runtime NPCs. It coordinates stubs, spawn services, representation tiers, budgets, lane topology, persistence, and cross-system events. Pedestrians do not independently decide to appear. Population demand is evaluated around the player and resolved through several runtime layers.
This article examines the relationship between stubs and Actor representations, the distant visual layer, asynchronous spawn queues, Actor attachment budgets, lane-based crowd flow, failure cleanup, and persistence. It then derives a data-oriented population runtime for UE5.8. Mass can support selected layers, but it is not an architectural prerequisite.
Population spawning crosses several stages and asynchronous tokens. A request can fail, be canceled, or time out. Acceptance means that work entered the scheduling pipeline; it does not mean that an entity is ready. The spawn, attachment, and reclamation paths below all rely on this distinction.
Terminology and Evidence Levels
| Term | Meaning |
|---|---|
| Stub | Lightweight identity data with a stable entity ID; not an Actor |
| Representation | The runtime form currently used for an identity |
| Actor representation | An Actor attached to a stub; components can be filtered for crowd, simple, or occupant tiers |
| Distant dot | Anonymous visual data with no stable identity |
| Attach / dispose | Acquire or release an Actor representation for a stub |
| Representation handoff | Coordination between representation layers; it does not imply that identity crosses a distant dot boundary |
| Asynchronous token | A receipt used to track cross-frame request state and cancellation |
| Work-point | A behavior anchor associated with a lane or scene location |
The article uses three evidence levels. “The code directly shows” refers to observable source behavior. “The call relationships support this abstraction” marks a responsibility model inferred from structure. “The proposed UE5.8 design” identifies migration guidance. These levels are kept separate.
1. Stub-First: Identity Precedes Actor Representation
① Source Observation and Responsibility Model
The population runtime is built around a stub-first model. The first form of a person inside the stable identity system is a stub, not an Actor representation. A stub stores a stable entity ID, transform, and required state, but none of the full Actor component stack for AI, animation, physics, or perception. Anonymous distant dots remain outside this identity system.
Attaching or disposing an Actor representation does not change the stub identity. A stub can acquire AI, animation, and interaction through an attached Actor, then release that representation when those capabilities are no longer required. Quest, save, and relationship systems can therefore refer to a stable identity without binding themselves to a transient Actor. A large world commonly uses several identifiers—population IDs, persistent IDs, and runtime representation handles. “Identity” here means the stable association layer exposed to higher-level systems, not one universal ID shared by every subsystem.
A dedicated stub controller owns the runtime collection. The code shows that it stores raw stub pointers and removes those references through deletion callbacks under a lock. This avoids reference-counting overhead, although the available source is insufficient to prove that performance was the sole reason for using raw pointers. What can be established is that a destruction path that bypasses the callback can leave a dangling pointer.
Raw Pointers, Deletion Callbacks, and Lifetime Constraints
The source combines raw pointers with deletion callbacks. When a stub is destroyed, the callback clears references held by the controller while the relevant data is locked. The design centralizes safety in the deletion path; any destruction route that skips that path can invalidate the collection.
A plain struct or SOA stub cannot use TWeakObjectPtr in UE. A safer starting point is an index/handle with a generation counter. Dereferencing checks both the slot and its generation, preventing a recycled slot from being mistaken for its previous occupant. TWeakObjectPtr remains appropriate for UObject or Actor representations. During concurrent deletion, the locked region should mark entries, remove them from collections, and collect pending notifications. External callbacks should normally run after the lock is released. Calling them under the lock is defensible only when non-reentrancy has been demonstrated.
Tokens, Pending Tables, and Validation After Asynchronous Creation
Stub creation uses asynchronous tokens rather than synchronous construction. A request obtains a token and enters a pending-creation table before the stub exists. When creation completes, the callback checks the token state before accepting the stub into the container. The container itself does not repeat rejection logic; validation occurs earlier in the path.
Failure handling is complicated by changing dependencies. Pending data stores a weak pointer to the traffic slot because that slot may be removed while the stub is being created. Completion must therefore validate the dependencies again. Even if stub construction succeeded, an invalid destination slot causes the new stub to be discarded, the slot to be reclaimed, and the work-point token to be cleared. Slot requests also use a fixed retry limit per frame so that a large set of failures cannot consume the entire frame budget.
② Implications for UE5.8
Actors, Mass, and ISM provide object lifetimes, batch processing, and instance rendering, respectively. They do not supply the combined semantics of stable identity, tiered representation, budgeted asynchronous attachment, and recoverable handoff. The proposed design places stable identity in an independent stub layer and attaches representations on demand. Whether Mass carries some of the data depends on the engine version, expected scale, and the project’s existing pipeline.
③ Porting the Model to UE5.8
// Responsibility-level architecture pseudocode.
// It is not a complete, compilable, or uniquely correct UE5 API design.
struct FPopulationStub
{
FPopulationEntityId Id;
FTransform Transform;
FPopulationPersistentState State;
FRepresentationHandle CurrentRepresentation;
};
// UPopulationRuntimeSubsystem owns the stub pool.
// Stub references use generation-checked data handles.
// Actor representations may use TWeakObjectPtr.
Migration rule: decouple stub identity from Actor representation. Actor representations can be attached and disposed repeatedly while the stub ID remains stable. The stub pool owns its own lifetime. Avoid a single-layer model in which spawning creates the complete identity and representation at once.
2. Three Runtime Cost Layers: Actor Representation, Stub, and Distant Dot
① Source Observation and Responsibility Model
Population runtime cost is divided by distance, importance, and semantic requirement:
- Actor representation: an Actor attached to a stub when needed. Actor configurations can include full, crowd, simple, and occupant tiers. Nearby interactive configurations carry the highest cost.
- Stub: lightweight data containing a stable entity ID, transform, and required state. It owns no Actor component stack. Actor representations can be attached and disposed while the stub identity remains unchanged.
- Distant dot: anonymous visual data interpolated along preprocessed lanes and rendered in batches. It has no entity ID, does not participate in interaction, and is not guaranteed to represent the same person as a stub created later.
Coordination across these layers is a representation and density transition, not a necessary identity chain from dot to Actor. The code directly shows that a stub leaving range can request a replacement distant dot near its lane position. In the opposite direction, the system creates population stubs from regional density demand as the player approaches. The layers maintain visual continuity, but the available evidence does not establish a one-to-one identity transfer between a dot and a stub.
Pedestrians and traffic both assign runtime cost according to distance and interaction demand. Their tiers, slots, and transition rules remain independently defined.

Sequence Walkthrough: From Anonymous Density to an Identified Representation
- The farthest layer maintains anonymous distant dots.
- As the player approaches, regional population demand creates stubs with stable IDs while preventing overlap with the distant layer.
- When budget permits, a stub attaches an appropriate Actor representation tier.
- Interaction state is written to the stub or its persistent data.
- When the player leaves, the Actor representation is disposed; identity can remain in the stub layer.
- If the stub later leaves range and is reclaimed, the system can request a new anonymous distant dot near the lane to maintain density.
Stable identity spans the stub and its attached representation. It does not extend into the distant dots before or after that interval.
Promotion Uses Importance Ranking, Not a Single Distance Threshold
Promotion is not triggered by distance or elapsed time alone. Candidate objects participate in a multi-factor importance score, and the highest-ranked candidates receive the limited set of full-representation slots. The code structure exposes the following dimensions; their exact weights and composition remain configuration-dependent:
- Identity priority: story, quest, community, and background populations begin from different priorities.
- Type weight: object type contributes to the score; relative ordering must be verified against configuration and callers.
- Distance and height difference: horizontal distance and vertical separation affect candidate priority.
- Visibility and areas of interest: the view and points of interest can raise a candidate’s priority; exact increments remain configurable.
Population scheduling evaluates candidates and attempts attachment within the available slots. Type, distance, height, visibility, and area-of-interest factors are observable in the source. Exact update cadence, weight ordering, and combination rules require configuration-level verification.
Component Filtering Belongs to Actor Representations
LOD-based component filtering applies to the Actor representation, not to the stub. The source configures separate component filters for crowd, simple, and occupant Actor tiers. The crowd tier excludes categories such as status effects, squad membership, visual perception, dismemberment, projectile spawning, and object carrying. Simple and occupant configurations remove additional capabilities.
Component types are initialized once and cached as type pointers, avoiding repeated string matching at runtime. The stub remains a data-only identity object; component filtering is strictly a representation concern.
② Implications for UE5.8
UE5.8 does not provide this complete population model as one system. Whether MassCrowd can carry part of it depends on the engine version and the project’s Mass pipeline. The migration design still needs three separate objects: anonymous distant dots, identity-bearing stubs, and Actor representations configured as full, crowd, simple, or occupant tiers.
UE already provides mature facilities at the representation and batch-processing layers. ISM/HISM can render large distant sets; Mass fragments and processors can batch data; Smart Objects can host interaction anchors; and the Animation Budget Allocator can constrain animation cost. The missing layer is the orchestration semantics that combine anonymous distant density, stable stub identity, tiered Actor representation, and budgeted attachment.
③ Porting the Model to UE5.8
enum class ECrowdRepresentationTier : uint8
{
FullActor,
CrowdActor,
SimpleActor,
OccupantActor,
DistantDot
};
// Stub: independent identity data, not an Actor tier in this enum.
// DistantDot: anonymous visual data; density is coordinated with stubs,
// but identity continuity is not implied.
Migration rule: distant dots, stubs, and Actor representations provide visual density, stable identity, and interaction capability, respectively. Component filtering belongs only to Actor representations. Stable identity begins at the stub.
3. Population Orchestration: From Community Data to Runtime Crowds
① Source Observation and Responsibility Model
Ordinary crowd demand begins with authored community data, which describes population types, density, and schedules for an area. At runtime, the orchestration layer converts that static data into a dynamic population. Player position, time, and density parameters determine spawn locations, population types, and representation cost.
The core of community data is a schedule. A community is divided into spawn phases, each associated with a time period and a quantity, a set of markings or spot nodes, and an optional sequence rule. Morning commuters, low-density late-night streets, and midday commercial crowds are driven by separate schedule phases rather than hard-coded condition branches.
The orchestration layer connects community data, stubs, runtime spawning, traffic lanes, distant rendering, response-unit demand, persistence, and cross-system events. It creates and coordinates population demand but does not construct Actors directly. Once type and quantity have been resolved, each entity still passes through the asynchronous spawn path.

The Responsibility Boundary of prevention
The internal name prevention can be misread as suppression of population spawning. The code directly exposes requests to spawn units by level, cancel batches by level, and query current spawn counts. Based on these interfaces and their call relationships, this article provisionally models it as a wanted or hostile-response spawn coordinator. Whether it owns the complete wanted-state machine remains unverified and requires examination of higher-level callers.
The same source class also owns a corpse counter and submits reclamation requests according to distance, visibility, and quantity thresholds. That ownership is directly observable, but it does not require the migration design to merge response spawning and global corpse cleanup into one business subsystem. Both can use the same population-runtime spawn and cleanup interfaces.
Response-unit demand differs from ordinary community-density demand. Corpse reclamation resides in the same source class but still enters the shared population cleanup pipeline.
Three Cleanup Ranges, Resource-Pressure Deletion, and Delayed ID Reuse
Corpse cleanup runs at a lower frequency rather than every frame. The system gathers dead bodies and divides them into three groups using squared distance to the player:
- Outer range: beyond the off-screen removal distance, force deletion immediately.
- Middle range: request soft deletion through the normal eligibility checks.
- Near range: keep the objects and record the farthest visible and non-visible candidates for resource-pressure handling.
A separate resource-pressure path activates when the corpse count exceeds an immediate-removal threshold, the total entity count reaches its limit, and normal cleanup removed nothing. It first force-deletes the farthest off-screen body. If no off-screen candidate exists, it uses the farthest visible candidate. Visibility constraints govern normal behavior and are crossed only after the pressure threshold is reached.
After deletion, an entity ID is inserted at one end of the ID pool while allocation pops from the other. This deque policy increases the interval before a released ID can be assigned again and reduces the risk that an obsolete script reference is confused with a new identity.
Schedule Transitions and Callback Registration
A time-period scheduler applies community schedules. When a new period set is installed, the system unregisters the previous callback, updates the schedule, applies the current game time immediately, and then registers a new callback. A single-period schedule selects that period directly. A multi-period schedule searches backward for the first entry whose start hour is no later than the current hour. If none matches, it wraps to the final period to cover intervals across midnight.
Only multi-period communities register a time callback. A community with one fixed period has no reason to listen for time changes. The callback also deduplicates by frame number to avoid processing the same transition more than once in a frame.
Completion Notifications for Spawn and Reclamation
The source exposes entity-spawner broadcasters and completion callbacks that pass selected results downstream without requiring every consumer to poll population state.
It also indicates that a broadcaster in the attachment path can run before all downstream side effects have completed. The event must therefore not be generalized as “everything is fully ready.” At minimum, completion semantics need to distinguish Actor attached from ready for gameplay.
② Implications for UE5.8
UE5.8 does not provide a complete path from community data to an orchestrated runtime crowd. The reference implementation converts population quantity, location, and type from hard-coded conditions into data-driven orchestration. Content authors define communities; the orchestration layer resolves them against player position and runtime rules. The migration therefore requires a dedicated coordination layer.
③ Porting the Model to UE5.8
// Population orchestration bridges community data, stubs, spawning,
// lanes, persistence, distant rendering, and events.
// Use explicit world phases rather than one monolithic Actor Tick.
class UPopulationRuntimeSubsystem : public UWorldSubsystem
{
void TickPopulationPhase(float Dt); // Evaluate demand and representation priority.
void TickSpawnPhase(float Dt); // Drain and throttle asynchronous requests.
void TickDespawnPhase(float Dt); // Deferred deletion, orphan storage, batch cleanup.
// Inputs: schedule phases, player position, time, and density.
// Response-unit demand remains separate from ordinary community demand.
};
Migration rule: orchestration coordinates rather than constructs entities. Community schedules drive ordinary population. Response units form a separate demand source. Completion notifications distinguish an attached Actor from gameplay-ready state.
4. Spawning Is a Request Queue, Not an Immediate Call
① Source Observation and Responsibility Model
The population system defines spawn a person as an asynchronous request. Interfaces that add entities, request spawning, or enable and disable crowds report acceptance or queueing; they do not report that an entity is visible.
A spawn crosses stub-creation token → population registration queue → entity-spawn token → attachment scheduling. Every stage can wait across frames, fail, or be canceled. When the initial request returns, the Actor representation generally does not exist. Logic that requires an interactive entity must wait for a later completion state.
The staging follows from streaming and budget constraints. The requested location may not be streamed in, the current frame’s spawn allowance may be exhausted, or attachment may be waiting for the entity-spawn service. Synchronous creation would concentrate Actor construction cost and would provide no safe queueing boundary when dependencies are unavailable.
A Four-Stage Model for Explaining Asynchronous Boundaries
The source does not contain one structure named “four tokens.” The asynchronous states and receipts along the spawn path can nevertheless be summarized as four stages. This is an explanatory model for boundaries and interruption points, not a claim about an identically named source architecture:
- Stub-creation token: the request first creates a stub. It waits if the destination has not streamed in and fails if the location is invalid.
- Population registration queue: the completed stub enters an ordered population table. Registration is queued and committed during the population system’s next processing pass.
- Entity-spawn token: the registered stub requests an Actor representation. Actor construction remains constrained by entity budgets and waits when the budget is full.
- Attachment scheduling: the completed entity attaches to the stub, configures components, AI, and animation, and restores persistent state. This work can span frames. The object becomes interactive only after the required completion level is reached.
Streaming, processing cadence, budgets, and cross-frame execution can delay any stage. Invalid positions and cancellation can terminate it. The system therefore exposes graded states such as Queued, StubCreated, ActorSpawning, ActorAttached, Failed, and TimedOut. Reducing the chain to one success/failure Boolean discards essential pending, cancellation, and timeout states.

② Implications for UE5.8
SpawnActor and deferred spawning can construct an Actor, but they do not provide a cross-frame, cancelable population request constrained by streaming and budgets with multiple completion levels. A population orchestration layer must wrap the final Actor construction step.
Calling SpawnActor when demand is created and immediately consuming its return value concentrates construction work in one frame, ignores unresolved streaming dependencies, and bypasses population budgets. It is better used as the final construction stage after queueing, throttling, streaming validation, budget checks, and state management.
③ Porting the Model to UE5.8
// Explicitly model asynchronous boundaries observed across source paths.
// This does not claim to reproduce an identically named state machine.
FPopulationSpawnHandle UPopulationRuntimeSubsystem::RequestSpawn(
const FPopulationSpawnDesc& Desc);
// The return value is a handle (accepted), not an Actor (complete).
enum class EPopulationSpawnStatus : uint8
{
Queued, StubCreated, ActorSpawning, ActorAttached, ReadyForGameplay,
Failed, Canceled, TimedOut
};
// Consumers wait for the completion level they require.
Migration rule: return a request handle rather than an Actor. Completion crosses multiple tokens and stages. Logic that requires entity presence waits for the attachment or gameplay-ready callback.
Spawn Throttling and Request Cancellation
The spawn queue applies two scheduling constraints. First, a hard per-frame cap allows only a fixed number of stubs to enter actual creation. Requests generated during a region transition are distributed across several frames instead of concentrating stub construction and Actor attachment.
Second, spawn and delete requests can cancel each other. Before processing deletion, the system checks whether the target remains in the spawn queue. If it has not been created, spawning is canceled and the ID is returned instead of constructing an object only to delete it. New spawn demand can also defer existing pending deletions.
The ID pool uses the same two-ended policy described earlier: allocation pops from one end and reclamation inserts at the other, increasing the delay before a recently released ID can be assigned again.
5. Spawn Budgets: Conditions for Attaching Actor Representations
① Source Observation and Responsibility Model
Of the three cost layers, a fully interactive Actor representation is the most expensive. An independent budget limits the number of high-cost representations that can be attached at once. Requests beyond the attachment budget wait until another representation is disposed and releases a slot.
The budget limits the frame cost of population simulation. Distant dots consume instance-pool, update, and rendering budgets. Stubs consume data-pool capacity. Actor representations consume the more expensive attachment and simulation budget. As the player’s view changes, low-priority representations release high-cost slots and higher-priority candidates acquire them.
The stub pool has a separate budget from Actor attachment. A large set of identities can remain in the lower-cost stub layer while only candidates likely to interact compete for high-cost Actor representations.

② Implications for UE5.8
UE5.8 does not provide the combined population semantics of an Actor attachment budget and an independent stub pool. Layered budgets cap expensive simulation so that Actor count does not grow with an area’s authored target population.
Two Entity Budgets, Quality Settings, and Unattached Staging
The two entity budgets in the source can be described as attached and unattached budgets, each with current usage and a limit. Limits come from a quality-tier configuration table, allowing the number of expensive representations to scale by performance setting.
The spawn algorithm sorts its queue by importance and attempts to place each candidate in the attached budget. When that budget is full, the object is not immediately discarded. It moves into the unattached budget as an already constructed entity waiting for attachment. It can proceed when an attached slot becomes available. A genuine creation failure, such as an invalid position, is canceled and removed rather than retried without limit.
The migration design should therefore expose a configurable two-level structure. Attached entities carry full simulation cost; unattached entities preserve constructed objects awaiting attachment; actual spawn failures terminate the request.
③ Porting the Model to UE5.8
// Actor attachment/simulation budget: high-cost slots, scaled by quality and runtime pressure.
// Stub budget: data-pool capacity and update cost.
// Distant-dot budget: instance-pool capacity, update batches, and rendering cost.
// As the player moves, high-cost slots are reassigned among candidates.
Migration rule: distant dots do not consume full-entity attachment slots, but they still consume instance, update, and rendering resources. High-cost slots must remain bounded and adjustable by quality level, platform, and runtime pressure.
6. Crowds and Lane Topology: Shared Spatial Data, Separate Semantics
① Source Observation and Responsibility Model
Crowds also use traffic-lane infrastructure. The source shows pedestrian systems listening to lane events, measuring density by lane fragment, and coordinating movement through traffic slots and work-points. These calls establish shared lane-graph data and selected coordination mechanisms. They do not prove that pedestrians and vehicles use identical slots, occupancy semantics, or spatial indices.
A pedestrian/vehicle coordinator receives lane events and uses traffic-slot mechanisms. Work-points provide spatial anchors for waiting, browsing a storefront, crossing a road, and similar behaviors. Population spawning can place pedestrians at those anchors.
Lane-event handling also follows the staged model. Except for monitor state, a lane-closure event does not immediately delete pedestrian objects. Dead-end and congestion cleanup is deferred to the deletion phase for batch processing.
Lane-Segment Density Drives Both Spawn and Deletion
The system maintains a density ledger for each lane segment. Every lane is divided into fragments that record the difference between target and actual population. A positive difference submits spawn requests; a negative difference initiates deletion. Deletion candidates are ranked by excess so that the fragments furthest above target are reduced first.
Spawn and deletion use the same density target, preventing independent rules from working against one another. Community data supplies the target and schedule changes propagate it to lane fragments. The difference between target and actual values drives both directions.

Assigning Distant Crowd Points to Lanes
A dedicated distant-crowd lane finder selects movement routes for anonymous points. It searches near each position for an appropriate pedestrian lane and creates the binding, preventing distant crowds from drifting outside walkable space or onto vehicle lanes.
Vehicle spawning and distant-crowd placement are both lane-space queries, but they use different filters and occupancy semantics. The available source does not confirm that both share the same BVH instance.
Work-points are assigned at this stage as well. Once associated with a pedestrian lane, a person can visit a nearby waiting, storefront, or crossing anchor, perform the related behavior, and continue moving. The result is more varied than indefinite constant-speed loops along the sidewalk.
② Implications for UE5.8
Available crowd and traffic facilities vary by UE version and plugin set. A reconstruction can share road and sidewalk topology and a common spatial coordinate basis, then define query filters and occupancy rules per object type. This provides a consistent foundation for crossing, yielding, and density coordination without forcing identical runtime semantics.
③ Porting the Model to UE5.8
// Use one lane-topology foundation with type-specific filters and occupancy semantics.
// Sidewalks form one class of edge in the graph.
// Pedestrians, vehicles, and distant dots use different query strategies.
// UPopulationTrafficCoordinator handles lane events, pedestrian slots, and work-points.
// Lane blockage: preserve monitor state and defer dead-end cleanup to the deletion phase.
Migration rule: crowds and vehicles share core lane-topology data, not necessarily the same slots or occupancy rules. Work-points anchor pedestrian behavior. Cleanup caused by lane closure is deferred and processed in the deletion phase.
7. Cleanup: Stalls, Range Exit, and Spawn Failure
① Source Observation and Responsibility Model
Population objects are continuously created and reclaimed. The reference design sends the following cases to one deletion phase instead of destroying objects from arbitrary call sites:
- Out of range: the object leaves the active area around the player.
- Stuck: geometry or traffic state prevents sustained movement.
- Spawn error: a position or dependency is invalid, or creation fails to complete.
- Lane dead end or congestion: the current lane no longer provides a valid path.
All deletion passes through a common callback. Because the stub controller stores raw pointers, marking, removal, and notification collection for the relevant sets must be protected by a lock. External notifications should run after unlocking to avoid deadlock through callback re-entry. Centralized batch processing also prevents iterator invalidation and data races caused by modifying population collections while they are being traversed.
Fade-Out, FIFO Ordering, and Pre-Deletion Demotion
Most stubs enter a deferred deleter after they become eligible for removal. The system marks the stub as non-persistent, lowers it to crowd priority, starts a fade, and appends it with a timestamp to a FIFO queue. Actual deletion occurs only when the object at the head has satisfied the fade duration.
Pre-deletion demotion prevents the fading object from re-entering importance competition and being promoted again. FIFO ordering makes reclamation order predictable. Only off-screen objects that are no longer required can bypass the fade and be deleted synchronously.
Deletion has multiple entry points and a single exit. Reaching a destination, traffic blockage, death, range exit, and lane overpopulation all converge on one function. That function transfers the stub to an orphan container, removes its traffic slot, and updates range counters. Each entry point retains its own visibility, distance, and timing conditions. A blocked object is removed only when it is sufficiently far away and outside the view. An out-of-range object requests a distant-dot substitute before removal. Lane-overpopulation cleanup avoids objects that were visible very recently.
The Orphan Container as a Retirement State
Removing a stub from the active collection does not destroy it immediately. The stub first enters an orphan container sorted by entity ID. Insertion uses lower_bound, preserving logarithmic ID lookup. An event-bridge object is created when the stub enters and destroyed with it at final deletion, allowing scripts to receive necessary retirement events.
After active-set removal, the system must still complete the fade, issue notifications, and reach a safe destruction point. The deferred deleter provides timing; the orphan container provides ordered storage and event bridging. Together they represent the object’s retirement state.

② Implications for UE5.8
UE Actor destruction does not automatically resolve cross-system population references, visual fade-out, or safe batch-mutation boundaries. A reconstruction still needs an explicit deletion phase: change ownership and indices under a lock, then issue potentially re-entrant notifications after unlocking.
③ Porting the Model to UE5.8
enum class EPopulationDespawnReason : uint8
{
OutOfRange, Stuck, SpawnError, LaneDeadEnd
};
// Gather stubs → mark/remove/collect notifications under lock → unlock → callbacks.
// Do not mutate the population collection concurrently with traversal.
Migration rule: multiple reclamation reasons converge on one deletion phase. The locked region handles ownership, indices, and notification lists. External callbacks run outside the lock by default. Collections are not modified concurrently with traversal.
8. Distant Crowds: Visual Data Is Not an Interactive Entity
① Source Observation and Responsibility Model
The farthest population layer is the distant crowd. It consists of points interpolated along lanes and rendered through GPU instancing. These points provide visual data, not complete population entities.
A distant plaza can look populated even though the logic layer contains no individual NPC decision loops. It contains route-following points updated and rendered in batches. As the player approaches, the system reduces or reallocates those points and separately creates population stubs from regional demand. This preserves visual continuity without promising one-to-one identity continuity.
Conditions for Reallocating Distant Dots
A distant dot updates every frame and is reallocated when its lane index becomes invalid, it moves too far from the player, it remains stationary for several consecutive frames, the lane needs fewer dots, or it enters the range assigned to ordinary crowds. A dot near that boundary can also be reallocated while inside the player’s view frustum, preventing anonymous visual data from overlapping newly created entity representations. The system performs a bounded number of attempts, selects a lane by weighted probability, and resets speed, position, and stationary-frame count.
The stationary counter preserves continuous flow in the distant layer. Distant dots do not solve real congestion. After remaining still, they are relocated. Nearby entities use the formal blockage and cleanup paths instead. The strategies differ because the distant layer is responsible only for aggregate motion.
During initialization, lanes are preprocessed into straight chains whose in-degree and out-degree do not exceed one. Dots interpolate along these chains. Construction includes cycle detection; a looped chain is marked invalid and retains debug information. Straight chains remove runtime pathfinding and intersection decisions and provide only continuous movement.

② Implications for UE5.8
ISM/HISM already renders large instance sets efficiently. The additional requirement is a semantic boundary between distant visual data and interactive representations. An ISM instance does not carry stable identity or complete interaction logic.
The model of a constant straight chain with reallocation after a stall performs no pathfinding, decision-making, or avoidance. It interpolates along preprocessed routes. Even inexpensive per-object AI becomes significant when multiplied by thousands of distant points. The distant layer should therefore produce continuous pedestrian or traffic flow only. Separately created nearby stubs and Actor representations handle individual destinations and obstacle avoidance.
③ Porting the Model to UE5.8
// Distant crowd = visual data rendered in ISM batches, not entities.
// Lane-interpolated points → UInstancedStaticMeshComponent batch rendering.
// Visual data being valid does not imply an interactive person exists there.
// Coordinate regional density and create separate stubs as the player approaches.
Migration rule: the distant crowd is visual data rather than an entity representation. ISM handles batch drawing; the logic layer provides neither stable identity nor interaction capability for each point.
9. Persistence: Preserve Only Identities and State That Must Continue
① Source Observation and Responsibility Model
Population runtime must support saves and streaming restoration, but persistence does not cover every background pedestrian. For objects that need continuity, the save records the stub’s entity ID and required persistent state. Actor representations are reconstructed on demand.
Quest-related identities, persistent markers, and state produced by important player interactions can survive streaming and loading. Pure background population is reclaimed and regenerated rather than carrying per-person memory.
Symmetry Between Creation and Restoration
Stub construction has new and restore modes. The new path enables persistence, creates persistent state for base data, and then creates component state. The restore path skips initial setup, accesses existing persistent state, and notifies components that restoration occurred. Their preconditions are opposite: component state must not exist before new creation, and it must exist before restoration. Violations trigger assertions.
The destructor adds another symmetry constraint. When a stub is destroyed, it asserts that base-data persistent state has already been cleared. A stub must pass through the formal deletion process, which handles persistent state before destruction. A direct delete exposes the bypass through the assertion.
Persistence faults often appear only after a save-and-load cycle. Symmetric creation and restoration, state-existence checks, and destructor assertions move those failures closer to the first inconsistent transition.
Saveable and Non-Saveable IDs
Entity IDs are divided into saveable and non-saveable categories. Story or quest NPCs, identities with persistent markers, and characters affected by important player interactions use saveable IDs. Regenerable background population uses non-saveable IDs and does not retain individual state after reclamation.
The distinction controls save size and I/O cost. Persisting thousands of background stubs would enlarge save files and restoration work without adding meaningful continuity. Saveability should therefore be decided as part of the stub design.

② Implications for UE5.8
UE provides a basic save framework, but the semantics of stub-layer persistence with representation reconstruction still need to be designed. Saving only required stable state avoids serializing large numbers of transient Actors and reduces both file size and restoration complexity.
③ Porting the Model to UE5.8
// Persist population identity and required state, not transient Actor representations.
// Save data = EntityId + FPopulationPersistentState.
// Streaming and load restore the stub; the Actor representation is rebuilt on demand.
// Pure background population remains regenerable.
Migration rule: save stub identity and persistent state, then reconstruct representations when required. The same principle applies to per-vehicle persistence.
Appendix: Identity and Representation Lifecycle for a Regional Population Entity
The source paths can be summarized in six transitions:
- Regional demand: community schedules and lane density determine the required population quantity and type.
- Asynchronous identity creation: a request is queued and receives an entity ID; completion validates the slot, lane, and streaming dependencies again.
- Representation-slot competition: scheduling evaluates multiple importance factors and selects attachment candidates within the high-cost representation budget.
- Attachment and gameplay: the stub receives an appropriate Actor representation. If the identity is persistent, interaction results are written to stable state.
- Disposal or retirement: the Actor representation is released as the player leaves. Stubs that are no longer required enter the unified reclamation path.
- Return to anonymous density: an out-of-range stub can request a replacement distant dot, but that dot does not inherit the stub’s identity. Dead objects follow corpse-cleanup rules, and their IDs are reused only after a delay.
Stable identity begins at the stub. Distant dots provide visual density before and after the identified interval but do not participate in the individual identity lifecycle.

10. Runtime Constraints: Lifetime and Concurrency Boundaries
The mechanisms above produce several cross-module constraints:
- Revalidate cross-frame dependencies: when a token completes, check the slot, lane, streamed region, and cancellation state again.
- Data handles must detect reuse: struct-based stubs use an index plus generation; only UObject or Actor representations use UObject weak references.
- Locks protect critical data only: mark, remove, and collect notifications under the lock; execute potentially re-entrant callbacks after unlocking.
- Reclamation has one controlled exit: visibility, fade-out, orphan storage, and final destruction occur in explicit phases.
- Budgets are measured separately: dots, stubs, and Actor representations each have capacity and update cost; high-cost slots scale with configuration and runtime pressure.
- Persistence paths remain symmetric: creation, restoration, and deletion validate state existence and save only identities that require continuity.
Streaming and parallel execution change references and preconditions over time. Lifetime design must distinguish the state that is valid now from the state that was valid when a request began.
11. Migration Trade-Offs: A Data-Oriented Population Runtime
The proposed migration uses a data-oriented population runtime. Mass is an optional batch-processing carrier, not the architectural premise.
| Mechanism | Adopted design | Rejected design | Reason |
|---|---|---|---|
| Identity | Stub ID and persistent state independent of Actor representation | Spawning immediately creates the complete Actor and identity | Decouple identity from representation |
| Layering | Anonymous dots, stubs, and tiered Actor representations | Treat all three as one object | Separate cost and semantics |
| Orchestration | Community population and response units are separate demand sources | Infer responsibility from an internal name alone | Data-driven and verifiable boundaries |
| Spawning | Cancelable asynchronous chain with graded completion | Treat request return as completion | Supports streaming and budgets |
| Budgets | Measure dots, stubs, and Actors separately | Set only one full-entity count | Constrain distinct cost sources |
| Placement | Shared lane topology with type-specific queries and occupancy | Assume all slot semantics are identical | Common spatial foundation |
| Cleanup | Multiple causes converge on a batched deletion phase | Delete from arbitrary call sites | Avoid concurrent collection mutation |
| Distant crowd | ISM visual data, not entities | Assign identities to distant dots | Visual presence is not entity existence |
| Persistence | Save important, interacted-with, or explicitly persistent identities | Save every background pedestrian or transient Actor | Control save size |
| Runtime carrier | Data-oriented core with optional Mass and ISM facilities | Declare Mass mandatory or forbidden in advance | Select by engine version and project pipeline |
The reconstruction should first implement the population semantic layer: stable identity, asynchronous state, budget slots, and recoverable transitions. Low-level updates can run in SOA, Mass, or a hybrid design, while distant rendering can use ISM/HISM. The choice depends on the engine version, existing pipeline, and profiling. Mass provides ECS and batch-processing facilities, but not the population-lifecycle semantics defined in this article.

AI Collaboration Retrospective
- AI contribution: organized source paths, cross-checked population, distant-crowd, and spawning modules, and converted the mechanisms into a readable responsibility model.
- Human verification: confirmed that distant dots carry no entity IDs, corrected the earlier model that extended identity through dots, separated stubs from tiered Actor representations, and preserved evidence boundaries around
preventionand completion events. - Verification method: traced critical conclusions back to the population-module source; UE5 sections are explicitly presented as migration guidance.
- Evidence boundary: source facts, responsibility abstractions, and migration proposals are labeled separately. An explanatory model is not presented as an identically named source architecture.
- Article boundary: this article covers the core logic of population scheduling and UE5 migration principles. Kinematics, animation, and visual crowd effects belong to the presentation half of the Urban Vitality series.