Entity Lifecycle
VS entities managed by Heartwood have a well-defined lifecycle driven by the Go server.
UUID tagging
Every Heartwood-managed entity is tagged with a UUID in VS's WatchedAttributes:
entity.WatchedAttributes.SetString("heartwood:uuid", uuid);This UUID is the stable identity across sessions. When a chunk loads and VS scans existing entities, it finds tagged entities and re-registers them with Go. This is how entity identity survives chunk unloads, server restarts, and reconnects.
Spawn suppression
Heartwood intercepts OnTrySpawnEntity and blocks native VS spawning for all registered species. Go is solely responsible for deciding when and where managed species appear.
Materialization flow
Chunk loads
→ C# sends ChunkLoaded(existing VS entities in chunk)
→ Go evaluates: what should be here given current population?
→ Go returns: spawn directives (new entities) + despawn directives (remove old)
→ C# EntityMaterializer creates new VS entities from EcoEntityData
→ C# removes VS entities flagged for despawnSync loop
Every 5 seconds, EntitySyncManager collects all managed VS entity states and sends them to Go via SyncEntities. Go responds with updated spawn/despawn directives. This keeps Go's model current with actual VS positions and health states.
Entity position pattern
From VS 1.22, use entity.Pos (not the deprecated entity.ServerPos):
entity.Pos.SetPosWithDimension(pos);
entity.PositionBeforeFalling.Set(pos);Lifecycle stages
Entities progress through age stages managed by Go:
| Stage | Size | Notes |
|---|---|---|
| Juvenile | 50% | Cannot breed |
| Subadult | 75% | Nearly mature |
| Adult | 100% | Full capability |
| Elder | 95% | Slightly reduced |
Stage transitions are time-based, computed by Go. The C# side receives the current stage and applies a scale modifier to the VS entity.
Death and removal
When Go decides an entity should die (old age, predation, starvation), it sends a despawn directive with reason. C# removes the VS entity and optionally spawns loot drops.
