CityRP Documentation Repository

cityrp.network

Clientside receiving, handshake, pull-on-visible resync and :ClientOwned() sends for the CityRP networking library. Storing values directly on the entity (sh_store.lua) retires the plugin this library replaces' worst clientside bug for free: PLUGIN.NSVars[entIndex], keyed by raw index, was never cleared on disconnect, so a recycled edict inherited whatever the previous occupant left behind. GMod hands a newly-created entity a fresh Lua table regardless of which index it reuses, so ent.__netvars simply does not exist yet for it -- there is nothing to clean up, and nothing here needs to try.

The gap that storage model leaves is timing. A value can arrive (via Update or Resync) referencing an entity this client hasn't networked yet; those are buffered by raw index in pending until OnEntityCreated produces the entity, and swept on a TTL in case it never does. And snapshots can overtake net messages, so a value sent for a leaving player can arrive after the slot is empty or already holds the next player. A player's index header carries their UserID for that: a value for anyone but the slot's current or next occupant is dropped.

Functions

Clientcityrp.network.AnnounceReady()Source ☍

Announces that this client's net channel is up and ready to receive the manifest.

Servercityrp.network.ApplyAndSend(netvar, ent, value) → booleanSource ☍

Applies a value and, if ApplyValue's delta guard says it changed, sends it.

Parameters

Returns

  1. booleanWhether the value changed, and therefore whether an update was sent.
Clientcityrp.network.ApplyIndexed(index, netvar, value, userid)Source ☍

Applies a decoded entity-scoped value, buffering it if the entity hasn't appeared yet. A player's value for an earlier occupant of the slot is dropped; one for a later occupant is buffered.

Parameters

  • indexinteger
  • netvarNetVar
  • valueany
  • useridinteger?The wire UserID of the player the value was sent for, or nil for a non-player entity.
Clientcityrp.network.ApplyUnindexed(netvar, value)Source ☍

Applies a decoded no-index value: Global goes to the global table, LocalPlayer to LocalPlayer().

Parameters

Sharedcityrp.network.ApplyValue(netvar, ent, value, predicted) → booleanSource ☍

Validates (if the var has an :Enum()-set validate function), applies a value to storage, and fires the var's :SetHook() hook if the value changed. Shared by the server's own SetNetVar/SetGlobal (sv_send.lua) -- so the server's own copy of a value updates immediately regardless of who receives the resulting net message, and so the delta guard that decides whether to bother networking at all lives in exactly one place -- and the client's receive path (cl_receive.lua), once an update has actually been decoded. for a client-side local apply the server has not confirmed, from either a :Predictable() or a :ClientOwned() var's client setter. See GenerateAccessor below.

Parameters

  • netvarNetVarThe var being applied.
  • entEntity?The entity to store on. Ignored (may be nil) for Global scope.
  • valueanyThe decoded value.
  • predictedboolean?Passed through to the :SetHook() hook as its 5th argument -- true only

Returns

  1. booleanWhether the value actually changed (false for a redundant re-set or a rejected invalid one).
Clientcityrp.network.BufferPending(index, id, value, userid)Source ☍

Buffers a decoded value for an entity index that doesn't resolve to a valid entity yet. A value for a player replaces a buffer held for an earlier occupant of the slot, and is dropped if the buffer is already held for a later one.

Parameters

  • indexinteger
  • idinteger
  • valueany
  • useridinteger?The wire UserID of the player the value was sent for, or nil for a non-player entity.
Servercityrp.network.ClearDebounce(owner)Source ☍

Drops every pending value and window for one owner. Called from sv_send.lua's cleanup hooks.

Parameters

  • ownerEntityThe disconnecting player or removed entity.
Clientcityrp.network.ClearPending(index)Source ☍

Drops everything buffered for index.

Parameters

  • indexinteger
Clientcityrp.network.ClientSet(name, value)Source ☍

Sets a :ClientOwned() var on the local player: applies it locally, then asks the server to accept it. What the server receives is a claim, never a fact -- see docs/networking.md.

The generated Set<Name>() calls this; use it directly for a var registered without :Accessor().

Parameters

  • namestringThe registered var name.
  • valueanyThe new value. nil clears it.
Servercityrp.network.CollectSendableVars(ent, ply, names, revoke) → { netvar: NetVar, value: any }[]Source ☍

Collects this entity's currently-set entity-scoped vars (IsEntityScope) that ply is allowed to see. Global and LocalPlayer-scoped vars never go through resync -- Global is broadcast independently of any entity's visibility, and LocalPlayer is always pushed straight to its one owner. substitute, replacing it on their client. Defaults to true; only the join bootstrap passes false.

Parameters

  • entEntity
  • plyPlayer
  • namestable<string, boolean>?Only collect these var names. nil collects every set var.
  • revokeboolean?Whether a :Filter()ed var ply fails contributes GetRevokedValue's

Returns

  1. { netvar: NetVar, value: any }[]
Servercityrp.network.CountInbound(ply) → booleanSource ☍

Counts one inbound message against ply's budget and says whether to process it. Deliberately crude -- :Debounce() is what actually makes client-owned vars safe, so this only ever fires for a client sending orders of magnitude more than a real one.

Parameters

Returns

  1. booleanFalse if the message should be ignored.
Servercityrp.network.DebounceSet(netvar, ent, value)Source ☍

Routes one server-side set through this var's debounce window. Called from cityrp.network.Dispatch (sv_send.lua) for any var that declared :Debounce().

Parameters

Sharedcityrp.network.DecodeEntry() → NetVar?, any, booleanSource ☍

Reads one var entry written by WriteVarEntry. On any decode failure the byte length of what follows is unknowable, so callers must stop reading rather than continue -- safe because a non-batchable entry is never batched with anything else.

Returns

  1. 1NetVar?nil on failure.
  2. 2any
  3. 3booleanFalse if the rest of this message must be discarded.
Servercityrp.network.DequeueEntity(ply, ent)Source ☍

Removes ent from ply's resync queue, clearing ply from pendingPlayers if that empties it.

Parameters

Servercityrp.network.Dispatch(netvar, ent, value)Source ☍

The single seam every server-side set goes through, so :Debounce() is one branch rather than a condition duplicated in SetNetVar and SetGlobal.

Parameters

Servercityrp.network.DrainOnePlayer(ply, take) → integerSource ☍

Drains up to take entities from ply's resync queue and sends whatever they're owed. A queue entry is a "re-evaluate me" marker, never a snapshot: no value and no recipient decision is captured when an entity is queued, only which vars to look at. Everything is read live here, so an entry queued several frames ago still sends the current value to whoever currently passes.

Parameters

Returns

  1. integerHow many queue entries were consumed (valid or not).
Clientcityrp.network.DrainPending(ent)Source ☍

Applies any values buffered for ent, now that it actually exists. A buffer held for a player other than ent is discarded.

Parameters

Servercityrp.network.DrainPendingDebounces()Source ☍

Applies any pending values whose windows have closed. On Think rather than a timer.Simple per pair, which would be a timer per player per var, each needing to re-validate its entity inside the callback (AGENTS.md footgun #2) for a routine mid-window disconnect.

Servercityrp.network.DrainResyncQueues()Source ☍

Drains every player's resync queue, round-robin, within the configured per-frame budgets. The cursor persists across frames (drainCursorPly) so a player who was last in line this frame is first in line next frame -- with enough players queued to exceed the per-frame budget, this is what guarantees everyone is eventually served instead of the same players always winning the race. If the previous cursor's queue emptied out between frames, the round-robin simply restarts from the first candidate rather than trying to preserve a "position" a table with unstable iteration order can't actually promise -- a minor, self-correcting fairness wrinkle.

Servercityrp.network.EnqueueAllEntitiesForResync(ply, revoke)Source ☍

Queues every currently-known networked entity for resync to ply. Used for the join bootstrap -- reusing the resync path means a large join gets the same per-frame rate limiting as any other resync, rather than a separate one-off bulk-send path to reason about and maintain. since a client holding a manifest from seconds ago has nothing stale to replace.

Parameters

  • plyPlayer
  • revokeboolean?Passed through to QueueEntity. Defaults to true; MarkReady passes false,
Sharedcityrp.network.FindVar(name) → NetVar?Source ☍

Looks up a registered var by name, logging (once per call, not once per name) if it isn't one. Shared by every public getter/setter so "unregistered name" fails the same way everywhere.

Parameters

  • namestringThe var name to look up.

Returns

  1. NetVar?The registered var, or nil (and a logged error) if name isn't registered.
Clientcityrp.network.FlushClientSets()Source ☍

Sends everything buffered while the manifest was outstanding. Called from the manifest receiver above, once byId/idBits are populated.

The queue is swapped out before iterating: each apply runs the var's :SetHook(), which may call ClientSet again, and adding a key mid-pairs is undefined in Lua.

Clientcityrp.network.FlushResyncRequests()Source ☍

Sends one batched resync request for every entity queued since the last flush.

Sharedcityrp.network.GenerateAccessor(netvar)Source ☍

Defines Get<Name>() (both realms) and Set<Name>() for a var registered with :Accessor(name), on the metatable ACCESSOR_METATABLE maps its scope to (Entity for Global/Entity scope, Player for Player/LocalPlayer, Vehicle/Weapon for those). A no-op for a var with no accessor name set. Idempotent -- safe to call more than once for the same var.

Set<Name>() is server-only -- SetNetVar/SetGlobal live in the server-only sv_send.lua -- unless the var opted into a client-side form:

  • :ClientOwned() applies locally and sends. Already vetted at seal by ValidateClientOwned, so a var that failed has had the flag cleared and simply gets no setter here.
  • :Predictable() applies locally only. Coherent for :SetLocalPlayer() alone, so a scope mismatch is a logged error rather than a silently-generated footgun.

Both pass predicted = true -- the client is holding a value the server has not confirmed either way. Client-owned wins if a var chained both; ValidateClientOwned has already warned.

Parameters

  • netvarNetVarThe var to generate accessors for.
Sharedcityrp.network.GenerateAccessors()Source ☍

Generates accessors for every currently-registered var. Called once from Seal(), after which new registrations no longer occur -- see sh_registry.lua.

Sharedcityrp.network.GenerateEarlyAccessor(netvar)Source ☍

Installs Get<Name>() (and the server's Set<Name>()) at registration, so a caller running before Seal finds them. Re-run by :Accessor() and each scope setter because chain order is free; it removes what this var installed elsewhere. Client setters wait for GenerateAccessor.

Parameters

  • netvarNetVarThe var to install accessors for.
Servercityrp.network.GetDebounceReport() → { owner: Entity?, netvar: NetVar, interval: number, pending: boolean, dispatches: integer }[]Source ☍

Every (owner, var) pair the debouncer is tracking, for cityrp_network_dump. Includes settled pairs: without them the dump cannot tell a var that has never been set from one that has, which is exactly the question worth asking of a client-owned var that is not arriving.

Returns

  1. { owner: Entity?, netvar: NetVar, interval: number, pending: boolean, dispatches: integer }[]
Sharedcityrp.network.GetGlobal(name, default) → anySource ☍

Reads a Global-scoped networked value.

Parameters

  • namestringThe registered var name.
  • defaultanyReturned if the value has never been set, or on any error path.

Returns

  1. any
Servercityrp.network.GetQueue(ply) → table<Entity, boolean|table<string, boolean>>Source ☍

Gets (creating if needed) a player's resync queue. A queue is a plain weak-keyed table of entities, not an ordered array. Photon's original resync queue is an array plus a drain cursor needing periodic "backlog reclamation" to stop the backing array growing forever; a weak-keyed table has no backing array to grow, and dropping an entity from it is an ordinary key removal. The trade-off is that iteration order (pairs) is unspecified rather than FIFO, which is fine -- fairness across players already comes from the round-robin in DrainResyncQueues, not per-player ordering.

Parameters

Returns

  1. table<Entity, boolean|table<string, boolean>>
Servercityrp.network.GetRevokedValue(netvar) → anySource ☍

What to send a player who has stopped passing a :Filter()ed var's check: :SetDefault()'s value, or nil to clear it outright.

Warning

A fixed substitute, not a per-player one -- every filtered-out player is told the same thing.

Parameters

Returns

  1. any
Sharedcityrp.network.GetSignedBits(value) → integerSource ☍

Number of bits required to write value with net.WriteInt, clamped to 1-32. Always reserves a sign-headroom bit -- without it, an exact power of two (e.g. 4, needing 3 unsigned bits) would not fit the signed range those same 3 bits provide (-4..3), silently truncating.

Parameters

  • valuenumberThe (integral) value that will be written.

Returns

  1. integerBits required, 1-32.
Sharedcityrp.network.GetUnsignedBits(value) → integerSource ☍

Number of bits required to write value with net.WriteUInt, clamped to 1-32. Unlike GetSignedBits, no sign-headroom bit is reserved -- callers must already know value is non-negative.

Parameters

  • valuenumberThe (integral, non-negative) value that will be written.

Returns

  1. integerBits required, 1-32.
Sharedcityrp.network.GetValueCodec(value) → NetCodecIdSource ☍

Determines which codec Auto should tag a value as. Mirrors the closed set bounded by AUTO_TAG_MAX -- every branch here must return an ID whose codec table entry actually exists and is self-contained (no extra argument required to read it back).

Parameters

  • valueanyThe value to classify.

Returns

  1. NetCodecIdThe codec ID to tag and write it with.
Servercityrp.network.Invalidate(ply, ent, key)Source ☍

Re-evaluates key for ply, delivering a value that has become visible and replacing one that has stopped being. Call it from whatever changed the eligibility; a filter is otherwise re-run only on a set or a PVS re-entry, neither of which is an authorization event. filter:GetPlayers(). Players mid-handshake are skipped. Global and LocalPlayer keys.

Parameters

  • plyPlayer|Player[]|nilnil re-evaluates for every player. Not a CRecipientFilter; pass
  • entEntity|Entity[]|nilnil scans ents.Iterator(), the expensive shape. Ignored for
  • keystring|string[]Required; also picks the route, since a name identifies its own scope.
Sharedcityrp.network.IsEntityScope(scope) → booleanSource ☍

Whether scope stores on an entity and uses entity-index wire framing.

Parameters

  • scopeNetScopeWhere a NetVar's value lives and who it is sent to by default.

Returns

  1. boolean
Sharedcityrp.network.IsFloatValue(value) → booleanSource ☍

Whether a Lua number is non-integral. Written without GMod's math.floor(value, 0) two-arg form this codebase's predecessor relied on -- the second argument is silently ignored either way.

Parameters

  • valuenumberThe number to check.

Returns

  1. booleanTrue if flooring value would change it.
Clientcityrp.network.IsLaterUserID(a, b) → booleanSource ☍

Whether wire UserID a was assigned after b. UserID only climbs, but the wire carries it modulo USERID_BITS, so this compares across the wrap.

Parameters

  • ainteger
  • binteger

Returns

  1. boolean
Sharedcityrp.network.IsNormalVector(vec) → booleanSource ☍

Whether a vector's components are all small enough to use the compact Normal wire encoding. Checks magnitude, not raw value -- a component of -1000 must not qualify just for being < 1.

Parameters

  • vecVectorThe vector to check.

Returns

  1. booleanTrue if every component's magnitude is at most 1.
Servercityrp.network.IsRecipientsEmpty(recipients) → booleanSource ☍

Whether a resolved recipient value (from :Filter()/:SendOmit()) contains no one.

Parameters

Returns

  1. boolean
Servercityrp.network.MarkReady(ply)Source ☍

Completes a player's handshake: sends the manifest and initial bootstrap, marks them ready, and runs anything queued by WaitForPlayer. Idempotent -- a client that re-announces before receiving anything back is a safe no-op. __netReady does not gate live Update/Resync sends (see SendUpdate's own comment for why); it gates the server's willingness to accept a resync request from this player and to count them as a resync candidate, both of which would be meaningless before their manifest exists.

Parameters

Servercityrp.network.MergeQueueEntry(existing, incoming) → boolean|table<string, boolean>Source ☍

Merges an incoming queue entry into what is already queued, keeping whichever is broader on both of NetResyncEntry's axes. Monotonic, so call order within a frame cannot narrow an entry.

Parameters

  • existing(boolean|table<string, boolean>)?What is already queued, or nil if nothing is.
  • incomingboolean|table<string, boolean>The entry being added.

Returns

  1. boolean|table<string, boolean>The entry to store.
Servercityrp.network.PassesRecipientCheck(netvar, ent, value, ply) → booleanSource ☍

Whether ply should receive this var's current value, for resync and bootstrap purposes. PVS/PAS are treated as bandwidth filters, not secrecy boundaries: they always pass here, because resync/bootstrap only ever consider a var for a player who is (or is about to be) in a position to receive it anyway. Only :Filter() can actually withhold a value from a specific player -- this is also why :Filter()'s callback doubles as the authorization check, rather than needing a second, separately-maintained predicate that could drift out of sync with the one used for live sends.

Parameters

  • netvarNetVar
  • entEntity?nil for the no-index (Global/LocalPlayer) group.
  • valueany
  • plyPlayer

Returns

  1. boolean
Servercityrp.network.QueueEntity(ply, ent, revoke)Source ☍

Adds ent to ply's resync queue for every var it has set, merging with anything already queued. GetRevokedValue's substitute. Defaults to true; only the join bootstrap passes false.

Parameters

  • plyPlayer
  • entEntity
  • revokeboolean?Whether the drain replaces a :Filter()ed var ply no longer passes with
Servercityrp.network.QueueEntityVars(ply, ent, names)Source ☍

Adds ent to ply's resync queue for only the named vars, merging with anything already queued.

Warning

names is stored by reference and must not be mutated afterwards -- one caller shares a single set across every pair it queues.

Parameters

  • plyPlayer
  • entEntity
  • namestable<string, boolean>The var names to resync, as a set.
Sharedcityrp.network.ReadAutoValue() → anySource ☍

Reads a value written by WriteAutoValue.

Returns

  1. anyThe decoded value, or nil if the tag was Nil.
Clientcityrp.network.ReadIndexHeader() → boolean, integer?, integer?Source ☍

Reads an index header written by WriteIndexHeader in sv_send.lua: whether an entity index follows, the index itself if so, and the player's wire UserID if it is a player's. Shared by the Update and Resync receivers below so this wire shape is decoded in exactly one place -- see the matching WriteIndexHeader for why (AGENTS.md footgun #11: paired literals, or paired shapes, drift when edited independently).

Returns

  1. 1boolean
  2. 2integer?
  3. 3integer?Only for a player's index.
Sharedcityrp.network.ReadSignedComponent() → numberSource ☍

Reads one component written by WriteSignedComponent.

Returns

  1. numberThe decoded component.
Servercityrp.network.RecipientsContain(recipients, ply) → booleanSource ☍

Whether ply is a member of a resolved recipient value.

Parameters

Returns

  1. boolean
Sharedcityrp.network.Register(name) → NetVarSource ☍

Registers a new network variable, or returns the existing one if name is already registered. Must be called before the registry seals (on Initialize) -- see Seal below.

Parameters

  • namestringThe variable's name. Must be unique.

Returns

  1. NetVarThe (possibly just-created) NetVar, ready for chained configuration.
Clientcityrp.network.RequestResync(ent)Source ☍

Queues ent for resync, debounced to at most one request per frame regardless of how many entities become visible in that frame.

Parameters

Sharedcityrp.network.Seal()Source ☍

Seals the registry: assigns every var a stable numeric ID and locks out further registration. Only the server actually assigns IDs, by sorting registered names -- the client waits for the server's manifest to populate byId by name instead, so the two realms never need to agree on sort order or registration order. Safe to call more than once; later calls are no-ops.

Servercityrp.network.SendGlobalsAndLocal(ply, names, revoke)Source ☍

Sends every current Global value and ply's own LocalPlayer-scoped values in one no-index group. The only path by which a Global value is re-delivered.

Warning

LocalPlayer values skip the recipient check and cannot be revoked -- that scope is owner-only and its recipient mode is ignored everywhere. GetRevokedValue's substitute. Defaults to true; only the join bootstrap passes false.

Parameters

  • plyPlayer
  • namestable<string, boolean>?Only send these var names. nil sends everything.
  • revokeboolean?Whether a Global var failing its :Filter() check contributes
Servercityrp.network.SendGroups(ply, groups)Source ☍

Sends a batch of {ent, vars = {{netvar, value}, ...}} groups to one player as one or more cityrp.network.Resync messages, splitting on the byte threshold between groups. A non-batchable (custom-codec) var is never shared with any other entry -- it is always flushed into, and sent as, a message of its own -- so an undecodable custom value can only ever corrupt that one message, not a whole batch of unrelated vars riding alongside it.

Parameters

Servercityrp.network.SendManifest(ply)Source ☍

Sends the sealed registry as id -> name/scope/codec/arg. Sent once per player, on their first cityrp.network.Sync announce -- see MarkReady below. The ID width travels in the header so the two realms can never disagree about it, which is what keeps a load-order difference between them from corrupting every value the way it could in the plugin this library replaces. A Custom-coded var's real codecArg (the opt passed to its :Write()/:Read()) is whatever the registering plugin's own shared code chose -- not necessarily numeric, and not something the receiving client needs from the wire anyway, since decoding it already requires that client to have run the same local :Read(fn, opt) call. A placeholder 0 goes out instead of the real value so a non-numeric opt can never break net.WriteUInt here.

Parameters

Servercityrp.network.SendUpdate(netvar, ent, value)Source ☍

Sends a single var change. Resolves recipients before net.Start so an empty :Filter() result skips networking entirely instead of leaving a started message with nowhere to send. Reaches every currently-connected player for Broadcast/PVS/PAS/Omit, including ones who haven't finished their handshake yet -- deliberately: filtering the recipient list down to "ready" players would mean reimplementing PVS/PAS membership in Lua just to exclude a few joining players from an engine call that already does that natively. Instead cl_receive.lua discards any Update/Resync payload before its own manifest has arrived, which costs that player nothing: MarkReady sends a full bootstrap right after the manifest, so a live update missed during the join race is already reflected in the state that bootstrap sends moments later.

Parameters

Servercityrp.network.SetGlobal(name, value)Source ☍

Sets a Global-scoped networked value and, if it changed, broadcasts it (subject to :Filter()).

Parameters

  • namestringThe registered var name.
  • valueanyThe new value. nil clears it.
Sharedcityrp.network.ValidateClientOwned(netvar)Source ☍

Checks a :ClientOwned() var's constraints and clears the flag if it fails any, so the client setter is never generated rather than a var being writable in a shape nobody vetted.

Runs at seal, not inside :ClientOwned(): a chain sets its fields in whatever order it was written, so :ClientOwned():Bool():SetPlayer():Debounce(1) would see a default scope, a default codec and no debounce. :Predictable() defers its scope check for the same reason.

Parameters

  • netvarNetVarThe var to check. A no-op unless it called :ClientOwned().
Servercityrp.network.WaitForPlayer(ply, fn)Source ☍

Runs fn(ply) once ply's handshake has completed, or immediately if it already has.

Parameters

Servercityrp.network.WarnSuspectRegistrations()Source ☍

Warns once per var about a registration that configures cleanly but cannot do what it looks like it does. Called from Seal, so each warning fires once per map load rather than once per send.

Sharedcityrp.network.WireUserID(ply) → integerSource ☍

A player's UserID as a player index header carries it: modulo USERID_BITS, so both realms compare the same truncated value.

Parameters

Returns

  1. integer
Sharedcityrp.network.WriteAutoValue(value)Source ☍

Writes a value self-describingly: a codec tag, then the value via that codec. This is what backs both the Auto codec and every key/value inside a Table.

Parameters

  • valueanyThe value to write. nil writes only the tag.
Servercityrp.network.WriteIndexHeader(hasIndex, ent)Source ☍

Writes an index header: whether an entity index follows, and the index itself if so. Shared by every send path that needs this exact shape (SendGroups's per-group header and SendUpdate's per-message header) so the wire format for "does this carry an index" is defined once -- see the matching ReadIndexHeader in cl_receive.lua (AGENTS.md footgun #11).

A player entity's index is always within the engine's player-slot range, so MAX_PLAYER_BITS is enough to encode it -- narrower than the general ENTITY_INDEX_BITS (MAX_EDICT_BITS) every non-player entity needs. Which width applies can't be inferred from netvar.scope alone -- a Player-scoped and an Entity-scoped var can share the same group/index header when they target the same physical player entity (SendGroups groups by entity, not scope) -- so the leading isPlayer bool is checked against the entity itself, and travels on the wire since the reader doesn't have ent yet; it's what this index will construct.

A player's header also carries their UserID: snapshots can overtake net messages, so a value sent for a leaving player can land after a new player has taken the slot on the client.

Parameters

  • hasIndexboolean
  • entEntity?Required (and used) only when hasIndex is true.
Sharedcityrp.network.WriteSignedComponent(component)Source ☍

Writes one signed vector/angle component, choosing between a raw float and a compact signed integer depending on which the value actually needs. Emits its own leading flag bit. Values outside the 32-bit signed integer range are forced onto the float path -- GetSignedBits clamps to 32, which would otherwise silently truncate a huge whole-number component.

Parameters

  • componentnumberThe component to write.
Sharedcityrp.network.WriteVarEntry(netvar, value)Source ☍

Writes one var entry: [id][isNil][value?]. Used by the server's live Update and grouped Resync paths (sv_send.lua) and by the client's ClientSet send (cl_receive.lua).

Parameters

ClientrecieveLPlyVarUpdate(length, ply)Source ☍

Internal function, for when a player's Local Player Var is updated.

Parameters

  • lengthany
  • plyany
ClientrecieveNSVarBootstrap(length, svr)Source ☍

Internal function, for the batched spawn bootstrap of every player's NSVars. Reads (entity, key, type, value) entries until a continuation bit is false. Each entry has the exact same encoding as a single NSVar.Update, so this stays in lockstep with the server's batched send in sv_init.lua.

Parameters

  • lengthnumberThe length of the net message.
  • svrPlayer?An empty variable, to ensure this has been sent from the server.
ClientrecieveNSVarClean(length, svr)Source ☍

Internal function, for when a player's NSVar is updated.

Parameters

  • lengthany
  • svrany
ClientrecieveNSVarUpdate(length, svr)Source ☍

Parameters

  • lengthany
  • svrany

Tables

Sharedcityrp.network.codecsSource ☍

Codec definitions, indexed by NetCodecId. Each entry is {name, write, read, batchable}. write(value, arg) / read(arg) -- arg is the codec argument from the NetVar (bit width for Integer/UInteger, byte length for Data), ignored by fixed-shape codecs. batchable = false (currently only Custom) marks a codec that can't safely share a batched message, since an undecodable value must not corrupt any entry after it -- see sv_send.lua.

A read may return a second value, false, to declare the byte stream unsalvageable from there on -- only BoundedString does, on a length prefix above its registered maximum. DecodeEntry checks it with == false, since every other codec's second return is nil.

Sharedcityrp.network.ENTITY_LIKE_SCOPESSource ☍

Scopes whose value is stored on an entity and travels with an entity index on the wire, as opposed to Global (no entity at all) or LocalPlayer (never carries an index -- the recipient is implicit). SetVehicle()/SetWeapon() behave exactly like SetEntity() here; the only thing they change is :Accessor()'s target metatable. Consulted via IsEntityScope below rather than repeating this set as an ad hoc or-chain at every call site that cares -- adding a future metatable-specific scope (NPC, NextBot, ...) then only ever needs one line changed here.

Classes

SharedNetCodecIdSource ☍

Numeric codec IDs. Freely renumberable -- unlike the manifest-assigned NetVar IDs in sh_registry.lua (which travel between realms and must never desync), these are never sent or persisted; both realms assign them identically from this shared file at every boot. Player is inserted in the self-contained/fixed-argument block rather than appended so AUTO_TAG_MAX stays a simple contiguous bound.

SharedNetRecipientModeSource ☍

How a NetVar's updates choose their recipients.

ServerNetResyncEntrySource ☍

What one entity's queued resync covers: true every var, a name set only those, false every var with revokes suppressed. MergeQueueEntry combines them.

SharedNetScopeSource ☍

Where a NetVar's value lives and who it is sent to by default.

Fields

Clientcityrp.networkSource ☍
Clientcityrp.network.idBitsSource ☍

codecIds

Sharedcityrp.network.CODEC_ANGLESource ☍
Sharedcityrp.network.CODEC_AUTOSource ☍

Meta codec: the value's shape is written to the wire as a per-value tag instead of being fixed by the manifest. Never chosen by GetValueCodec as a nested Auto/Table entry's tag.

Sharedcityrp.network.CODEC_BITSource ☍

Raw single bit via net.WriteBit/net.ReadBit, returning 0/1 rather than a real boolean. Declared-only, like Integer/UInteger -- Auto already covers booleans via CODEC_BOOL.

Sharedcityrp.network.CODEC_BOOLSource ☍
Sharedcityrp.network.CODEC_BSTRINGSource ☍

Length-prefixed string, bounded to the maxLen its :String(maxLen) registration declared. Declared-only: Auto has no maxLen to infer, which is also why this sits above AUTO_TAG_MAX.

Sharedcityrp.network.CODEC_BYTESource ☍
Sharedcityrp.network.CODEC_COLORSource ☍
Sharedcityrp.network.CODEC_CUSTOMSource ☍

User-supplied :Write(fn, opt) / :Read(fn, opt). Cannot be described by the manifest, so vars using it are sent one per message rather than batched -- see sv_send.lua.

Sharedcityrp.network.CODEC_DATASource ☍
Sharedcityrp.network.CODEC_DOUBLESource ☍
Sharedcityrp.network.CODEC_ENTITYSource ☍
Sharedcityrp.network.CODEC_FLOATSource ☍
Sharedcityrp.network.CODEC_INTSource ☍
Sharedcityrp.network.CODEC_INTEGERSource ☍

Explicit bit-width signed integer, 1-32 bits. Declared-only; Auto always prefers the fixed Nibble/Byte/Short/Int tiers instead, so a var must call :Integer(bits) to get this codec.

Sharedcityrp.network.CODEC_MAXSource ☍
Sharedcityrp.network.CODEC_NIBBLESource ☍
Sharedcityrp.network.CODEC_NILSource ☍
Sharedcityrp.network.CODEC_NORMALSource ☍
Sharedcityrp.network.CODEC_PLAYERSource ☍

Narrower counterpart to CODEC_ENTITY for a value known to be a player: net.WritePlayer/ net.ReadPlayer size the index off MAX_PLAYER_BITS (the engine's own player-slot-count bound) instead of the wider MAX_EDICT_BITS every other entity needs. GetValueCodec picks this over CODEC_ENTITY automatically whenever the value actually is a player.

Sharedcityrp.network.CODEC_SHORTSource ☍
Sharedcityrp.network.CODEC_STRINGSource ☍
Sharedcityrp.network.CODEC_TABLESource ☍
Sharedcityrp.network.CODEC_UBYTESource ☍
Sharedcityrp.network.CODEC_UINTSource ☍
Sharedcityrp.network.CODEC_UINTEGERSource ☍
Sharedcityrp.network.CODEC_UNIBBLESource ☍
Sharedcityrp.network.CODEC_USHORTSource ☍
Sharedcityrp.network.CODEC_VECTORSource ☍

Scopes

Sharedcityrp.network.byIdSource ☍

Registered vars by their sealed numeric ID. Empty until Seal runs (server: immediately, from its own sort; client: incrementally, as manifest entries arrive -- see cl_receive.lua).

Sharedcityrp.network.ENTITY_INDEX_BITSSource ☍

Bits used to write/read an entity index on the wire for Entity/Player-scoped vars. MAX_EDICT_BITS is the engine's own answer to "how many bits does any entity index need" (what net.WriteEntity itself is sized on), so this is guaranteed correct for whatever the server's actual edict limit is, rather than a separately-guessed "safely large" literal that could drift from the real limit.

Sharedcityrp.network.NETVARSource ☍

A registered network variable, mid-configuration or sealed. Every field below is set through the chained builder methods; construct with cityrp.network.Register, never with setmetatable directly.

Sharedcityrp.network.RECIPIENT_BROADCASTSource ☍
Sharedcityrp.network.RECIPIENT_FILTERSource ☍
Sharedcityrp.network.RECIPIENT_OMITSource ☍
Sharedcityrp.network.RECIPIENT_PASSource ☍
Sharedcityrp.network.RECIPIENT_PVSSource ☍
Sharedcityrp.network.registrySource ☍

Registered vars by name. Populated by cityrp.network.Register, consumed by Seal.

Sharedcityrp.network.RESYNC_GROUP_OVERHEAD_BITSSource ☍

Approximate extra bits a mapped-index :Enum() (CODEC_CUSTOM) costs per resync versus a batchable one, assuming worst case: its own WriteIndexHeader plus the group/var/end framing bools SendGroups adds around a non-batchable entry -- see sv_send.lua. Deliberately a little above the literal ~20-bit tally, so a marginal bit saving isn't enough to justify losing batchability (see :Enum()).

Sharedcityrp.network.SCOPE_ENTITYSource ☍
Sharedcityrp.network.SCOPE_GLOBALSource ☍

Stored in the library, not on any entity; has no owning entity at all.

Sharedcityrp.network.SCOPE_LOCALPLAYERSource ☍

Stored on the owning player; sent only to that player, never broadcast.

Sharedcityrp.network.SCOPE_PLAYERSource ☍
Sharedcityrp.network.SCOPE_VEHICLESource ☍

Storage and wire format identical to SCOPE_ENTITY -- only :Accessor()'s generated methods differ, attaching to FindMetaTable("Vehicle") instead of FindMetaTable("Entity").

Sharedcityrp.network.SCOPE_WEAPONSource ☍
Sharedcityrp.network.sealedSource ☍

Whether the registry has sealed. Register after this point is an error.

Sharedcityrp.network.sortedIdsSource ☍

Every assigned ID, in order. Populated once by Seal (server only -- the client never assigns its own IDs) so repeat consumers like SendManifest and cityrp_network_dump don't each rebuild and sort this from byId on every call to a value that cannot change after sealing.

wireConstants

Sharedcityrp.network.CODEC_ARG_BITSSource ☍

Bits used to write a manifest entry's codec argument (bit width, byte length, etc).

Sharedcityrp.network.CODEC_BITSSource ☍

Bits used to write a NetCodecId value.

Sharedcityrp.network.globalsSource ☍

Global-scoped values, by name. Entity/Player/LocalPlayer-scoped values live on the entity itself instead -- see the Entity.__netvars field below.

Sharedcityrp.network.MANIFEST_COUNT_BITSSource ☍

Bits used to write the manifest's entry count.

Sharedcityrp.network.MANIFEST_IDBITS_FIELDSource ☍

Fixed-width wire format constants shared between sv_send.lua and cl_receive.lua. Defined once here, rather than as literals repeated on both realms, so the two can never drift apart -- see AGENTS.md footgun #11 (client/server-paired literals must be edited together). Bits used to write cityrp.network.idBits itself in the manifest header.

Sharedcityrp.network.RESYNC_COUNT_BITSSource ☍

Bits used to write how many entity indices a resync request contains.

Servercityrp.network.resyncQueuesSource ☍

Per-player resync queues: ply -> {[Entity] = NetResyncEntry}. Both axes are weak so a disconnect or an entity removal cleans itself up even if the explicit PlayerDisconnected/EntityRemoved hooks below somehow miss it (which, per AGENTS.md footgun #3, a third-party hook.Add on the same event returning non-nil first genuinely could) -- see GetQueue's note for why this is a plain weak-keyed set rather than an ordered array.

Sharedcityrp.network.SCOPE_BITSSource ☍

Bits used to write a NetScope value.

Sharedcityrp.network.USERID_BITSSource ☍

Bits used to write the UserID a player's index header carries. UserID only climbs, so the wire carries it modulo this width, through cityrp.network.WireUserID.

Servercityrp.network.waitQueueSource ☍

Callbacks waiting on a player's handshake to finish. WaitForPlayer queues here; cleared (and run) once that player's manifest and bootstrap have been sent.

Servercityrp_networkSource ☍
SharedNETTYPE_ANGLESource ☍
SharedNETTYPE_BITSource ☍
SharedNETTYPE_BOOLSource ☍
SharedNETTYPE_BYTESource ☍

Signed 8 bit.

SharedNETTYPE_COLORSource ☍
SharedNETTYPE_DATASource ☍
SharedNETTYPE_ENTSource ☍
SharedNETTYPE_FLOATSource ☍

32 bit floating point value.

SharedNETTYPE_INTSource ☍

Signed 32 bit.

SharedNETTYPE_LONGSource ☍

Signed 64 bit.

SharedNETTYPE_MAXSource ☍

Increment this value if you add additional types.

SharedNETTYPE_NIBBLESource ☍

Signed 4 bit.

SharedNETTYPE_NILSource ☍
SharedNETTYPE_NORMSource ☍
SharedNETTYPE_SHORTSource ☍

Signed 16 bit.

SharedNETTYPE_STRSource ☍
SharedNETTYPE_TABSource ☍
SharedNETTYPE_UBYTESource ☍

Unsigned 8 bit.

SharedNETTYPE_UINTSource ☍

Unsigned 32 bit.

SharedNETTYPE_ULONGSource ☍

Unsigned 64 bit.

SharedNETTYPE_UNIBBLESource ☍

Unsigned 4 bit.

SharedNETTYPE_USHORTSource ☍

Unsigned 16 bit.

SharedNETTYPE_UXLONGSource ☍

Unsigned 128 bit.

SharedNETTYPE_VECSource ☍
SharedNETTYPE_XLONGSource ☍

Signed 128 bit.

NetVar

27 functions · 42 fields Source ☍

A registered network variable, mid-configuration or sealed. Every field below is set through the chained builder methods; construct with cityrp.network.Register, never with setmetatable directly.

Functions

SharedNetVar:Accessor(name) → NetVarSource ☍

Generates Get<name>() (both realms) and Set<name>() (server only), attaching to the metatable that best matches this var's scope -- FindMetaTable("Player") for :SetPlayer()/ :SetLocalPlayer(), FindMetaTable("Vehicle")/FindMetaTable("Weapon") for those, and FindMetaTable("Entity") otherwise -- see sh_store.lua's GenerateAccessor for why that distinction exists.

Parameters

  • namestringSuffix for the generated method names.

Returns

  1. NetVarFor chaining.
SharedNetVar:AutoHook() → NetVarSource ☍

Shorthand for :SetHook() that derives the hook name from the var's own name, for the common case of not caring what it's called -- "CityRP.Network." .. name .. ".Changed", matching this codebase's existing CityRP.<Module>.<Event> hook naming (CityRP.DayNight.PeriodChanged, CityRP.Networking.Register, etc).

Returns

  1. NetVarFor chaining.
SharedNetVar:Broadcast() → NetVarSource ☍

Sends updates to every player (the default for every scope except LocalPlayer, which is always owner-only regardless of this setting).

Returns

  1. NetVarFor chaining.
SharedNetVar:ClientOwned() → NetVarSource ☍

Lets a client set this var on its own player: Set<Name>() appears on the client, applying locally then sending, and the server applies it through the ordinary SetNetVar path so recipient rules and the :Enum() validator still hold. cityrp.network.ClientSet is the same without an accessor.

What arrives is a claim, never a fact -- never gate permissions, economy or anti-cheat on one. See docs/networking.md.

Constraints are checked at seal, not here: a builder chain sets its fields in any order, so none of them exist yet. See ValidateClientOwned.

Returns

  1. NetVarFor chaining.
SharedNetVar:Data(maxLen) → NetVarSource ☍

Fixed-length byte string. Pads short values with \0 to exactly maxLen and costs that much regardless; for text use :String(maxLen) above.

Parameters

  • maxLenintegerByte length. Both realms must agree on this value; it also travels in the manifest.

Returns

  1. NetVarFor chaining.
SharedNetVar:Debounce(seconds, ceiling) → NetVarSource ☍

Coalesces sets to at most one change per seconds: a set in a quiet period dispatches immediately, one inside the window overwrites a single pending slot. The apply is debounced too, so server-side reads lag by up to seconds. ceiling reserves the shape for adaptive backoff without enabling it -- omitted, it equals seconds and the interval never moves. Required by :ClientOwned(). See docs/networking.md.

Parameters

  • secondsnumberMinimum seconds between dispatches. Must be positive.
  • ceilingnumber?Upper bound for adaptive backoff. Defaults to seconds, i.e. no escalation.

Returns

  1. NetVarFor chaining.
SharedNetVar:Enum(list) → NetVarSource ☍

Declares this var as an enum over list, a sequential (ipairs-ordered) array of its legal values. Picks between two wire strategies by comparing their actual bit cost:

  • Direct value (batchable): list is entirely integers. The value itself goes on the wire, sized to its min/max via :Integer/:UInteger -- signed only if min is negative. No offset from min is applied even when every value shares a large common magnitude (e.g. {100,101}) -- an offset would itself need a CODEC_CUSTOM closure, exactly the cost this path avoids.
  • Mapped index (not batchable): the value's index in list goes on the wire instead, via an auto-generated :Write()/:Read() pair sized to #list. Cheaper for a small set of large-magnitude or widely-spread values, at the cost of CODEC_CUSTOM -- never sharing a resync message with sibling vars on the same entity.

For an all-integer list, the mapped index is used only if it beats the direct-value encoding by more than RESYNC_GROUP_OVERHEAD_BITS. A list containing anything non-integer always uses the mapped index; there is no numeric value to size a direct encoding from.

Either way, Setting a value not present in list is rejected -- logged, not stored/sent -- by ApplyValue's validate check. nil (clearing the var) always bypasses this check.

Parameters

  • listany[]The enum's legal values, in wire-assignment order. Must be non-empty; a mapped-index list must also have no duplicates.

Returns

  1. NetVarFor chaining.
SharedNetVar:Filter(fn) → NetVarSource ☍

Sends updates only to whoever fn returns, and doubles as the authorization check used by resync and late-join sync -- see sv_send.lua. Keep fn cheap and side-effect free: it can run once per update and again per resync candidate.

Parameters

Returns

  1. NetVarFor chaining.
SharedNetVar:Integer(bits) → NetVarSource ☍

net.WriteInt/net.WriteUInt only accept 1-32 bits -- the plugin this library replaces declared 64- and 128-bit integer types that could never actually be written. :Long() below is the closest working replacement for those call sites, not a wider integer.

Parameters

  • bitsintegerBit width, 1-32.

Returns

  1. NetVarFor chaining.
SharedNetVar:Long() → NetVarSource ☍

Widest integer GLua numbers can actually represent exactly (2^53). An alias of :Double() -- there is no true 64-bit integer codec, because a Lua number cannot hold one losslessly regardless of how it is framed on the wire.

Returns

  1. NetVarFor chaining.
SharedNetVar:Predictable() → NetVarSource ☍

Allows client-side prediction: :Accessor()'s generated Set<Name>() becomes available on the CLIENT too, applying locally (storage + :SetHook() only -- never a network send, the client has no authority to send) instead of being server-only. A later confirmed value -- whether that same client's predicted action being confirmed, or an unrelated server-side change -- arrives through the normal decode path and overwrites the locally-applied one, correcting any drift.

Only meaningful for :SetLocalPlayer() -- a client predicting some other entity's state isn't coherent, so :Accessor() logs an error and skips generating the client setter on a scope mismatch rather than silently letting a broadcast/entity-scoped var be mutated client-side with nothing to correct it.

Returns

  1. NetVarFor chaining.
SharedNetVar:Read(readFn, opt) → NetVarSource ☍

Sets a custom deserializer to pair with :Write().

Parameters

  • readFnfun(arg: any):anyCalled with opt to read the value back.
  • optanyPassed through as arg; typically the same value given to :Write().

Returns

  1. NetVarFor chaining.
SharedNetVar:SendOmit(fn) → NetVarSource ☍

Sends updates to everyone except whoever fn returns (net.SendOmit).

Parameters

Returns

  1. NetVarFor chaining.
SharedNetVar:SendPAS() → NetVarSource ☍

Sends updates only to players who can potentially hear the entity's position (net.SendPAS). Same bandwidth-not-secrecy caveat as :SendPVS().

Returns

  1. NetVarFor chaining.
SharedNetVar:SendPVS() → NetVarSource ☍

Sends updates only to players who can potentially see the entity's position (net.SendPVS). Treated as a bandwidth filter, not a secrecy boundary: resync always includes a PVS var, because the client is asking precisely because the entity just entered its PVS. Use :Filter() for anything that must not reach a player at all.

Returns

  1. NetVarFor chaining.
SharedNetVar:SetDefault(value) → NetVarSource ☍

Sets the value Entity:GetNetVar/cityrp.network.GetGlobal returns before anything is set.

Parameters

  • valueanyThe default value.

Returns

  1. NetVarFor chaining.
SharedNetVar:SetEntity() → NetVarSource ☍

Scopes this var to a single entity (the default scope).

Returns

  1. NetVarFor chaining.
SharedNetVar:SetGlobal() → NetVarSource ☍

Scopes this var globally -- one value, no owning entity. Use cityrp.network.SetGlobal/GetGlobal rather than an entity method.

Returns

  1. NetVarFor chaining.
SharedNetVar:SetHook(hookName) → NetVarSource ☍

Runs hook.Run(hookName, ent, newValue, oldValue, predicted) on both realms whenever this var changes. predicted is true only for a client-side local apply from a :Predictable() var's client Set<Name>(); every other trigger (a normal server Set, or either realm decoding a confirmed value off the wire) passes nil.

Parameters

  • hookNamestringThe hook name to run.

Returns

  1. NetVarFor chaining.
SharedNetVar:SetLocalPlayer() → NetVarSource ☍

Scopes this var to a single owning player's private state. Never broadcast: sent only to the owner via net.Send(ply), regardless of any :Filter()/:SendPVS() call. Like :SetPlayer(), :Accessor() attaches to FindMetaTable("Player").

Returns

  1. NetVarFor chaining.
SharedNetVar:SetNoSync() → NetVarSource ☍

Excludes this var from join sync and resync -- it is only ever pushed on change. Use for fire-and-forget events rather than durable state; a client that was out of PVS during the push will never receive it.

Returns

  1. NetVarFor chaining.
SharedNetVar:SetPlayer() → NetVarSource ☍

Scopes this var to a player. Storage/wire format are identical to :SetEntity() -- a player is an entity -- but :Accessor() attaches to FindMetaTable("Player") rather than Entity's, so a same-named method Player's own metatable already defines natively can't shadow it.

Returns

  1. NetVarFor chaining.
SharedNetVar:SetVehicle() → NetVarSource ☍

Scopes this var to a vehicle. Storage/wire format identical to :SetEntity(); only :Accessor()'s target metatable (FindMetaTable("Vehicle")) differs -- see :SetPlayer().

Returns

  1. NetVarFor chaining.
SharedNetVar:SetWeapon() → NetVarSource ☍

Scopes this var to a weapon. Same rationale as :SetVehicle(), targeting FindMetaTable("Weapon") instead.

Returns

  1. NetVarFor chaining.
SharedNetVar:String(maxLen) → NetVarSource ☍

Text. With no argument, net.WriteString/net.ReadString -- null-terminated, so the writer picks the length. With maxLen, a length prefix sized to maxLen then exactly that many bytes: no padding, and the read length comes from this registration rather than the wire, which is why it is the only string form :ClientOwned() accepts. Over-length is logged either way, never silently dropped (sh_codecs.lua). maxLen counts bytes, so truncation can split a character.

Parameters

  • maxLeninteger?Maximum byte length, 1 to (2 ^ CODEC_ARG_BITS) - 1. Omit for the unbounded form.

Returns

  1. NetVarFor chaining.
SharedNetVar:UInteger(bits) → NetVarSource ☍

Unsigned counterpart to :Integer(bits). Same 1-32 bit range and the same fallback on misuse.

Parameters

  • bitsintegerBit width, 1-32.

Returns

  1. NetVarFor chaining.
SharedNetVar:Write(writeFn, opt) → NetVarSource ☍

Sets a custom serializer, bypassing the built-in codec table. Because the manifest cannot describe an arbitrary function, vars using this are sent one per message rather than batched -- see sv_send.lua.

Parameters

  • writeFnfun(value: any, arg: any)Called with the value (and opt) to write it.
  • optanyPassed through to writeFn/the matching :Read() call as arg.

Returns

  1. NetVarFor chaining.

Fields

SharedNetVar.__indexSource ☍

A registered network variable, mid-configuration or sealed. Every field below is set through the chained builder methods; construct with cityrp.network.Register, never with setmetatable directly.

SharedNetVar.accessorNameSource ☍

If set, generates Get<Name>()/Set<Name>() (setter server-only unless predictable) on the metatable :Accessor()'s scope maps to -- see sh_store.lua's GenerateAccessor.

SharedNetVar.AngleSource ☍
SharedNetVar.AutoSource ☍

Explicitly requests the self-describing codec (the default when no codec method is called).

SharedNetVar.BitSource ☍
SharedNetVar.BoolSource ☍
SharedNetVar.ByteSource ☍
SharedNetVar.clientOwnedSource ☍

If true, :Accessor() generates a client-side Set<Name>() that applies locally and sends to the server -- see :ClientOwned(). Cleared at seal if the var fails ValidateClientOwned.

SharedNetVar.codecSource ☍

The wire codec. CODEC_AUTO unless a codec constructor was called.

SharedNetVar.codecArgSource ☍

Codec-specific argument (bit width for Integer/UInteger, byte length for Data).

SharedNetVar.ColorSource ☍
SharedNetVar.customReadSource ☍

Set by :Read(); used when codec == CODEC_CUSTOM.

SharedNetVar.customWriteSource ☍

Set by :Write(); used when codec == CODEC_CUSTOM.

SharedNetVar.debounceCeilingSource ☍

Upper bound for adaptive backoff. Equal to debounceInterval unless :Debounce() was given a second argument, in which case escalation is enabled.

SharedNetVar.debounceIntervalSource ☍

Minimum seconds between dispatches, and the floor an adaptive interval resets to -- see :Debounce().

SharedNetVar.defaultSource ☍

The value Entity:GetNetVar returns before anything has been set.

SharedNetVar.DoubleSource ☍

64-bit IEEE double via net.WriteDouble. Also the target for :Long() -- see below.

SharedNetVar.EntitySource ☍
SharedNetVar.enumListSource ☍

The list passed to :Enum(), kept for introspection (cityrp_network_dump).

SharedNetVar.FloatSource ☍
SharedNetVar.hasDefaultSource ☍

Whether :SetDefault() was called.

SharedNetVar.hookNameSource ☍

Hook run on change, both realms: hook.Run(hookName, ent, newValue, oldValue, predicted).

SharedNetVar.idSource ☍

Assigned at seal. nil before the registry seals.

SharedNetVar.IntSource ☍
SharedNetVar.nameSource ☍

The registered name. Unique; this is what travels in the manifest.

SharedNetVar.NibbleSource ☍
SharedNetVar.NilSource ☍
SharedNetVar.NormalSource ☍

Compact vector codec for components known to stay within +/-1 (e.g. a direction). A component outside that range still encodes correctly, just without the compact path's benefit.

SharedNetVar.noSyncSource ☍

If true, excluded from join sync and resync -- push-only.

SharedNetVar.PlayerSource ☍

Narrower than :Entity() for a value known to always be a player: sizes the index off MAX_PLAYER_BITS instead of the wider MAX_EDICT_BITS every other entity needs. :Auto() already picks this over :Entity() on its own whenever the value actually is a player, so this constructor is for declaring the narrower shape explicitly up front, not required for the saving.

SharedNetVar.predictableSource ☍

If true, :Accessor() also generates a client-side Set<Name>() that applies locally (storage + hook only, no network send) instead of being server-only -- see :Predictable().

SharedNetVar.recipientFnSource ☍

Backing function for :SendOmit()/:Filter().

SharedNetVar.recipientModeSource ☍

How a NetVar's updates choose their recipients.

SharedNetVar.scopeSource ☍

Where the value is stored and who receives it by default.

SharedNetVar.ShortSource ☍
SharedNetVar.TableSource ☍
SharedNetVar.UByteSource ☍
SharedNetVar.UIntSource ☍
SharedNetVar.UNibbleSource ☍
SharedNetVar.UShortSource ☍
SharedNetVar.validateSource ☍

Optional value validator, set by :Enum(). Checked by

SharedNetVar.VectorSource ☍