Skip to main content

Data Mutation & Model Extending

Last updated: 16 July 2026

This page covers two related topics: mutating game data through Update() and Delete(), and extending models with domain behaviour as named RPC methods.


Data mutation​

When to use​

Use mutation when you need to persist changes to game data as state:

  • updating fields on objects returned by a query and saving them with Update()
  • applying a single inline update operation with Update(handler)
  • removing objects included in a selection with Delete()
info

This is the standard path when the outcome must be a stored state change that can later be retrieved and, where applicable, observed through the data layer.

Baseline rule​

PlayServ does not require special techniques to modify data. The flow is:

  1. retrieve data
  2. change fields using standard setters
  3. call Update()
note

Whether a write is allowed depends on the caller and the table. By default a game client cannot write, and on a table owned by a player a client only writes its own rows. See Access Control if an Update() or Delete() is refused.

Update a selection​

Select a set of objects, modify them, then persist the changes.

var players = PlayServ.Model<Player>()
.Where(player => player.Level >= 10);

// modify every selected object
players.Map(p => {
p.Coins += 100;
});

// modify a single object in the selection
players[0].Coins += 500;

// persist changes
players.Update();

Update with a handler​

You can also update using a single Update(...) call with an inline handler.

players.Update(p => {
p.Coins += 100;
});

Delete​

To delete all objects included in the selection:

players.Delete();

Model extending​

When to use​

Use model extending when you need to attach domain behaviour to a model type and execute it as an RPC method:

  • defining behaviour as an extension method on a model via the RPC handler API
  • invoking that behaviour from client code on a retrieved entity — for example, player.Shoot(...)
info

Model extending allows gameplay operations to be expressed as an explicit action — a method — executed through the RPC handler pipeline, including abort behaviour.

How it works​

A model can be extended with custom RPC methods tied to an entity type — for example, NPC spawns, player shoots, chest opens. When these RPC methods execute, the model data acts as their context.

This path is appropriate when the operation represents a named action associated with an entity type, rather than a direct field update.

Clientplayer.Shoot(...)RPC callServer handlerDoShoot — model as contextreturn truereturn falsePipeline proceedsaction is appliedPipeline abortsaction is rejected

Server: define an extension method

PlayServ.Server.Model<Player>()
.DoShoot(vector => {
return false; // abort pipeline
});

Client: call the extension method

var player = await PlayServ.GetPlayer(playerId);
player.Shoot(vector3d);

Next steps​