Table of Contents

Systems Abstraction

Namespaces: RisingV.Shared.Systems, RisingV.Shared.Managers
Assembly: RisingV.Shared

The Systems abstraction is the lightest layer on top of the Manager framework, aimed at orchestrating game‐loop tickers—logic that runs every server tick, physics step, or fixed interval (think Update in Unity’s ECS).

Plugin
  └─ SystemManager
        ├─ HealthRegenSystem
        ├─ WeatherSystem
        └─ SpawnCleanupSystem

Each system supplies:

  • Update(float dt) – executed once per tick.
  • Optional stages (PreUpdate, PostUpdate).
  • IsEnabled flag that can be toggled at runtime or via config.

1. Core Contracts

Contract Purpose
ISystem Marker; ties a system to SystemManager.
ITickSystem Adds the Update method with delta‐time parameter.
IStageSystem Adds optional PreUpdate / PostUpdate hooks.
SystemBase Convenience abstract base that wires logging, enable flag, and config binding.
SystemManager TypeMapManager that registers systems and drives the tick loop.

ISystem & ITickSystem

public interface ISystem : IManageable<SystemManager>
{
    bool IsEnabled { get; }
}

public interface ITickSystem : ISystem
{
    void Update(float deltaTime);
}

IStageSystem (Optional)

public interface IStageSystem : ITickSystem
{
    void PreUpdate(float dt)  { }
    void PostUpdate(float dt) { }
}

SystemBase

Provides:

  • protected readonly Logger Log
  • protected ConfigEntry<bool>? EnabledEntry (auto‐bound)
  • Virtual OnEnable() / OnDisable() for side‐effects.
public abstract class SystemBase : IStageSystem
{
    public virtual bool IsEnabled => EnabledEntry?.Value ?? true;
    public virtual void PreUpdate(float dt) { }
    public abstract void Update(float dt);
    public virtual void PostUpdate(float dt) { }
}

2. SystemManager

public sealed class SystemManager
    : TypeMapManager<ISystem, SystemManager>, IPluginComponent
{
    public float TimeScale { get; set; } = 1f;

    // Tick driver – call from plugin’s server loop
    public void Tick(float deltaTime)
    {
        deltaTime *= TimeScale;

        foreach (var sys in this.Enumerate<ITickSystem>())
        {
            if (!sys.IsEnabled) continue;

            if (sys is IStageSystem stage) stage.PreUpdate(deltaTime);
            sys.Update(deltaTime);
            if (sys is IStageSystem stage2) stage2.PostUpdate(deltaTime);
        }
    }
}

Lifecycle mirrors other managers (Initialize → Load → Ready …) so systems can perform heavy allocation in Load and start ticking only after Ready.


3. Typical Usage

// Plugin field
public override void OnInitialize()
{
    SystemManager.AddSystem<HealthRegenSystem>(this);
    SystemManager.AddSystem<WeatherSystem>(this);
}

// If you want to handle the ticks manually, e.g. in a server loop, you can do so:
// Make sure the SystemManager.UseBuiltInTickRunner is set to false.
public void OnServerTick(float dt) => _systems.Update(dt);

Creating a system:

public sealed class HealthRegenSystem : SystemBase
{
    public override void Update(float dt)
    {
        foreach (var player in PlayerDatabase.All)
            player.AddHealth(0.5f * dt);
    }
}

4. Advanced Features

Feature Description
TimeScale Speed up / slow down simulation (0 pauses all systems).
Dynamic Add/Remove Add or unload systems at runtime; manager updates enumeration cache safely.
Priority Sorting (Optional) Override SystemManager.OrderItems to sort by custom attribute [SystemPriority].
Hot Reload Systems implementing IReloadable will receive config changes without restart.

5. Best Practices

  • Keep per‐tick work tiny—heavy jobs belong in asynchronous Tasks or Jobs.
  • Use deltaTime rather than Time.fixedDeltaTime constants to remain framerate‐independent.
  • Toggle systems via config (EnabledEntry) for fast iteration.
  • Log at Trace in hot paths; strip in release builds.

6. Troubleshooting

Symptom Possible Cause Remedy
System never runs Not registered / IsEnabled=false Add in Initialize; check config.
Stutter spikes Heavy logic in Update Profile; move to job threads or cache expensive lookups.
Tick order wrong Dependencies between systems Implement priority attribute or split into multiple managers.

TL;DR

  • System = ticked logic module with optional pre/post stages.
  • SystemManager orchestrates updates and plugs into the Manager lifecycle.
  • Use for timers, regen, world effects, cleanups—any looped behaviour that doesn’t justify a full Engine.