Extending SDK Components
Last updated: 16 July 2026
This mechanism allows developers to extend component behaviour without modifying the component itself.
When you need to extend a component's functionality, PlayServ uses handlers. A handler lets you attach custom logic to a component method without rewriting the component itself.
When to extend SDK components
Use component extending when you need to:
- add custom rules around an existing component method — for example, allow or deny a join
- introduce game-specific behaviour into a standard component flow
- attach multiple independent handlers to the same extension point
Extend a component method
Example: extend the Join method for a group component.
// Extend the Join method
PlayServ.Server.Group("Game")
.ExtendMethod(PlayServ.Server.Group.Join, user => {
return false; // abort pipeline
})
// sugar
.DoJoin(user => { ... });
When the component executes the Join operation, the pipeline runs as follows:
The component starts
The component begins its processing cycle for the Join operation.
Handlers are executed
Registered handlers run in order, as a middleware chain.
A handler returns false
If any handler returns false, the pipeline stops immediately.
The operation is cancelled
The Join operation is cancelled and no further handlers run.
A handler can abort the middleware pipeline. Returning false stops further processing and cancels the operation.
How handlers are executed
A handler is executed as part of a middleware pipeline. This is what makes it possible to register more than one handler for the same extension point and still keep each handler implementation minimal.
Works across components
This approach applies to any component. Some components reserve specific RPC methods in their API and explicitly mark them as extendable. These methods are used in the component's lifecycle and are invoked by the component itself under certain conditions.
Some components expose explicit extension points as reserved RPC methods. These methods are part of the component lifecycle and are invoked by the component itself under specific conditions.
Example: controlled Join for a match room
Scenario: you have a match room that players can enter. The client uses the standard Join() call, but the server must decide whether joining is allowed. Typical gameplay rules include:
- the match has already started
- the room is full
- the user is banned from this mode
- the user does not meet rank or level requirements
You do not replace the Groups component or introduce a separate custom RPC method. Instead, you extend the standard Join method and apply server-side rules while keeping the client call unchanged.
Flow:
Client calls Join()
The client calls Join() on the target group.
Server runs the Join pipeline
The server executes the Join middleware pipeline, running each registered rule handler.
A rule fails
If any rule fails, the handler returns false and the pipeline is aborted — the join is rejected.
All rules pass
If every rule passes, the join is allowed and the handler completes.
Client:
await PlayServ.Group("Game").Join();
Server:
PlayServ.Server.Group("Game")
.ExtendMethod(PlayServ.Server.Group.Join, user => {
// Gameplay checks
bool roomIsFull = false;
bool matchAlreadyStarted = false;
bool userIsBanned = false;
bool requirementsNotMet = false;
if (roomIsFull || matchAlreadyStarted || userIsBanned || requirementsNotMet)
return false; // abort pipeline -> Join is rejected
return true; // allow Join to proceed
})
// sugar: the Join handler itself
.DoJoin(user => {
// Optional: actions on successful join
// e.g. attach user to match context
return true; // accept user into the group
// return false; // reject
});
Next steps
- Groups — how extendable methods fit into the full groups component lifecycle (
Joinis one example) - RPC & Server-side Game Logic — extension points are tied to RPC methods and handler execution