Matchmaking 服务端SDK接入指南
Matchmaking 服务端SDK接入指南
服务端SDK 运行在 multiverse dedicated server 上,需要与 multiverse sdk 搭配使用
Sync 不支持集成 Matchmaking 服务端 SDK
服务端SDK用于获取匹配到该房间的玩家数据,以及在运行过程中根据需要开启和关闭回填匹配。 目前支持的语言和平台如下:
- Unity
- C#
- Go
操作指南
Unity
参考 Launcher 教程,安装 Launcher 后,关联 UOS APP, 开启 Matchmaking Server 服务并安装 Matchmaking Server SDK。
注意 :请务必确认在进行后续教程之前,已经成功完成了 Launcher 教程的安装步骤,否则可能导致后续接入无法顺利进行。
public interface IMatchmakingServerSDK
{
/// <summary>
/// 获取当前房间配置以及匹配到房间的所有玩家数据(适用于按需模式)
/// 该方法用于房间启动后获取一次当前房间的基本配置和玩家数据,若开启BackFill,后续推荐使用GetNewPlayersFromBackFill获取最新的玩家数据
/// 可通过 multiverse local sdk server进行本地测试拿到mock 数据
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
/// <returns>当前房间配置和玩家数据</returns>
public Task<Match> GetMatchInfo();
/// <summary>
/// 舰队模式下需通过该方法Watch server, 直到game server为allocated状态,方能获取到匹配玩家数据
/// 当拿到匹配数据后,会自动停止Watch
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
public void WatchMatchInfo(MatchmakingServerSDK.WatchMatchInfoCallback callback);
/// <summary>
/// 为当前房间开启BackFill以匹配到更多的玩家
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <param name="teams"> 当前房间所有的玩家数据
/// (匹配系统将结合当前房间配置需要的玩家人数信息与此处传递的当前房间玩家人数信息推算出该房间还需要多少玩家)</param>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
public Task StartBackFill(List<Team> teams);
/// <summary>
/// 停止BackFill
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
/// <returns>停止时间点该房间所有的玩家数据</returns>
public Task<List<Team>> StopBackFill();
/// <summary>
/// BackFill进行过程中,可通过该方法拿到最新的玩家数据
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
/// <returns>最新的玩家数据</returns>
public Task<List<Team>> GetNewPlayersFromBackFill();
/// <summary>
/// Watch BackFill, 持续拿到最新抓取到房间的玩家数据,当抓取玩家数量达到当前配置最大人数时,会自动停止Watch
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
public void WatchBackFill(Action<List<Team>> callback);
/// <summary>
/// 判断当前房间是否开启BackFill
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
/// <returns>是否开启BackFill</returns>
public Task<bool> IsBackFillStarted();
}try
{
// mv 和 mm sdk 初始化
await MultiverseSDK.Initialize();
await MatchmakingServerSDK.Initialize();
}
catch (MatchmakingServerSDKException ex)
{
Debug.LogErrorFormat("Failed to initialize mm server sdk. {0}", ex);
throw;
}
catch (MultiverseSDKException ex)
{
Debug.LogErrorFormat("Failed to initialize mv sdk. {0}", ex);
throw;
}
try
{
// 获取匹配到该房间到玩家数据
var matchInfo = await MatchmakingServerSDK.Instance.GetMatchInfo();
Debug.Log($"match: {JsonConvert.SerializeObject(matchInfo)}");
// 标记 game server 为ready
await MultiverseSDK.Instance.ReadyAsync();
// 检测匹配系统是否已为该房间开启匹配回填
// (在网页上允许自动匹配回填后,匹配时若人数已达到配置最大人数,则也不会为房间开启匹配回填,
// 仅当在网页上允许自动匹配回填,且匹配时人数不足配置最大人数,但是达到配置最少人数时,会创建房间并为该房间开启匹配回填)
var isBackFillStarted = await MatchmakingServerSDK.Instance.IsBackFillStarted();
if (isBackFillStarted)
{
// 若开启了匹配回填, 通过WatchBackFill持续拿到最新的玩家数据
// (teams 变量为本局游戏全部玩家数据,不是新增玩家数据)
MatchmakingServerSDK.Instance.WatchBackFill(teams =>
{
Debug.Log($"current player data: {JsonConvert.SerializeObject(teams)}");
});
}
else
{
// 一段时间过后,检测到有玩家下线后, 主动开启BackFill 以抓取新的玩家
await Task.Delay(TimeSpan.FromSeconds(30));
// teams 为当前房间所有的玩家数据, 匹配系统将结合当前房间配置需要的玩家人数信息与
// 此处传递的当前房间玩家人数信息推算出该房间还需要多少玩家
var teams = <List<Team>>;
await MatchmakingServerSDK.Instance.StartBackFill(teams);
MatchmakingServerSDK.Instance.WatchBackFill(teams =>
{
Debug.Log($"current player data: {JsonConvert.SerializeObject(teams)}");
});
// 一段时间过后, 停止BackFill
await Task.Delay(TimeSpan.FromSeconds(30));
await MatchmakingServerSDK.Instance.StopBackFill();
}
await Task.Delay(TimeSpan.FromSeconds(120));
// 关闭 server
await MultiverseSDK.Instance.ShutdownAsync();
}
catch (MatchmakingServerSDKException ex)
{
Debug.LogErrorFormat("Failed to call mm server sdk method. {0}", ex);
throw;
}
catch (MultiverseSDKException ex)
{
Debug.LogErrorFormat("Failed to call mv sdk method. {0}", ex);
throw;
}try
{
// mv 和 mm sdk 初始化
await MultiverseSDK.Initialize();
await MatchmakingServerSDK.Initialize();
}
catch (MatchmakingServerSDKException ex)
{
Debug.LogErrorFormat("Failed to call mm server sdk method. {0}", ex);
throw;
}
catch (MultiverseSDKException ex)
{
Debug.LogErrorFormat("Failed to call mv sdk method. {0}", ex);
throw;
}
try
{
// 标记 game server 为ready
await MultiverseSDK.Instance.ReadyAsync();
// 舰队模式时因服务器是预先开启的,启动时可能并无法获取到匹配数据
// 因此需使用 WatchMatchInfo 方法 watch server状态
// 当server 变为 allocated状态时,即可获取到匹配数据,WatchMatchInfo也将自动停止
MatchmakingServerSDK.Instance.WatchMatchInfo(async(match) =>
{
Debug.Log($"match: {JsonConvert.SerializeObject(match)}");
// 检测匹配系统是否已为该房间开启匹配回填
// (在网页上允许自动匹配回填后,匹配时若人数已达到配置最大人数,则也不会为房间开启匹配回填,
// 仅当开启匹配回填, 且匹配时人数不足配置最大人数,但是达到配置最少人数时,为创建房间并为该房间开启匹配回填)
var isBackFillStarted = await MatchmakingServerSDK.Instance.IsBackFillStarted();
if (isBackFillStarted)
{
MatchmakingServerSDK.Instance.WatchBackFill(teams =>
{
Debug.Log($"cur player data: {JsonConvert.SerializeObject(teams)}");
});
}
await Task.Delay(TimeSpan.FromSeconds(120));
// 关闭 server
await MultiverseSDK.Instance.ShutdownAsync();
});
}
catch (MatchmakingServerSDKException ex)
{
Debug.LogErrorFormat("Failed to call mm server sdk method. {0}", ex);
throw;
}
catch (MultiverseSDKException ex)
{
Debug.LogErrorFormat("Failed to call mv sdk method. {0}", ex);
throw;
}C#
此 SDK 包(UOS.Matchmaking.Server.SDK)已经发布在 NuGet 上,您可以直接 下载 或者通过命令行的 .NET CLI 安装。
dotnet add package UOS.Matchmaking.Server.SDKpublic interface IMatchmakingServerSDK
{
/// <summary>
/// 获取当前房间配置以及匹配到房间的所有玩家数据(适用于按需模式)
/// 该方法用于房间启动后获取一次当前房间的基本配置和玩家数据,若开启BackFill,后续推荐使用GetNewPlayersFromBackFill获取最新的玩家数据
/// 可通过 multiverse local sdk server进行本地测试拿到mock 数据
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
/// <returns>当前房间配置和玩家数据</returns>
public Task<Match> GetMatchInfo();
/// <summary>
/// 舰队模式下需通过该方法Watch server, 直到game server为allocated状态,方能获取到匹配玩家数据
/// 当拿到匹配数据后,会自动停止Watch
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
public void WatchMatchInfo(Action<Match> callback));
/// <summary>
/// 为当前房间开启BackFill以匹配到更多的玩家
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <param name="teams"> 当前房间所有的玩家数据
/// (匹配系统将结合当前房间配置需要的玩家人数信息与此处传递的当前房间玩家人数信息推算出该房间还需要多少玩家)</param>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
public Task StartBackFill(List<Team> teams);
/// <summary>
/// 停止BackFill
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
/// <returns>停止时间点该房间所有的玩家数据</returns>
public Task<List<Team>> StopBackFill();
/// <summary>
/// BackFill进行过程中,可通过该方法拿到最新的玩家数据
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
/// <returns>最新的玩家数据</returns>
public Task<List<Team>> GetNewPlayersFromBackFill();
/// <summary>
/// Watch BackFill, 持续拿到最新抓取到房间的玩家数据,当抓取玩家数量达到当前配置最大人数时,会自动停止Watch
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
public void WatchBackFill(Action<List<Team>> callback);
/// <summary>
/// 判断当前房间是否开启BackFill
/// 不可通过 multiverse local sdk server进行本地测试
/// </summary>
/// <exception cref="MatchmakingServerSDKException"> 可查看具体errCode 和 message判断异常原因</exception>
/// <returns>是否开启BackFill</returns>
public Task<bool> IsBackFillStarted();
}try
{
// mv 和 mm sdk 初始化
await MultiverseSDK.Initialize();
await MatchmakingServerSDK.Initialize();
}
catch (MatchmakingServerSDKException ex)
{
Console.WriteLine("Failed to initialize mm server sdk. {0}", ex);
throw;
}
catch (MultiverseSDKException ex)
{
Console.WriteLine("Failed to initialize mv server sdk. {0}", ex);
throw;
}
try
{
// 获取匹配到该房间到玩家数据
var matchInfo = await MatchmakingServerSDK.Instance.GetMatchInfo();
Console.WriteLine($"match: {JsonConvert.SerializeObject(matchInfo)}");
// 标记 game server 为ready
await MultiverseSDK.Instance.ReadyAsync();
// 检测匹配系统是否已为该房间开启匹配回填
// (在网页上允许自动匹配回填后,匹配时若人数已达到配置最大人数,则也不会为房间开启匹配回填,
// 仅当在网页上允许自动匹配回填,且匹配时人数不足配置最大人数,但是达到配置最少人数时,会创建房间并为该房间开启匹配回填)
var isBackFillStarted = await MatchmakingServerSDK.Instance.IsBackFillStarted();
if (isBackFillStarted)
{
// 若开启了匹配回填, 通过WatchBackFill持续拿到最新的玩家数据
// (teams 变量为本局游戏全部玩家数据,不是新增玩家数据)
MatchmakingServerSDK.Instance.WatchBackFill(teams =>
{
Console.WriteLine($"current player data: {JsonConvert.SerializeObject(teams)}");
});
}
else
{
// 一段时间过后,检测到有玩家下线后, 主动开启BackFill 以抓取新的玩家
await Task.Delay(TimeSpan.FromSeconds(30));
// teams 为当前房间所有的玩家数据, 匹配系统将结合当前房间配置需要的玩家人数信息与
// 此处传递的当前房间玩家人数信息推算出该房间还需要多少玩家
var teams = <new List<Team>{}>;
await MatchmakingServerSDK.Instance.StartBackFill(teams);
MatchmakingServerSDK.Instance.WatchBackFill(newTeams =>
{
Console.WriteLine($"current player data: {JsonConvert.SerializeObject(newTeams)}");
});
// 一段时间过后, 停止BackFill
await Task.Delay(TimeSpan.FromSeconds(30));
await MatchmakingServerSDK.Instance.StopBackFill();
}
await Task.Delay(TimeSpan.FromSeconds(120));
// 关闭 server
await MultiverseSDK.Instance.ShutdownAsync();
}
catch (MatchmakingServerSDKException ex)
{
Console.WriteLine("Failed to call mm server sdk method. {0}", ex);
throw;
}
catch (MultiverseSDKException ex)
{
Console.WriteLine("Failed to call mv sdk method. {0}",ex);
throw;
}try
{
// mv 和 mm sdk 初始化
await MultiverseSDK.Initialize();
await MatchmakingServerSDK.Initialize();
}
catch (MatchmakingServerSDKException ex)
{
Console.WriteLine("Failed to initialize mm server sdk. {0}", ex);
throw;
}
catch (MultiverseSDKException ex)
{
Console.WriteLine("Failed to initialize mv server sdk. {0}", ex);
throw;
}
try
{
// 标记 game server 为ready
await MultiverseSDK.Instance.ReadyAsync();
// 舰队模式时因服务器是预先开启的,启动时可能并无法获取到匹配数据
// 因此需使用 WatchMatchInfo 方法 watch server状态
// 当server 变为 allocated状态时,即可获取到匹配数据,WatchMatchInfo也将自动停止
MatchmakingServerSDK.Instance.WatchMatchInfo(async(match) =>
{
Console.WriteLine($"match: {JsonConvert.SerializeObject(match)}");
// 检测匹配系统是否已为该房间开启匹配回填
// (在网页上允许自动匹配回填后,匹配时若人数已达到配置最大人数,则也不会为房间开启匹配回填,
// 仅当开启匹配回填, 且匹配时人数不足配置最大人数,但是达到配置最少人数时,为创建房间并为该房间开启匹配回填)
var isBackFillStarted = await MatchmakingServerSDK.Instance.IsBackFillStarted();
if (isBackFillStarted)
{
MatchmakingServerSDK.Instance.WatchBackFill(teams =>
{
Console.WriteLine($"cur player data: {JsonConvert.SerializeObject(teams)}");
});
}
await Task.Delay(TimeSpan.FromSeconds(120));
// 关闭 server
await MultiverseSDK.Instance.ShutdownAsync();
});
}
catch (MatchmakingServerSDKException ex)
{
Console.WriteLine("Failed to call mm server sdk method. {0}", ex);
throw;
}
catch (MultiverseSDKException ex)
{
Console.WriteLine("Failed to call mv sdk method. {0}", ex);
throw;
}Go
go get cnb.cool/unity/uos/matchmaking-server-sdk@v1.1.0type MatchmakingServerSDK interface {
// GetMatchInfo 获取匹配数据,包括AppId, RoomId 和玩家数据等信息(适用于按需模式)
// 该方法用于房间启动后获取一次当前房间的基本配置和玩家数据,若开启BackFill,后续推荐使用GetNewPlayersFromBackFill获取最新的玩家数据
// 可通过 multiverse local sdk server进行本地测试拿到mock 数据
GetMatchInfo() (*Match, error)
// WatchMatchInfo 舰队模式下需通过该方法Watch server, 直到game server为allocated状态,方能获取到匹配玩家数据
// 当拿到匹配数据后,会自动停止Watch
// 不可通过 multiverse local sdk server进行本地测试
WatchMatchInfo(MatchInfoCallback) error
// StartBackFill 为当前房间开启BackFill以匹配到更多的玩家
// 不可通过 multiverse local sdk server进行本地测试
StartBackFill([]*Team) error
// StopBackFill 停止BackFill,会返回停止时间点该房间所有的玩家数据
// 不可通过 multiverse local sdk server进行本地测试
StopBackFill() ([]*Team, error)
// GetNewPlayersFromBackFill BackFill进行过程中,可通过该方法拿到最新的玩家数据
// 不可通过 multiverse local sdk server进行本地测试
GetNewPlayersFromBackFill() ([]*Team, error)
// WatchBackFill BackFill进行过程中, 可通过该方法Watch BackFill, 持续拿到最新抓取到房间的玩家数据
// 当抓取玩家数量达到当前配置最大人数时,会自动停止Watch
// 不可通过 multiverse local sdk server进行本地测试
WatchBackFill(BackFillCallback) error
// IsBackFillStarted 判断当前是否开启BackFill
// 不可通过 multiverse local sdk server进行本地测试
IsBackFillStarted() (bool, error)
}package main
import (
mvSdk "cnb.cool/unity/uos/multiverse-sdk/go"
mmSdk "cnb.cool/unity/uos/matchmaking-server-sdk/go"
"github.com/sirupsen/logrus"
"time"
)
var (
logger = logrus.WithField("component", "matchmaking-server-sdk")
)
func main() {
// 获取 mv sdk instance
mvInstance, err := mvSdk.GetInstance()
if err != nil {
logger.WithError(err).Fatalf("failed to create mv instance")
}
// 获取 mm sdk instance
mmInstance, err := mmSdk.GetInstance()
if err != nil {
logger.WithError(err).Fatalf("failed to create mm instance")
}
// 获取匹配到该房间到玩家数据
match, err := mmInstance.GetMatchInfo()
if err != nil {
logger.WithError(err).Fatalf("failed to get matchInfo")
}
logger.Println(match)
// 标记 game server 为ready
if err = mvInstance.Ready(); err != nil {
logger.WithError(err).Fatalf("failed to call ready method")
}
logger.Info("server is ready")
// 检测匹配系统是否已为该房间开启匹配回填
// (在网页上允许自动匹配回填后,匹配时若人数已达到配置最大人数,则也不会为房间开启匹配回填,
// 仅当在网页上允许自动匹配回填,且匹配时人数不足配置最大人数,但是达到配置最少人数时,会创建房间并为该房间开启匹配回填)
isBackFillStarted, err := mmSdk.IsBackFillStarted()
if err != nil {
logger.WithError(err).Fatalf("failed to check IsBackFillStarted")
}
if isBackFillStarted {
// 若开启了匹配回填, 通过WatchBackFill持续拿到最新的玩家数据
// (teams 变量为本局游戏全部玩家数据,不是新增玩家数据)
if err = mmInstance.WatchBackFill(func(teams []*mmSdk.Team) {
logger.Println(teams)
}); err != nil {
logger.WithError(err).Fatalf("failed to watch backFill")
}
} else {
// 一段时间过后,检测到有玩家下线后, 主动开启BackFill 以抓取新的玩家
time.Sleep(30 * time.Second)
// teams 为当前房间所有的玩家数据, 匹配系统将结合当前房间配置需要的玩家人数信息与
// 此处传递的当前房间玩家人数信息推算出该房间还需要多少玩家
teams := <[]*mmSdk.Team{}>
if err = mmInstance.StartBackFill(teams); err != nil {
logger.WithError(err).Fatalf("failed to start backFill")
}
logger.Info("started backFill")
if err = mmInstance.WatchBackFill(func(teams []*mmSdk.Team) {
logger.Println(teams)
}); err != nil {
logger.WithError(err).Fatalf("failed to watch backFill")
}
// 一段时间过后, 停止BackFill
time.Sleep(30 * time.Second)
teams, err = mmInstance.StopBackFill()
if err != nil {
logger.WithError(err).Fatalf("failed to stop backFill")
}
// 停止BackFill 会返回停止时间节点该房间的玩家数据
logger.Println(teams)
}
time.Sleep(60 * time.Second)
// 关闭 server
if err = mvInstance.Shutdown(); err != nil {
logger.WithError(err).Fatalf("failed to call shutdown method")
}
}package main
import (
mvSdk "cnb.cool/unity/uos/multiverse-sdk/go"
mmSdk "cnb.cool/unity/uos/matchmaking-server-sdk/go"
"github.com/sirupsen/logrus"
"time"
)
var (
logger = logrus.WithField("component", "matchmaking-server-sdk")
)
func main() {
// 获取 mv sdk instance
mvInstance, err := mvSdk.GetInstance()
if err != nil {
logger.WithError(err).Fatalf("failed to create mv instance")
}
// 获取 mm sdk instance
mmInstance, err := mmSdk.GetInstance()
if err != nil {
logger.WithError(err).Fatalf("failed to create mm instance")
}
// 标记 game server 为ready
if err = mvInstance.Ready(); err != nil {
logger.WithError(err).Fatalf("failed to call ready method")
}
logger.Info("server is ready")
// 舰队模式时因服务器是预先开启的,启动时可能并无法获取到匹配数据
// 因此需使用 WatchMatchInfo 方法 watch server状态
// 当server 变为 allocated状态时,即可获取到匹配数据,WatchMatchInfo也将自动停止
if err = mmInstance.WatchMatchInfo(func(match *mmSdk.Match) {
logger.Println(match)
// 检测匹配系统是否已为该房间开启匹配回填
// (在网页上允许自动匹配回填后,匹配时若人数已达到配置最大人数,则也不会为房间开启匹配回填,
// 仅当开启匹配回填, 且匹配时人数不足配置最大人数,但是达到配置最少人数时,为创建房间并为该房间开启匹配回填)
isBackFillStarted, err := mmSdk.IsBackFillStarted()
if err != nil {
logger.WithError(err).Fatalf("failed to check IsBackFillStarted")
}
if isBackFillStarted {
if err = mmInstance.WatchBackFill(func(teams []*mmSdk.Team) {
logger.Println(teams)
}); err != nil {
logger.WithError(err).Fatalf("failed to watch backFill")
}
} else {
logger.Info("backFill is not started")
}
time.Sleep(60 * time.Second)
// 关闭 server
if err = mvInstance.Shutdown(); err != nil {
logger.WithError(err).Fatalf("failed to call shutdown method")
}
}); err != nil {
logger.WithError(err).Fatalf("failed to watch matchInfo")
}
for {
time.Sleep(time.Second)
}
}