Table of Contents

Class CommandBuilder<T>

Namespace
Typhon.Engine
Assembly
Typhon.Engine.dll

Declares a command type: what it is called on the wire, how fast a session may send it, who may send it, and what it must look like to be worth decoding.

public sealed class CommandBuilder<T> where T : unmanaged

Type Parameters

T

The command type: an unmanaged struct, declared in an assembly a client can reference without the engine.

Inheritance
CommandBuilder<T>
Inherited Members

Remarks

Every public instance field of T travels, whether or not the declaration mentions it (01-model § 7: "fields default to their raw type"). Field<TField>(Expression<Func<T, TField>>, Codec, string) OVERRIDES how one of them travels; Ignore<TField>(Expression<Func<T, TField>>) keeps one off the wire. Silence declares nothing, deliberately: a command whose author forgot a field would otherwise arrive zeroed on a server that had no way to say so.

The struct's layout does not define the wire. Fields travel in the catalog's canonical order and are decoded one at a time, so reordering members of the C# struct is not a silent protocol break — which is exactly what canonicalization exists to prevent.

The rate limit is enforced on the transport thread, before the ring, so a client flooding a command type costs the tick nothing.

Methods

Coalesce(CommandCoalesce)

Sets how arrivals are delivered into a tick.

public CommandBuilder<T> Coalesce(CommandCoalesce mode)

Parameters

mode CommandCoalesce

Queued, or newest-per-session.

Returns

CommandBuilder<T>

This builder.

Field<TField>(Expression<Func<T, TField>>, Codec, string)

Overrides how one of the command's fields travels — a position quantized over the grid, a reference sent as a netId — instead of its raw type.

public CommandBuilder<T> Field<TField>(Expression<Func<T, TField>> selector, Codec codec, string name = null)

Parameters

selector Expression<Func<T, TField>>

Selects the field.

codec Codec

How the value travels.

name string

The wire name. null takes the field's own name.

Returns

CommandBuilder<T>

This builder.

Type Parameters

TField

The field's type.

Remarks

It is an override, not the thing that makes the field travel: a field nobody mentions travels under the codec its CLR type defaults to. What this buys is the cases a type cannot imply — a pair of floats that is a world position, a u32 that is a netId, a range that deserves 8 bits instead of 32.

Exceptions

InvalidOperationException

The selector names something that is not a public instance field of T, or that field is already declared or ignored.

Ignore<TField>(Expression<Func<T, TField>>)

Keeps one of the command's fields off the wire: scratch space, a field the server fills in, a value the client has no business sending.

public CommandBuilder<T> Ignore<TField>(Expression<Func<T, TField>> selector)

Parameters

selector Expression<Func<T, TField>>

Selects the field.

Returns

CommandBuilder<T>

This builder.

Type Parameters

TField

The field's type.

Remarks

It takes a verb because silence must not mean "not replicated". Every other field travels by default, so leaving one out of the declaration is indistinguishable from forgetting it — and the failure that produces is a field that arrives zeroed for ever, discovered by a player. Saying so costs one line and makes the omission reviewable.

Exceptions

InvalidOperationException

The selector names something that is not a public instance field of T, or that field already carries a Field<TField>(Expression<Func<T, TField>>, Codec, string) declaration.

Name(string)

Overrides the wire name, which is the type's own name by default.

public CommandBuilder<T> Name(string name)

Parameters

name string

The wire name.

Returns

CommandBuilder<T>

This builder.

Precheck(CommandPrecheck<T>)

Attaches the syntactic pre-check run before the command enters the tick.

public CommandBuilder<T> Precheck(CommandPrecheck<T> precheck)

Parameters

precheck CommandPrecheck<T>

The check.

Returns

CommandBuilder<T>

This builder.

Remarks

The adapter is captured here, where T is a compile-time argument, because the ingress path that calls the check holds only a Type and raw payload bytes. Reaching a typed delegate from a Type would take MakeGenericType over a value type, which is the AOT blocker class #409 names; a static lambda here is one cached instance per command type and no reflection at all.

Rate(int, int)

The per-session token bucket for this command type.

public CommandBuilder<T> Rate(int perSecond, int burst)

Parameters

perSecond int

Sustained rate, above zero.

burst int

Bucket depth — how many may arrive at once after a quiet period. At least perSecond.

Returns

CommandBuilder<T>

This builder.

Roles(params SessionRole[])

The roles allowed to send this command. Declaring none accepts every role.

public CommandBuilder<T> Roles(params SessionRole[] roles)

Parameters

roles SessionRole[]

The accepted roles.

Returns

CommandBuilder<T>

This builder.