Generated RpcClient
ULinkRPC.Analyzers generates a project-specific RpcClient facade through a Roslyn Source Generator. It is not a fixed type from a NuGet package; it is generated during the current project compilation.
Construction
The generated type lives in the configured generated namespace, which is usually Rpc.Generated by default.
using Rpc.Generated;
var options = new RpcClientOptions(transport, serializer);
await using var client = new RpcClient(options);
If contracts include notification contracts, the generator also emits RpcClient.RpcNotificationBindings:
var notifications = new RpcClient.RpcNotificationBindings();
notifications.Add(new PlayerNotifications());
await using var client = new RpcClient(options, notifications);
Each notification receiver type can be registered only once. Registering the same notification contract more than once throws InvalidOperationException.
Lifecycle
RpcClient internally holds ULinkRPC.Client.RpcClientRuntime.
ConnectAsync(CancellationToken)binds notifications and starts the runtime.DisposeAsync()disposes the runtime, stops background loops, fails pending requests, and disposes the transport.Disconnecteddirectly forwards the runtime disconnect event.Optionsreturns theRpcClientOptionspassed at construction.
The same generated client instance must not be reused as an automatic reconnect object. After disconnecting or disposing, the application layer should dispose the current instance and create a new transport, serializer, options object, and generated client.
Api Facade
client.Api lazily creates a RpcApi. By default, RpcApi generates groups from the first segment of the service namespace and properties from service interfaces.
For example, Game.Rpc.Contracts.IPlayerService usually generates an entry point similar to:
var player = client.Api.Game.Player;
var reply = await player.LoginAsync(request, ct);
Long-lived projects can lock these names explicitly on the service contract:
[RpcService(1, ApiGroup = "Game", ApiName = "Player")]
public interface IPlayerService
{
}
Generated API names must be unique within each group. If two services would generate the same client.Api.<group>.<name> path, generation fails so the contract can choose an explicit ApiGroup or ApiName.
Notification Base Class
When notification contracts exist, the generator emits an inheritable base class for each notification interface. The base class implements the notification interface and generates each notification method as an empty virtual method, so business code can override only the methods it needs.
Notification handlers follow the same threading model as RpcClientRuntime: handlers run on the runtime notification loop and are not automatically marshaled back to the Unity, Tuanjie, or Godot main thread. If you need to update engine objects, hand the work off to main-thread logic.
Generation
Generated clients, service proxies, notification binders, and server binders are generated by ULinkRPC.Analyzers at compile time:
- Server projects generate server binders, notification proxies,
AllServicesBinder, and the binder assembly attribute. - Godot, Unity, Unity CN, and Tuanjie clients generate the
RpcClientfacade, service clients, and notification binders.
These types update at compile time as Shared contracts change. Application code should maintain contracts, service implementations, and client business logic. Do not hand-edit generated output.