Using generated code
The C# schema-generated code consists of two main parts: data classes and component classes.
Data classes
Data classes are used to represent data at rest and correspond to the schemalang type
definitions.
A data class is generated for each type defined in the schema, with fields corresponding to each field in the schema definition.
Data representation
- Strings are represented as UTF-8 encoded
string
members. Make sure to use this same encoding when updating a component. list<T>
fields are represented as aImprobable.Collections.List<T>
of the repeated type. This type is very similar toSystem.Generic.List<T>
.map<Key, Value>
fields are represented asImprobable.Collections.Map<Key, Value>
. This type is very similar toSystem.Generic.Dictionary<Key, Value>
.option<T>
fields are represented asImprobable.Collections.Option<T>
.
All of the Improbable.Collections
equivalents provide structural equality checks.
Component classes
Component classes correspond to schemalang component
definitions, and contain metadata and classes
for sending and receiving component data (updates, command requests and command responses).
For each component, we generate:
a metaclass implementing
Improbable.Worker.IComponentMetaclass
.These metaclasses are used when referring to specific components when using the API - every generic type parameter
C
expects a metaclass argument.an
Update
class nested inside the metaclass.This has an optional field for each field in the component (since it represents a diff).
command metaclasses nested inside the metaclass, as
SomeComponent.Commands.SomeCommand
.These work in a similar way to component metaclasses, but for command-related functions.
Example generated code
Given the following simple schema (in package example;
):
type StatusEffect {
string name = 1;
int32 multiplier = 2;
}
component Creature {
id = 12345;
int32 health = 1;
list<StatusEffect> effects = 2;
}
The generated code will contain the Creature
IComponentMetaclass
with Data
and and Update
classes. Moreover, there will be a StatusEffect
struct
representing the
StatusEffect
type, and CreatureData
type for the (auto-generated) underlying type of the component.
You can use the Create()
method of the data types to obtain a default instance whose fields are initialised
with zeroes, empty strings, empty collections or other default instances as appropriate. Enum fields
will be initialised with the first value listed in the schema.
We strongly recommend using either the static Create()
method or the full constructor that takes an initial
value for every field. This is because the default constructor of the generated data types will leave some
fields initialized with null
, which is not valid.
Here are some ways that these classes can be used with the API:
public static void GeneratedCodeExamples(Connection connection)
{
var dispatcher = new Dispatcher();
dispatcher.OnAuthorityChange<Creature>(op => {
switch (op.Authority)
{
case Authority.Authoritative:
// We were granted authority over the status component. Send an update.
var update = new Creature.Update();
update.SetHealth(10);
connection.SendComponentUpdate(op.EntityId, update);
break;
case Authority.AuthorityLossImminent:
// About to lose authority.
break;
case Authority.NotAuthoritative:
// Authority was revoked.
break;
}
});
dispatcher.OnComponentUpdate<Creature>(op =>
{
// Again, use the extension method Get() to get the concrete type of update.
var update = op.Update.Get();
if (update.effects.HasValue)
{
// The `effects` field was updated.
}
});
}
In order to compile this example, you would have to wrap the Examples
method in a class.