Table of Contents

Class ObjectSpawnerScheduler

Namespace
FishMMO.Shared
Assembly
FishMMO.Shared.dll

Runs the respawn checks for every ObjectSpawner that currently has something to respawn, from one Update instead of one per spawner.

public static class ObjectSpawnerScheduler
Inheritance
ObjectSpawnerScheduler
Inherited Members

Remarks

The interval a spawner polls on is still its own — see RespawnCheckIntervalMinimum. What changes here is which spawners are asked at all. A spawner with nothing pending, which is most of them in a world at rest, is not in the list and costs nothing whatsoever: not a check, not a gate comparison, and not a Update dispatch.

The list holds references, not scheduling state. It is a plain List<T> of spawners with membership maintained by swap-removal, so a spawner occupies one reference while it has work and nothing at all when it does not. There is no ordering structure, no queued entries, and no per-spawner allocation. Measured against 100,000 spawners, whose own timer lists and spawned dictionaries come to roughly 107 MB, a membership list covering a tenth of them adds about 0.25 MB.

Fields

FramesPerSweep

How many frames one full pass over the active list is spread across.

public const int FramesPerSweep = 60

Field Value

int

Remarks

A spawner's own check interval is seconds long, so being visited within about a second costs nothing anybody can observe and keeps the per-frame walk proportional to a slice of the active list rather than all of it.

NotActive

The index stored on a spawner that is not currently in FishMMO.Shared.ObjectSpawnerScheduler.active.

public const int NotActive = -1

Field Value

int

Properties

ActiveCount

How many spawners currently have work outstanding. Exposed for tests and diagnostics.

public static int ActiveCount { get; }

Property Value

int

Methods

Clear()

Empties the active list. Intended for tests and for a clean shutdown between sessions.

public static void Clear()

Refresh(ObjectSpawner)

Brings spawner into or out of the active list to match whether it has anything to respawn.

public static void Refresh(ObjectSpawner spawner)

Parameters

spawner ObjectSpawner

The spawner whose membership should be refreshed.

Remarks

Call after anything that changes that: a despawn adding a respawn timer, a spawn consuming one, or the spawner reaching its cap and clearing them. Idempotent, so callers need not track whether the spawner was already in the list.

Tick(DateTime)

Gives every spawner with outstanding work the chance to run its respawn check.

public static void Tick(DateTime nowUtc)

Parameters

nowUtc DateTime

The current UTC time, for evaluating respawn deadlines.

Remarks

Each spawner decides for itself whether its own interval has elapsed, so this walk is a float comparison per active spawner and nothing more. Spawners that finish their work leave the list here rather than being left to be skipped over on later frames.

Tick(DateTime, float)

Gives a slice of the spawners with outstanding work the chance to run their respawn check.

public static void Tick(DateTime nowUtc, float nowTime)

Parameters

nowUtc DateTime

The current UTC time, for evaluating respawn deadlines.

nowTime float

The current UnityEngine.Time.time, for the interval gates.

Remarks

The list is swept rather than walked: each frame advances a cursor through a fraction of it, so every active spawner is visited about once per FramesPerSweep frames instead of every frame. Their own interval gate is measured in seconds (RespawnCheckIntervalMinimum), so visiting more often than that buys nothing — it only moves the cost from the spawners that have work to the ones that are merely waiting, which is most of them.

UnityEngine.Time.time is read once by the caller rather than by each spawner. It is a native property, and crossing into the engine per active spawner per frame cost more than everything else in this walk put together.

The dangling-reference check is ReferenceEquals(object, object) and not == null on purpose. Unity overloads that operator to ask the engine whether the native object is still alive, which is another crossing per entry per frame. Membership is maintained on destruction instead, so a plain reference check is all this needs.

Unregister(ObjectSpawner)

Drops spawner from the active list.

public static void Unregister(ObjectSpawner spawner)

Parameters

spawner ObjectSpawner

The spawner to drop.

Remarks

Call from OnStopNetwork, so a spawner in an unloaded scene is not walked and its reference is not held.