Func Stateful 客户端SDK接入指南
Func Stateful 客户端SDK接入指南
通过集成此 SDK 客户端可以按照 Func Stateful 配置的策略获得一个可用的服务器信息;也可以查询所有可用服务器后,自行选择连接到指定的服务器。
1. 安装配置 UOS Launcher
参考 Launcher 教程,安装 Launcher 后,关联 UOS APP, 开启 Func Stateful 服务并安装 Func Stateful SDK。
注意: 请务必确认在进行后续教程之前,已经成功完成了 Launcher 教程的安装步骤,否则可能导致后续接入无法顺利进行。
2. 核心类&接口
public interface IFuncStatefulSDK
{
#region ListServersAsync
/// <summary>
/// 获得所有运行中的服务器信息.
/// 通过 name, tags 或其组合进行筛选
/// </summary>
/// <returns>包含 Server 信息的数组</returns>
/// <exception cref="Exception">包含失败信息</exception>
public Task<Server[]> ListServersAsync();
public Task<Server[]> ListServersAsync(string name);
public Task<Server[]> ListServersAsync(IReadOnlyCollection<string> tags);
public Task<Server[]> ListServersAsync(string name, IReadOnlyCollection<string> tags);
public Task<Server[]> ListServersByProfileIdAsync(string profileId);
public Task<Server[]> ListServersByProfileIdAsync(string name, string profileId);
public Task<Server[]> ListServersByProfileIdAsync(IReadOnlyCollection<string> tags, string profileId);
public Task<Server[]> ListServersByProfileIdAsync(string name, IReadOnlyCollection<string> tags, string profileId);
#endregion
#region ConnectAsync
/// <summary>
/// 调用此方法来获得一个可用服务器的 Endpoint 信息.
/// 通过 name, tags, properties 或其组合进行筛选
/// </summary>
/// <param name="playerId">玩家的 Id</param>
/// <returns>服务器的 Endpoint 信息</returns>
/// <exception cref="Exception">包含失败信息的JSON字符串</exception>
public Task<Endpoint> ConnectAsync(string playerId);
public Task<Endpoint> ConnectAsync(string playerId, string name);
public Task<Endpoint> ConnectAsync(string playerId, IReadOnlyCollection<string> tags);
public Task<Endpoint> ConnectAsync(string playerId, Dictionary<string, string> properties);
public Task<Endpoint> ConnectAsync(string playerId, string name, IReadOnlyCollection<string> tags);
public Task<Endpoint> ConnectAsync(string playerId, string name, Dictionary<string, string> properties);
public Task<Endpoint> ConnectAsync(string playerId, IReadOnlyCollection<string> tags,
Dictionary<string, string> properties);
public Task<Endpoint> ConnectAsync(string playerId, string name, IReadOnlyCollection<string> tags,
Dictionary<string, string> properties);
public Task<Endpoint> ConnectByProfileIdAsync(string playerId, string profileId);
public Task<Endpoint> ConnectByProfileIdAsync(string playerId, string name, string profileId);
public Task<Endpoint> ConnectByProfileIdAsync(string playerId, IReadOnlyCollection<string> tags, string profileId);
public Task<Endpoint> ConnectByProfileIdAsync(string playerId, Dictionary<string, string> properties, string profileId);
public Task<Endpoint> ConnectByProfileIdAsync(string playerId, string name, IReadOnlyCollection<string> tags, string profileId);
public Task<Endpoint> ConnectByProfileIdAsync(string playerId, string name, Dictionary<string, string> properties, string profileId);
public Task<Endpoint> ConnectByProfileIdAsync(string playerId, IReadOnlyCollection<string> tags,
Dictionary<string, string> properties, string profileId);
public Task<Endpoint> ConnectByProfileIdAsync(string playerId, string name, IReadOnlyCollection<string> tags,
Dictionary<string, string> properties, string profileId);
/// <summary>
/// 连接到指定服务器, 并获取 Endpoint 信息
/// </summary>
/// <param name="playerId">玩家的 Id</param>
/// <param name="serverId">服务器的 Id</param>
/// <returns>服务器的 Endpoint 信息</returns>
/// <exception cref="Exception">包含失败信息的JSON字符串</exception>
public Task<Endpoint> ConnectWithServerIdAsync(string playerId, string serverId);
public Task<Endpoint> ConnectWithServerIdByProfileIdAsync(string playerId, string serverId, string profileId);
#endregion
#region DisconnectAsync
/// <summary>
/// 玩家登出后调用, 通知 Func Stateful 此 Player 已经下线; (建议在 Server 端调用 disconnect 方法)
/// </summary>
/// <param name="playerId">玩家的 Id</param>
/// <exception cref="Exception">包含失败信息的JSON字符串</exception>
public Task DisconnectAsync(string playerId);
public Task DisconnectByProfileIdAsync(string playerId, string profiledId);
#endregion
}3. 集成示例
初始化SDK
IFuncStatefulSDK sdk;
try
{
FuncStatefulSDK.Initialize();
sdk = FuncStatefulSDK.Instance;
}
catch (Exception e)
{
Debug.Log($"failed to initSdk, exception: {e.Message}");
throw;
}客户端流程 A

// 随机生成一个用户 Id
_playerId = Guid.NewGuid().ToString();
Debug.Log($"generate a random playerId: {_playerId}");
// 调用 connect 获得一个可用的服务器
Endpoint endpoint;
try
{
// 根据设置分配策略随机返回
endpoint = await sdk.ConnectAsync(_playerId);
// 通过服务器名称进行筛选
// endpoint = await sdk.ConnectAsync(_playerId, "竞技场服务器");
// 通过标签进行筛选
// endpoint = await sdk.ConnectAsync(_playerId, new[] { "最强王者", "超凡大师" });
// 通过自定义变量进行筛选
// endpoint = await sdk.ConnectAsync(_playerId, new Dictionary<string, string>
// {
// {"region", "跨5"},
// });
// 通过组合名称、标签和自定义变量进行筛选
// ...
}
catch (Exception e)
{
Debug.Log($"failed to call connect, exception: {e.Message}");
throw;
}
// 客户端根据 ip:port 连接到指定的服务器
// ...
var connectEndpoint = $"appId: {endpoint.appId}; ip: {endpoint.ip};";
connectEndpoint = endpoint.ports.Aggregate(connectEndpoint,
(current, pt) => current + $" {pt.port}/{pt.protocol}/{pt.name} ");
Debug.Log("connect info: " + connectEndpoint);
// 客户端退出前, 调用 disconnect (推荐在服务端调用)
// 服务端发现客户端下线后,在服务端调用
try
{
await sdk.DisconnectAsync(_playerId);
}
catch (Exception e)
{
Debug.Log($"failed to call disconnect, exception: {e.Message}");
throw;
}客户端流程 B

// 随机生成一个用户 Id
_playerId = Guid.NewGuid().ToString();
Debug.Log($"generate a random playerId: {_playerId}");
Server[] servers;
try
{
// 查询所有可用服务器信息
servers = await sdk.ListServersAsync();
// 通过服务器名称进行筛选
// servers = await sdk.ListServersAsync("竞技场服务器");
// 通过标签进行筛选
// servers = await sdk.ListServersAsync(new[] { "最强王者", "超凡大师"});
// 组合服务器名称和标签进行筛选
// servers = await sdk.ListServersAsync("竞技场服务器", new[] { "最强王者" });
}
catch (Exception e)
{
Debug.Log($"fail to list servers, exception: {e.Message}");
throw;
}
// 查看返回的服务器信息
Debug.Log($"list servers get {servers.Length} servers;");
for (var i = 0; i < servers.Length; i++)
{
var ep = $"appId: {servers[i].endpoint.appId}; ip: {servers[i].endpoint.ip};";
ep = servers[i].endpoint.ports.Aggregate(ep,
(current, pt) => current + $" {pt.port}/{pt.protocol}/{pt.name} ");
Debug.Log($"server-{i}: serverId:{servers[i].serverId}, name:{servers[i].name}, ");
}
// 指定一个返回的服务器 Id, 调用 connect 连接到到次服务器
Endpoint endpoint;
try
{
var connectedServerId = servers[0].serverId;
var profileId = servers[0].profileId;
endpoint = await sdk.ConnectWithServerIdAsync(_playerId, connectedServerId, profileId);
}
catch (Exception e)
{
Debug.Log($"failed to call connect, exception: {e.Message}");
throw;
}
// 客户端根据 ip:port 连接到指定的服务器
// ...
var connectEndpoint = $"appId: {endpoint.appId}; ip: {endpoint.ip};";
connectEndpoint = endpoint.ports.Aggregate(connectEndpoint,
(current, pt) => current + $" {pt.port}/{pt.protocol}/{pt.name} ");
Debug.Log("connect info: " + connectEndpoint);
// 客户端退出前, 调用 disconnect (推荐在服务端调用)
// 服务端发现客户端下线后,在服务端调用
try
{
await sdk.DisconnectAsync(_playerId);
}
catch (Exception e)
{
Debug.Log($"failed to call disconnect, exception: {e.Message}");
throw;
}多 App 接入
IFuncStatefulSDK sdk1;
IFuncStatefulSDK sdk2;
try
{
// 该初始化方式将默认关联 UOS Launcher 中填写的 UOS APP
FuncStatefulSDK.Initialize();
sdk1 = FuncStatefulSDK.Instance;
// 当需要关联非 UOS Launcher 中填写的 UOS APP 时使用该方法
// 将 appId 和 appSecret 替换成实际值
sdk2 = await FuncStatefulSDK.NewInstance("<appId>", "<appSecret>");
}
catch (Exception e)
{
Debug.Log($"failed to initSdk, exception: {e.Message}");
throw;
}
// 后续流程可以参考客户端流程 A 或 B, 分别调用 sdk1 和 sdk2 实现多 App 接入