---
title: "Extend RpcCallback - s&box library"
description: "Async RPC Callback for s&box – Call server methods with await, [RpcCallback] handles the round-trip automatically."
canonical: "https://sbox.watch/libraries/extend/extend_rpc/"
generated_at: "2026-07-22T23:17:23.213Z"
---

# Extend RpcCallback

Async RPC Callback for s&box – Call server methods with await, \[RpcCallback\] handles the round-trip automatically.

- Type: library
- Ident: extend.extend_rpc
- Creator: extend
- Canonical: https://sbox.watch/libraries/extend/extend_rpc/
- Markdown: https://sbox.watch/libraries/extend/extend_rpc.md
- sbox.game: https://sbox.game/extend/extend_rpc/
- Generated: 2026-07-22T23:17:23.213Z

## Stats

- 24h momentum: +0
- Terry score: --
- Favorites: 0
- Upvotes: 0
- Downvotes: 0
- Updated: Aug 29, 2025
- Created: Aug 27, 2025
- Size: 50.5 KB
- Files: 27
- Tags: 

## Description

\# Extend RPC Library

A library for \*\*s&box\*\* that makes it easy to send RPC calls and receive \*\*asynchronous callbacks\*\*.
It simplifies \*\*client ↔ server\*\* communication while taking full advantage of async/await.

\#\# 🚀 Features
- Asynchronous RPC calls
- Receive callbacks using \`async/await\`
- Simplified error and timeout handling
- Supported return types:
 ✅ \*\*Primitives\*\* (int, float, bool, string, etc.)
 ✅ \*\*structs\*\*
 ✅ \*\*records\*\*
 ✅ \*\*List<>\*\*

\#\# 📦 Installation
Clone or download this repository and add its content directly into your \*\*s&box\*\* project at Libraries/extend.extend\_rpc folder.

\#\# 🛠 Basic Usage Example
\[RpcCallback\]
public async Task<int> Compute(int a, int b)
{
 return a + b;
}

protected override void OnStart()
{
 Task.RunInThreadAsync(async () =>
 {
 var result = await Compute(1, 4);
 Log.Info("Result is: " + result);
 });
}
\#\# 🛠 List Usage Example
\[RpcCallback\]
public async Task<List<int>> Compute(int a, int b)
{
 return \[a + b\];
}

protected override void OnStart()
{
 Task.RunInThreadAsync(async () =>
 {
 var results = await Compute(1, 4);
 Log.Info("Result is: " + string.Join(", ", results));
 });
}

\#\# 🛠 Using a struct as return type
protected override void OnStart()
{
 Task.RunInThreadAsync(async () =>
 {
 var stats = await GetPlayerStats("Player\_42");
 Log.Info($"Kills: {stats.Kills}, Deaths: {stats.Deaths}, Accuracy: {stats.Accuracy}");
 });
}

\[RpcCallback\]
public async Task<PlayerStats> GetPlayerStats(string playerId)
{
 // Simulate database fetch
 await Task.Delay(100);

 return new PlayerStats
 {
 Kills = 10,
 Deaths = 3,
 Accuracy = 0.75f
 };
}

public struct PlayerStats
{
 public int Kills { get; set; }
 public int Deaths { get; set; }
 public float Accuracy { get; set; }
}

\#\# 🛠 Using a record as return type
// Primary constructors are not supported yet when serializing / deserializing in s&box
public record InventoryItem( string Name, int Quantity );

// Instead, use this way
public record InventoryItem
{
 public string Name { get; set; }
 public int Quantity { get; set; }

 public InventoryItem( string name, int quantity )
 {
 Name = name;
 Quantity = quantity;
 }
}

\[RpcCallback\]
public async Task<InventoryItem> GetInventoryItem(string itemId)
{
 await Task.Delay(50);

 return new InventoryItem("Health Potion", 5);
}

protected override void OnStart()
{
 Task.RunInThreadAsync(async () =>
 {
 var item = await GetInventoryItem("potion\_health");
 Log.Info($"Item: {item.Name}, Quantity: {item.Quantity}");
 });
}\#\# ⚙️ How it works

Functions marked with the \[RpcCallback\] attribute are \*\*wrapped automatically\*\*.
When you call them:

1. The wrapper sends an \*\*RPC to the server\*\*.
2. The server executes the \*\*original method\*\*.
3. The return value is captured.
4. Another \*\*RPC is sent back to the caller (client)\*\* with the result.

This makes it possible to await the call just like a local async function.

The caller receives the result as a Task<T> (async/await).

Any return type is supported as long as it’s a primitive, a struct, or a record that can be serialized.

Collections (List<T>, arrays, etc.) are also supported if T is a valid type.

The library handles serialization, network transport, and automatic value return.

Configurable timeout (default: 5s).

\#\# 📖 Quick Reference

\[RpcCallback\] → Marks a method as an asynchronous RPC.

Task.RunInThreadAsync(...) → Runs a task outside the main game thread.

Exceptions are automatically propagated back to the caller.

\#\# 🤝 Contributing

Pull Requests are welcome!
Please follow C\# best practices. Unit tests is optional.


