Published Views
Register a View as a subscribable target — one shared instance or one per client — and get a handle clients can subscribe to.
Status: ✅ Implemented · Visibility: Public · Level: 🟢 Start Here · Category: Subscriptions
🎯 What it solves
Streaming live state to connected clients needs a server-side notion of "what is subscribable" that's
independent of any one client's connection — a name clients reference, a priority for overload behavior, and a
subscriber count for diagnostics. Without it, every feature wiring up client sync would invent its own
ad-hoc registry of "queries clients can ask for." PublishedView is that registry entry: it wraps a query
result (a ViewBase) with the metadata the subscription system needs to deliver deltas, and it is the only
currency SetSubscriptions accepts — callers hand it PublishedView handles, never raw Views.
⚙️ How it works (in brief)
TyphonRuntime.PublishView(...) registers a View under a unique name and returns a PublishedView handle.
Two registration modes exist, picked by which overload you call: pass a ViewBase instance directly for a
shared View (one instance, all subscribers see the same data), or pass a Func<ClientContext, ViewBase>
factory for a per-client View (a fresh instance created for each subscriber). Every PublishedView carries
a Name, a Priority (for overload throttling), an IsShared flag, and a live SubscriberCount. The
PublishedViewRegistry, reachable via runtime.PublishedViews, holds every published View for lookup and
diagnostics. Registration itself does not start pushing data — a client only receives deltas for a View once
it is included in a SetSubscriptions call.
Sub-features
| Sub-feature | Use it for |
|---|---|
| Shared (world-state) Views | World objects, NPCs, terrain — one delta computed per tick, fanned out to every subscriber |
| Per-client View factories | Inventory, quest state, anything parameterized by which client is asking |
⚠️ Guarantees & limits
- Names are unique and permanent —
PublishViewthrowsArgumentExceptionif the name is already registered; there is no unpublish/rename. - A View can only be published once —
RegisterSharedthrowsInvalidOperationExceptionon a View that's already published, and on one already wired as a system input (see Published/System-Input View Separation). Use a dedicated View instance per published name. - Publishing is setup-time, not per-tick — registration takes a lock and rebuilds a snapshot array; it is meant to happen during startup/configuration, not on a hot path.
PublishedView.PublishedId(ushort) is assigned in registration order and is stable for the process lifetime; it is not persisted across restarts.SubscriberCountreflects only clients currently inActive/Syncingsubscription state — it changes asSetSubscriptionstransitions are applied during the Output phase, not the instant the call is made.
🧪 Tests
- ViewSeparationTests — name
uniqueness (
ArgumentException), single-publish rule (InvalidOperationException), theIsPublishedflag, and that two separate View instances over the same query don't conflict
🔗 Related
- Sibling: Published/System-Input View Separation
- Sibling: Persistent Views — the underlying
ViewBasequery mechanism this feature publishes over the wire - Sub-features: Shared (world-state) Views, Per-client View factories