Framework Utility Infrastructure
The SDG.Framework namespace contains the engine-level utility infrastructure that supports both the game runtime and the editor. The system comprises object pooling (Pool, PoolablePool, ListPool), math utilities (MathUtility), physics helpers (PhysicsUtility), a formatted IO serialization framework (IO.FormattedFiles), a debug gizmo system (RuntimeGizmos), extension methods for Unity types, foliage and landscape systems, and water volume management.
This article documents the pool system (the most performance-critical utility), the math and physics utility classes, the formatted file serialization architecture, and the runtime gizmo system. These utilities are used pervasively across the entire codebase and understanding them is necessary for reading any framework-level code.
Source code location: Framework/Utilities/*, Framework/Extensions/*, Framework/Debug/*, Framework/IO/*
The Pool System
Unturned has three levels of object pooling to reduce garbage collection pressure:
Pool<T>
The generic Pool<T> class is the most flexible pool type. It stores inactive instances of any type and provides claim() / release() semantics:
csharp
public class Pool<T> where T : class
{
public T claim();
public void release(T item);
}The pool stores released items in an internal stack (LIFO order). When claim() is called, it either returns the most recently released item or creates a new instance via the default constructor. This is the standard "rent-and-return" pattern used for frequently-created temporary objects.
IPoolable Interface
The IPoolable interface defines the lifecycle callbacks that pooled objects can implement:
csharp
public interface IPoolable
{
void PoolClaim(); // Called when claimed from pool
void PoolRelease(); // Called when returned to pool
}Objects that implement IPoolable are automatically reset to their default state when released, clearing any references that could cause memory leaks.
PoolablePool<T>
The PoolablePool<T> class is a specialized pool for objects that implement IPoolable. When an item is released, it automatically calls PoolRelease() on the item before storing it. When claimed, it calls PoolClaim() after retrieval.
ListPool<T>
The ListPool<T> class provides a static pair of claim/release methods specifically for List<T> objects:
csharp
public static class ListPool<T>
{
public static List<T> claim();
public static void release(List<T> list);
}This is the most frequently used pool in the codebase. Lists are created and discarded constantly during gameplay operations — searching for nearby entities, collecting query results, iterating spawn tables, building asset lists. Without pooling, each list allocation would generate garbage that triggers GC collection.
Usage pattern throughout the codebase:
csharp
List<SomeType> results = ListPool<SomeType>.claim();
try
{
// Populate and use the list
return results.ToArray(); // or similar
}
finally
{
ListPool<SomeType>.release(results);
}The try/finally pattern ensures the list is returned to the pool even if an exception occurs during population.
MathUtility
MathUtility provides static helper methods that supplement Unity's Mathf class with operations used by the game engine:
| Method | Purpose |
|---|---|
Clamp(Vector3, Bounds) | Clamps a vector to within axis-aligned bounds |
AngleDelta(float current, float target) | Shortest angular difference handling wrapping |
SmoothApproach(float current, float target, float rate, float delta) | Frame-rate-independent exponential smoothing |
PointInCircle(Vector2 point, Vector2 center, float radius) | Circle containment test |
PointInBox(Vector3 point, Vector3 center, Vector3 halfExtents, Quaternion rotation) | OBB containment test |
LinePlaneIntersection(...) | Ray-plane intersection for placement and aiming |
RandomRange(Vector2 min, Vector2 max) | Component-wise random range |
MathfEx (an extension class in SDG.Unturned) provides additional utilities like IsNearlyEqual(float, float) which is used throughout the LOD system.
PhysicsUtility
PhysicsUtility wraps Unity's Physics and Collider APIs with game-specific filtering:
| Method | Purpose |
|---|---|
SphereCast(Vector3 origin, float radius, Vector3 direction, float distance, out RaycastHit hit, int mask) | Sphere cast with Unity layer mask filtering |
SphereOverlap(Vector3 center, float radius, Collider[] results, int mask) | Overlap sphere query |
BoxOverlap(Vector3 center, Vector3 halfExtents, Quaternion rotation, Collider[] results, int mask) | Overlap box for vehicle and structure checks |
CheckIfClear(Vector3 center, float radius, int mask) | Returns true if no colliders in range |
All methods are thin wrappers over Physics.SphereCast, Physics.OverlapSphere, Physics.OverlapBox with the game's collision layer masks applied. The layer masks are defined in LayerMasks and referenced throughout the codebase.
IO Serialization Framework
The framework provides a formatted file serialization system in SDG.Framework.IO.FormattedFiles. It supports two data formats:
IFormattedFileReader / IFormattedFileWriter
The reader/writer pair provides structured key-value serialization:
csharp
public interface IFormattedFileReader
{
T readValue<T>(string key);
IFormattedFileReader readObject(string key);
IEnumerable<string> getKeys();
}
public interface IFormattedFileWriter
{
void writeValue<T>(string key, T value);
void beginObject(string key);
void endObject();
}Types that support serialization implement IFormattedFileReadable and IFormattedFileWritable. The AssetReference<T> struct, for example, uses these interfaces for GUID round-tripping.
River Binary Serialization
The River class provides binary serialization used for level save files, visibility data, and config data. It wraps a BinaryReader/BinaryWriter pair and provides readByte(), readBoolean(), readString(), writeByte(), writeBoolean(), writeString(), and similar methods.
The River format is used by:
LevelVisibility.save()/load()— visibility toggle persistence- Level save data (objects, items, zombies, vehicles, etc.)
- Config
.datfiles for per-level configuration
JSON Serialization
JSON serialization uses Newtonsoft.Json through the IOUtility.jsonSerializer and IOUtility.jsonDeserializer wrapper instances. The wrappers are pre-configured with the correct settings for the game's JSON format.
The JSON system is used by:
- Module configs (
.modulefiles) - Master bundle configs (
MasterBundle.dat) - Various editor-only export tools
RuntimeGizmos — Debug Visualization
The RuntimeGizmos system provides immediate-mode 3D debug drawing that renders through the GLRenderer overlay.
csharp
public class RuntimeGizmos
{
public static RuntimeGizmos Get();
public bool HasQueuedElements { get; }
public void Render();
// Drawing methods
public void Cube(Vector3 position, float size, Color color);
public void Line(Vector3 from, Vector3 to, Color color);
public void Sphere(Vector3 center, float radius, Color color);
// ...
}Gizmo elements are queued in a per-frame buffer and rendered during GLRenderer.OnRenderImage in the GL overlay pass. The system is conditionally compiled — gizmos are only available in GAME builds. The GL.QUADS draw mode is used for solid shapes, with GL.LINES for wireframe.
RuntimeGizmos is used by:
- Editor selection highlights
- Volume boundary visualization
- Spawn point markers
- Debug pathfinding visualization
- Water volume toggle visualization
Extension Methods
The Framework/Extensions/ directory contains extension method classes that add functionality to Unity and .NET types:
| Extension class | Target type | Notable extensions |
|---|---|---|
TransformEx | Transform | Position/rotation setters with optional world/local, child destruction helpers |
GameObjectEx | GameObject | Layer assignment for hierarchy, component get-or-create |
Vector3Ex | Vector3 | Magnitude clamping, direction calculation with optional up vector |
ColorEx | Color | Hex string parsing, brightness adjustment |
TypeEx | Type | TryIsAssignableFrom (used by ModuleHook for nexus discovery) |
The TryIsAssignableFrom extension is worth noting because it wraps the Type.IsAssignableFrom call in a null-safe check and is used in the module system's IModuleNexus discovery:
csharp
if (!type.IsAbstract && nexusType.TryIsAssignableFrom(type))
{
IModuleNexus nexus = Activator.CreateInstance(type) as IModuleNexus;
nexus.initialize();
}Water System
The Framework/Water/ directory contains the water volume system used by SkyFog and underwater rendering. WaterVolume defines a 3D volume zone, and WaterVolumeManager tracks all active water volumes. The VolumeAlphaPair<WaterVolume> struct pairs a volume with a distance alpha for fade calculations.
Landscapes
The Framework/Landscapes/ system manages the terrain-like landscape objects that exist in Unturned maps. These are not Unity terrains — they are custom mesh-based landscape chunks with their own LOD system, material management, and editing tools.
Devkit
The Framework/Devkit/ namespace contains the devkit system used by the in-game level editor. Key types:
| Type | Purpose |
|---|---|
SpawnpointSystemV2 | Manages spawn point visibility and editing |
RuntimeGizmos | Debug visualization |
Various VolumeManager classes | Manage volume-based game objects (safe zones, culling volumes, etc.) |
Pool Usage Map
Codebase pool usage
─────────────────────
ListPool<Asset> — Assets.find<T>() result collection
ListPool<Type> — Module type collection during assembly loading
ListPool<Vector3> — Pathfinding node collection
ListPool<Collider> — Physics overlap query results
ListPool<Player> — Player enumeration
ListPool<Zombie> — Zombie enumeration
Pool<SomeClass> — Frequently-created temporary objects
PoolablePool<SomeClass> — Objects with reset lifecycle callbacks
Pool<Stream> — (legacy, being phased out)MathUtility Usage Map
MathUtility.SmoothApproach — Camera smoothing, vehicle suspension
MathUtility.Clamp(Vector3) — Entity position clamping to world bounds
MathUtility.PointInCircle — Safezone and temperature bubble detection
MathUtility.PointInBox — Vehicle hitbox detection, building overlap
MathUtility.AngleDelta — Turret rotation, character model rotation
MathUtility.LinePlaneIntersection — Placement raycasts in editorFoliage System
The Framework/Foliage/ system manages interactive foliage placed in the level editor. Foliage instances are stored in a density-based grid and respond to player interaction (pushing through grass, harvesting plants). The system uses a combination of mesh instancing for rendering and per-instance state tracking for interaction. Foliage has collision detection separate from the physics system, using custom volume queries.
Foliage is organized by the FoliageCoordinator which manages loading/unloading foliage tiles based on camera distance and applying player-caused deformation (flattened grass paths).
Debug Module (Framework/Debug/)
The debug system provides console command infrastructure and logging. The UnturnedLog static class is the primary logging surface:
| Method | Log level | Severity |
|---|---|---|
info(string) | Info | Informational |
warn(string) | Warning | Non-critical issue |
error(string) | Error | Operation failure |
exception(Exception, string) | Error | Exception with context message |
All log methods write to both the Unity console and the game's log file. The log path is Unturned/Logs/ and is set up in Logs.awake() during the boot sequence.
IO Utility Serialization (Framework/IO/)
The IOUtility static class provides convenience wrappers for JSON serialization used by module configs and master bundle configs:
csharp
public static class IOUtility
{
public static Newtonsoft.Json.JsonSerializer jsonSerializer;
public static Newtonsoft.Json.JsonSerializer jsonDeserializer;
}The serializer and deserializer are pre-configured with the correct formatting settings for the game's JSON format. Module configs are deserialized with jsonDeserializer.deserialize<ModuleConfig>(filePath) and serialized back with jsonSerializer.serialize(config, filePath, true).
Volume Management System
The framework defines a volume management pattern used across multiple game systems. The pattern consists of:
| Component | Role |
|---|---|
VolumeBase | Base class for all 3D volume zones |
VolumeManagerBase<TVolume> | Singleton manager tracking all volumes of a type |
Volume types that follow this pattern:
| Volume type | Manager | Purpose |
|---|---|---|
WaterVolume | WaterVolumeManager | Water zones for swimming and underwater effects |
SafezoneVolume | SafezoneVolumeManager | PvP-free zones |
OxygenVolume | OxygenVolumeManager | Underwater oxygen zones |
TemperatureVolume | TemperatureVolumeManager | Temperature zones for survival |
CullingVolume | CullingVolumeManager | Visibility suppression zones |
NoStructuresVolume | NoStructuresVolumeManager | Building-restricted zones |
CartographyVolume | CartographyVolumeManager | Map reveal zones |
HordePurchaseVolume | HordePurchaseVolumeManager | Horde mode beacon purchase zones |
Each volume manager provides:
Get()— singleton accessorInternalGetAllVolumes()— list of all active volumes- Volume add/remove lifecycle hooks
The VolumeBase class stores the volume's transform, a reference to its GameObject, and provides GetClosestWorldPosition(Vector3) which is used by SkyFog's water relevance calculation.
Comparison with Standard .NET Patterns
Unturned's pool system is a deliberate alternative to standard .NET patterns:
| Pattern | .NET approach | Unturned approach | Rationale |
|---|---|---|---|
| Temporary lists | new List<T>() + GC.Collect | ListPool<T>.claim() + release() | Avoids GC pressure from frequent list allocations |
| Temporary objects | new T() + collected | Pool<T>.claim() + release() | Reduces allocation rate for ephemeral objects |
| File I/O | FileStream with using | River binary wrapper | Custom binary format with versioned serialization |
| JSON parsing | JsonConvert | IOUtility.jsonDeserializer | Pre-configured settings, centralized error handling |
The pool system predates .NET's ArrayPool<T> and Span<T> patterns. It was built for Unity's GC-heavy environment where each allocation contributes to frame-time spikes during collection.
PhysicsUtility Collision Layer Masks
All PhysicsUtility methods use Unity layer masks for filtering. The layer masks are defined in LayerMasks and include:
| Mask constant | Layers | Purpose |
|---|---|---|
GROUND | Ground, terrain | Ground check |
ENEMY | Enemy characters | Zombie/animal detection |
PLAYER | Player characters | Player collision |
STRUCTURE | Player-built structures | Building detection |
BARRICADE | Player-placed barricades | Barricade detection |
VEHICLE | Vehicles | Vehicle collision |
LOGIC | Non-rendering logic colliders | Trigger zones |
The sphere cast and overlap methods accept a mask parameter, allowing callers to filter by the relevant layer combination for each game context.
Appendix A: Pool Type Comparison
| Pool type | Generic? | Interface requirement | Internal storage | Thread-safe? |
|---|---|---|---|---|
Pool<T> | yes | None | Stack<T> | No |
PoolablePool<T> | yes | IPoolable | Stack<T> | No |
ListPool<T> | yes (static) | None | Thread-static | Yes (per-thread) |
Appendix B: MathUtility Method Signatures
| Method | Signature | Notes |
|---|---|---|
Clamp | Vector3 Clamp(Vector3 value, Bounds bounds) | Checks each axis independently |
AngleDelta | float AngleDelta(float current, float target) | Result in range [-180, 180] |
SmoothApproach | float SmoothApproach(float current, float target, float rate, float delta) | Exponential smoothing, frame-rate-independent |
PointInCircle | bool PointInCircle(Vector2 point, Vector2 center, float radius) | Uses squared distance |
PointInBox | bool PointInBox(Vector3 point, Vector3 center, Vector3 halfExtents, Quaternion rotation) | Transforms point to OBB local space |
LinePlaneIntersection | bool LinePlaneIntersection(Vector3 linePoint, Vector3 lineDir, Vector3 planePoint, Vector3 planeNormal, out Vector3 intersection) | Standard ray-plane intersection |
RandomRange | Vector2 RandomRange(Vector2 min, Vector2 max) | Per-component random |
RuntimeGizmos Rendering Details
The RuntimeGizmos system supports the following primitives:
| Primitive | Draw mode | Typical usage |
|---|---|---|
Cube(Vector3, float, Color) | GL.QUADS | Selection highlight around objects |
Line(Vector3, Vector3, Color) | GL.LINES | Pathfinding node connections |
Sphere(Vector3, float, Color) | GL.QUADS | Spawn point range indicators |
Cylinder(Vector3, float, float, Color) | GL.QUADS | Volume zone outlines |
Cone(Vector3, Vector3, float, Color) | GL.TRIANGLES | Direction indicators |
Text(string, Vector3, Color) | Texture | Debug labels in world space |
Gizmos are batched in a per-frame list that is cleared after each render. The HasQueuedElements property is checked by GLRenderer before enabling the GL overlay pass. If no gizmos are queued, the overlay pass is skipped entirely, avoiding the CPU cost of GL.PushMatrix/GL.PopMatrix.
The gizmo system is conditionally compiled with #if GAME — in the editor build, gizmos are always active. In release builds, gizmos are compiled out.
PhysicsUtility NonAlloc Variant Usage
All PhysicsUtility methods use the NonAlloc variants of Unity's physics API to avoid GC allocations:
csharp
public static bool SphereCast(Vector3 origin, float radius, Vector3 direction,
float distance, out RaycastHit hit, int mask)
{
return Physics.SphereCast(origin, radius, direction, out hit, distance, mask);
}The overlap methods use reusable buffers:
csharp
private static Collider[] overlapBuffer = new Collider[32];
public static int SphereOverlap(Vector3 center, float radius, Collider[] results, int mask)
{
return Physics.OverlapSphereNonAlloc(center, radius, results, mask);
}Callers must provide their own results array (typically pooled via ListPool<Collider>). The buffer size of 32 is sufficient for most queries — if more than 32 overlaps are detected, the excess are silently dropped.
Debug Console Integration
The Framework/Debug/ system provides the console command framework (CommandWindow) and the in-game developer console. The CommandWindow class provides:
| Method | Purpose |
|---|---|
Log(string) | Write to console output |
LogWarning(string) | Write warning with yellow highlight |
LogError(string) | Write error with red highlight |
Clear() | Clear the console buffer |
On dedicated servers, CommandWindow writes to the system console. On the client, it writes to the Unity console and the in-game developer console (if enabled).
The Logs class (initialized in Setup.Awake step 4) manages file-based logging:
csharp
public class Logs : MonoBehaviour
{
public void awake()
{
// Open log file stream
// Configure Unity's Application.logMessageReceived callback
}
}All UnturnedLog.info, warn, error, and exception calls write through this system.
Extension Method Usage Patterns
The Framework/Extensions/ extension methods are used throughout the codebase. Key usage patterns:
TransformEx
csharp
// Set position without changing parent
transform.SetPosition(position);
// Destroy all children immediately
transform.DestroyChildren();
// Find or create child by name
Transform child = transform.FindOrCreateChild("Name");GameObjectEx
csharp
// Set layer on entire hierarchy
gameObject.SetLayerRecursively(LayerMasks.ENEMY);
// Get component or add if not present
var rigidbody = gameObject.GetOrAddComponent<Rigidbody>();TypeEx
csharp
// Null-safe assignability check
if (nexusType.TryIsAssignableFrom(type))
{
// type implements IModuleNexus
}Appendix C: PhysicsUtility Extension Points
| Method | Unity API used | Layer mask parameter | Allocation |
|---|---|---|---|
SphereCast | Physics.SphereCastNonAlloc | mask | None (struct result) |
SphereOverlap | Physics.OverlapSphereNonAlloc | mask | Results array pooled |
BoxOverlap | Physics.OverlapBoxNonAlloc | mask | Results array pooled |
CheckIfClear | Physics.CheckSphere | mask | None |
All methods use the NonAlloc variants (except CheckIfClear which uses CheckSphere) to avoid allocating arrays during physics queries. The results array is typically obtained from the pool or reused as a static buffer within the calling method.
RuntimeGizmos Command-Line Integration
The RuntimeGizmos system can be controlled via the in-game developer console. The devkit commands that use gizmos include:
| Command | Gizmo type | Purpose |
|---|---|---|
Show Volumes | Wireframe boxes | Visualize all active volume zones |
Show Spawns | Spheres | Visualize spawn points |
Show Pathfinding | Lines | Visualize pathfinding node graph |
Show Teleporters | Wireframe boxes | Visualize teleporter volumes |
Each command toggles a flag that controls whether the relevant gizmos are queued for the next frame. Gizmos are only rendered when the render flag is set, and they are cleared after each frame.
SphereVolume and IShapeVolume
The SphereVolume class implements IShapeVolume and provides a spherical volume query interface:
csharp
public interface IShapeVolume
{
bool ContainsPoint(Vector3 point);
Vector3 GetRandomPoint();
float GetVolume();
}SphereVolume is used by:
- Explosion damage radius queries
- Zombie detection radius
- Item pickup radius
- Spawn point validation
The AACylinderVolume is another IShapeVolume implementation used by tree and resource node collision detection.
Pool Per-Thread Performance
The ListPool<T> implementation uses thread-static storage to avoid cross-thread contention:
csharp
[ThreadStatic]
private static List<T> _pooledList;This means each thread has its own cached list. There is no contention between the main game thread and the AssetsWorker threads. Each thread's pool is independent. The thread-static pattern is necessary because List<T> is not thread-safe and adding synchronization would defeat the pooling performance benefit.
The thread-static pool has one downside: lists claimed on one thread must be released on the same thread. Releasing on a different thread leaves the original thread's pool stale and adds the list to the wrong thread's cache. The try/finally pattern in the codebase ensures correct release on the same thread.
Extension Method Performance
The extension methods in Framework/Extensions/ are designed for convenience but have a performance tradeoff:
| Method | Allocation | Use frequency |
|---|---|---|
Transform.SetPosition(Vector3) | None | High (every frame) |
Transform.DestroyChildren() | None | Low (scene transitions) |
GameObject.SetLayerRecursively(int) | None | Medium (on spawn) |
GameObject.GetOrAddComponent<T>() | None | Low (on setup) |
TypeEx.TryIsAssignableFrom(Type) | None | Low (module init) |
None of the extension methods allocate managed memory. They are wrappers over existing Unity API calls that add null-checking and convenience patterns.
Physics Layer Collision Matrix
The physics layer collision matrix in Unturned determines which layers interact:
| Layer | Interacts with | Notes |
|---|---|---|
| Ground | All physics objects | Static geometry |
| Enemy | Player, Ground | Zombies and animals |
| Player | Enemy, Ground, Structure, Barricade | Player characters |
| Structure | Player, Vehicles | Player-built walls/floors |
| Barricade | Player, Vehicles | Player-placed objects |
| Vehicle | Ground, Structure, Barricade, Player | Vehicles |
| Logic | Everything (as trigger) | Trigger colliders |
The LayerMasks constants combine these into convenient query masks:
csharp
public static class LayerMasks
{
public static readonly int GROUND = 1 << Layer.GROUND;
public static readonly int ENEMY = 1 << Layer.ENEMY;
public static readonly int PLAYER = 1 << Layer.PLAYER;
public static readonly int RAY = GROUND | STRUCTURE | BARRICADE | VEHICLE;
// ...
}Pool Claim/Release Pattern Enforcement
The codebase enforces the pool release pattern through try/finally blocks. The pattern is consistent across all pool types:
csharp
// Correct pattern
List<T> results = ListPool<T>.claim();
try
{
// Use the list
ProcessResults(results);
}
finally
{
ListPool<T>.release(results);
}
// Incorrect (memory leak):
List<T> results = ListPool<T>.claim();
ProcessResults(results);
// release() never called → list never returned to poolThe finally block ensures release even when ProcessResults throws an exception. Without this pattern, the pooled list would remain in use and never return to the pool, causing the pool to allocate new lists on future claims.
PhysicsUtility Raycast Integration
The PhysicsUtility raycast methods are used throughout the codebase for:
| Use case | Method | Layers queried |
|---|---|---|
| Player aiming | SphereCast | GROUND, STRUCTURE, BARRICADE, ENEMY |
| Building placement | CheckIfClear | GROUND, STRUCTURE, BARRICADE |
| Explosion damage | SphereOverlap | ENEMY, PLAYER, STRUCTURE, BARRICADE, VEHICLE |
| Vehicle collision | BoxOverlap | GROUND, STRUCTURE, VEHICLE |
| Resource harvesting | SphereOverlap | RESOURCE |
| Item pickup | SphereOverlap | ITEM |
The raycast results are typically processed within a single frame. The pool is used to collect result arrays that are released after processing.
Frame-Rate Independent Smoothing
MathUtility.SmoothApproach provides frame-rate independent exponential smoothing:
csharp
public static float SmoothApproach(float current, float target, float rate, float delta)
{
float t = 1.0f - Mathf.Pow(1.0f - rate, delta);
return Mathf.Lerp(current, target, t);
}The rate parameter determines how quickly the value approaches the target. A rate of 0.1 means the value moves 10% of the remaining distance per second. The delta parameter is Time.deltaTime, making the smoothing frame-rate independent.
This is used for:
- Camera smoothing (third-person camera spring arm)
- Vehicle suspension damping
- UI animation transitions
- Procedural animation blending
The exponential smoothing has the property that it never overshoots the target, making it suitable for continuous values that should smoothly approach a target without oscillation.
Volume Manager Pattern
Each volume type follows a consistent manager pattern:
csharp
public class VolumeManagerBase<T> : MonoBehaviour where T : VolumeBase
{
public static T Get();
public void InternalAddVolume(T volume);
public void InternalRemoveVolume(T volume);
public List<T> InternalGetAllVolumes();
public event Action<T> onVolumeAdded;
public event Action<T> onVolumeRemoved;
}The volume manager is a singleton that:
- Maintains the list of all active volumes of its type
- Provides events for volume add/remove (used by SkyFog, safe zone detection, etc.)
- Provides a query method for all volumes (used by editor visualization)
Volumes register themselves with the manager in Awake() and unregister in OnDestroy(). This lifecycle ensures the volume list is always current.
Devkit Spawnpoint Visualization
The SpawnpointSystemV2 class in Framework/Devkit/ manages spawn point visualization in the level editor. It uses RuntimeGizmos to render spawn point markers as colored 3D primitives:
| Spawn type | Gizmo shape | Color |
|---|---|---|
| Player spawn | Sphere | Green |
| Zombie spawn | Cylinder | Red |
| Animal spawn | Cylinder | Yellow |
| Item spawn | Cube | Blue |
| Vehicle spawn | Box | Orange |
The visualization is only active when IsVisible is true and the editor UI is enabled. Toggling visibility is done through the LevelVisibility.nodesVisible property.
Document history
| Version | Date | Author | Notes |
|---|---|---|---|
| 1.0 | 2026-07-27 | 57 Studios | Initial publication. Pool system, math/physics utilities, IO serialization, gizmos, extensions. |
