Class ObserverStreamingRegistry
Server-side scheduler that applies ObserverStreamingPolicy to every registered character: scales each one's observer range by local density, and for every viewing client ranks what it can see and rate limits everything beyond the cap.
public static class ObserverStreamingRegistry
- Inheritance
-
ObserverStreamingRegistry
- Inherited Members
Remarks
Characters register from CharacterPredictionController.OnStartServer — players,
monsters, pets, and the service NPCs built on the same prefab stack — because their
NetworkTransform and other per-tick traffic is what an observer's bandwidth is spent on.
Static classified objects (world items, waypoints) have no such hook and are adopted by
ObserverBudgetCondition on first evaluation, so that every classification can
be budgeted; they cost a position read per pass and nothing on the wire.
Runs one pass every RescheduleIntervalTicks ticks off FishNet.Managing.Timing.TimeManager.OnPostTick. A pass is O(entries) for density (uniform grid) plus O(viewers × entries) for ranking, with entries grouped by Unity scene so characters in different scenes never compare positions. At 200 players and 700 characters that is ~140k score evaluations per half second, all field reads.
Properties
Count
Number of objects currently registered — characters and budgeted statics alike.
public static int Count { get; }
Property Value
LastPassBudgetExcluded
(viewer, observed) pairs excluded by the visibility budget in the last pass.
public static int LastPassBudgetExcluded { get; }
Property Value
LastPassLimitedPairs
(viewer, observed) pairs rate limited in the last pass.
public static int LastPassLimitedPairs { get; }
Property Value
LastPassPinned
Characters pinned into a visibility budget in the last pass.
public static int LastPassPinned { get; }
Property Value
LastPassRangeChanges
Characters whose observer range was changed in the last pass.
public static int LastPassRangeChanges { get; }
Property Value
LastPassViewers
Viewers ranked in the last pass.
public static int LastPassViewers { get; }
Property Value
Methods
Clear()
Drops every registration. For tests and server shutdown.
public static void Clear()
Remarks
Through Detach(ObserverStreamingEntry, int) rather than Unregister(NetworkObject), which takes the object and so cannot remove an entry whose object has already been destroyed — exactly the entries a shutdown is most likely to be holding.
Get(NetworkObject)
Returns the entry for a registered object, or null.
public static ObserverStreamingEntry Get(NetworkObject networkObject)
Parameters
networkObjectNetworkObject
Returns
IsWithinVisibilityBudget(int, int, bool, out bool)
Whether a character is inside a viewer's visibility budget.
public static bool IsWithinVisibilityBudget(int viewerClientId, int observedObjectId, bool currentlyVisible, out bool hasRanking)
Parameters
viewerClientIdintClient id of the viewing connection.
observedObjectIdintObject id of the character being tested.
currentlyVisibleboolTrue when the viewer already observes it; widens the budget by the hysteresis.
hasRankingboolFalse when this viewer has no ranking yet.
Returns
- bool
True when the character is inside the budget.
Remarks
The budget condition's whole implementation. hasRanking distinguishes
"ranked and excluded" from "no pass has run for this viewer yet" — the caller must not
treat the second as a rejection, or everything stays hidden until the first pass lands.
LogSummary()
Logs a one-line summary of the last pass. For diagnostics.
public static void LogSummary()
Register(NetworkObject, ICharacter)
Registers a character. Installs the entry as the object's observer send filter.
public static ObserverStreamingEntry Register(NetworkObject networkObject, ICharacter character)
Parameters
networkObjectNetworkObjectcharacterICharacter
Returns
RegisterObject(NetworkObject)
Registers a classified object that nothing else registered — a dropped item, a waypoint.
public static ObserverStreamingEntry RegisterObject(NetworkObject networkObject)
Parameters
networkObjectNetworkObjectThe object to track.
Returns
- ObserverStreamingEntry
The entry, or null when the object is not classified.
Remarks
These have no CharacterPredictionController to register them from, so the call
comes from ObserverBudgetCondition the first time the object is evaluated:
that condition runs on the server for every object carrying the manager's defaults, and
it already holds the NetworkObject. The first evaluation defers (the object is
unranked, which is admitted) and the next scheduling pass ranks it — the same deferral a
freshly connected viewer gets, and the reason neither shows as a pop-in.
Only objects that declare a ClassifiedDistanceCondition are taken. Anything else has no budget to be measured against, and registering it would cost a per-pass position read for a decision that would always be "admit".
RunPass()
Runs one scheduling pass over every registered character. Public so a server can force a pass after a bulk change (a load boundary) and so tests can drive it.
public static void RunPass()
TryGetNearestViewerDistance(NetworkObject, out float)
Distance from networkObject to the nearest player in its scene, as
measured by the last scheduling pass.
public static bool TryGetNearestViewerDistance(NetworkObject networkObject, out float distance)
Parameters
networkObjectNetworkObjectThe object to measure from.
distancefloatDistance to the nearest player, or
PositiveInfinitywhen the scene holds none.
Returns
- bool
True when a pass has measured this object.
Remarks
The proximity primitive server-side simulation should ask, in place of
NetworkObject.Observers. Observer membership answers "who is this object being
streamed to", which the visibility budget bounds — a monster outside every viewer's budget
has no observers and is still standing in a crowd. This answers "how close is the nearest
player", which is what a leash, a wake-up or an aggro sweep actually wants to know.
False when the object is not registered, or when no pass has measured it yet. Callers must
not read that as "nobody is near": it is an unanswered question, and the answer arrives
within one RescheduleIntervalTicks.
Unregister(NetworkObject)
Unregisters a character, restoring its prefab range and removing the send filter.
public static void Unregister(NetworkObject networkObject)
Parameters
networkObjectNetworkObject