房间管理API接入指南
房间管理API接入指南
开启服务
房间管理功能需要在Multiverse的「项目设置」中房间管理模块开启
授权
Basic Authorization (推荐服务器端程序使用)
使用 Basic Authorization 来进行鉴权 (推荐服务器端程序使用). 步骤如下:
在 UOS 网站上获取当前需要使用的 UOS APP 的 AppId 和 AppServiceSecret
注:此处 AppId 和 AppServiceSecret,可在 UOS 网站上获取


在请求任意 API 的 Request Header 中增加 Header:
- Authorization: Basic base64(appId:appServiceSecret)
示例代码
C## C# 使用示例 - Basic 授权方式 using System; using System.Collections.Generic; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; class Program { private static string GetBasicAuthorization(string appId, string appServiceSecret) { string credentials = $"{appId}:{appServiceSecret}"; byte[] credentialsBytes = Encoding.UTF8.GetBytes(credentials); string encodedCredentials = Convert.ToBase64String(credentialsBytes); return $"Basic {encodedCredentials}"; } public static async Task Main(string[] args) { using (HttpClient client = new HttpClient()) { // 使用项目的 APP_ID, APP_SERVICE_SECRET 获取 headers client.DefaultRequestHeaders.Add("Authorization", GetBasicAuthorization(APP_ID, APP_SERVICE_SECRET)); // 以get方法为例,替换 url 为你需要请求的 url HttpResponseMessage response = await client.GetAsync(url); response.EnsureSuccessStatusCode(); // 其他处理…… } } }Python# Python 使用示例 - Basic 授权方式 import base64 import requests def get_basic_authorization(app_id, app_service_secret): """ 获取basic auth的Header """ credentials = f'{app_id}:{app_service_secret}' encoded_credentials = base64.b64encode(credentials.encode("utf-8")).decode("utf-8") return {'Authorization': f'Basic {encoded_credentials}'} # 使用 APP_ID, APP_SERVICE_SECRET 获取Basic Token Header headers = get_basic_authorization(APP_ID, APP_SERVICE_SECRET) # 以get方法为例,替换 url 为你需要请求的 url response = requests.get(url, headers=headers)JavaScript// JavaScript 使用示例 - Basic 授权方式 const axios = require('axios'); function getBasicAuthorization(appId, appServiceSecret) { /** 获取 basic auth 的 Header */ const credentials = `${appId}:${appServiceSecret}`; const encodedCredentials = btoa(credentials); return { 'Authorization': `Basic ${encodedCredentials}` }; } // 使用 APP_ID, APP_SERVICE_SECRET 获取Basic Token Header const headers = getBasicAuthorization(APP_ID, APP_SERVICE_SECRET); // 以get方法为例,替换 url 为你需要请求的 url const response = await axios.get(url, { headers });Go// Go 使用示例 - Basic 授权方式 import ( "bytes" "encoding/base64" "encoding/json" "fmt" "io" "net/http" ) func GetBasicAuthorization(appID, appServiceSecret string) string { credentials := appID + ":" + appServiceSecret encodedCredentials := base64.StdEncoding.EncodeToString([]byte(credentials)) return "Basic " + encodedCredentials } func main() { // 以get方法为例,替换 url 为你需要请求的 url req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } // 使用 APP_ID, APP_SERVICE_SECRET 获取Basic Token Header req.Header.Set("Authorization", GetBasicAuthorization(APP_ID, APP_SERVICE_SECRET)) client := &http.Client{} response, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // ……其他处理 }
Nonce Authorization (推荐客户端程序使用)
使用 Nonce Authorization 来进行鉴权 (推荐客户端程序使用)。步骤如下:
在 UOS 网站上获取当前需要使用的 UOS APP 的 AppId 和 AppSecret
注:此处 AppId 和 AppSecret,可在 UOS 网站上获取


在请求任意 Sync API 的 Request Header 中增加如下 Header:
- X-TIMESTAMP: 当前时间戳
- X-NONCE: 随机生成的UUID
- X-APPID: 当前需要使用的 UOS APP 的 AppId
- Authorization: nonce hexadecimal(sha256(appId + ":" + appSecret + ":" + X-TIMESTAMP + ":" + X-NONCE))
示例代码:
C## C# 使用示例 - Nonce 授权方式 using System; using System.Collections.Generic; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; class Program { private static Dictionary<string, string GetNonceAuthorization(string appId, string appSecret) { string nonce = Guid.NewGuid().ToString(); long timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); string signString = $"{appId}:{appSecret}:{timestamp}:{nonce}"; byte[] signBytes = Encoding.UTF8.GetBytes(signString); using (SHA256 sha256 = SHA256.Create()) { byte[] hashBytes = sha256.ComputeHash(signBytes); string token = BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); return new Dictionary<string, string { { "X-APPID", appId }, { "X-TIMESTAMP", timestamp.ToString() }, { "X-NONCE", nonce }, { "Authorization", $"nonce {token}" } }; } } public static async Task Main(string[] args) { using (HttpClient client = new HttpClient()) { // 使用项目的 APP_ID, APP_SECRET 获取 headers var headers = GetNonceAuthorization(APP_ID, APP_SECRET); foreach (var header in headers) { client.DefaultRequestHeaders.Add(header.Key, header.Value); } // 以get方法为例,替换 url 为你需要请求的 url HttpResponseMessage response = await client.GetAsync(url); // 其他处理…… } } }Python# Python 使用示例 - Nonce 授权方式 import hashlib import time import uuid import binascii import requests def get_nonce_authorization(app_id, app_secret): """生成 nonce 授权 Headers""" nonce = str(uuid.uuid4()) timestamp = int(time.time()) calculated_check_sum = hashlib.sha256(f'{app_id}:{app_secret}:{timestamp}:{nonce}'.encode()).digest() token = binascii.hexlify(calculated_check_sum).decode() headers = { 'X-APPID': app_id, 'X-TIMESTAMP': str(timestamp), 'X-NONCE': nonce, 'Authorization': f'nonce {token}', 'Content-Type': 'application/json' } return headers # 使用项目的 APP_ID, APP_SECRET 获取 headers headers = get_nonce_authorization(APP_ID, APP_SECRET) # 替换 url 为你需要请求的 url response = requests.get(url, headers=headers)JavaScript// JavaScript - Nonce 授权方式 const axios = require('axios'); function getNonceAuthorization(appId, appSecret) { const nonce = crypto.randomUUID(); const timestamp = Math.floor(Date.now() / 1000); const signString = `${appId}:${appSecret}:${timestamp}:${nonce}`; const hash = crypto.createHash('sha256').update(signString).digest('hex'); return { 'X-APPID': appId, 'X-TIMESTAMP': timestamp.toString(), 'X-NONCE': nonce, 'Authorization': `nonce ${hash}` }; } // 使用 APP_ID, APP_SECRET 获取Nonce Token Header const headers = getNonceAuthorization(APP_ID, APP_SECRET); // 以get方法为例,替换 url 为你需要请求的 url const response = await axios.get(url, { headers });
使用示例
房间状态
| Status | 描述 |
|---|---|
| SERVER_ALLOCATED | 已成功分配服务器(房间创建成功的默认状态),该状态仅表示 Multiverse 服务器分配成功 |
| READY | Multiverse 内游戏服务器已完全准备就绪,该状态下玩家可以加入房间 |
| RUNNING | 房间处于运行中,该状态下玩家无法加入房间 |
| ALLOCATION_FAILED | 分配服务器失败(房间分配失败的状态) |
| CLOSED | 房间已关闭,服务器已销毁 |
调用流程
可参考下方流程在 Multiverse 服务中集成房间管理的相关功能:
- 在 游戏客户端/游戏大厅 调用 「创建房间」
- 房间创建成功后可在 Multiverse 服务端SDK中调用 GetServerInfoAsync 方法获取房间ID
- 房主调用 「加入房间」 进行预加入房间
- Multiverse Server 等待房主加入服务器后, 调用 「确认房间加入」 确认房主加入成功
- Multiverse Server 程序等房主加入成功以及服务器程序初始化成功后,调用 「更新房间状态」 将房间状态更新成已就绪("READY")
- 游戏客户端/游戏大厅 可调用 「查询房间列表」 查询所有状态为已就绪("READY")房间
- 玩家调用 「加入房间」 进行预加入房间
- Multiverse Server 等待玩家加入服务器后, 调用 「确认房间加入」 确认玩家加入成功
- 待房间满员或无法加入新玩家后, Multiverse Server 调用 「更新房间状态」 将房间状态更新成运行中("RUNNING")
- Multiverse Server 或 游戏客户端 在有游戏玩家离开房间时调用 「离开房间」
- Multiverse Server 可以调用 「更新房间」 来更换房主或更新一些私有的Properties
房间管理 API 调用示例
C#
// [UOS Multiverse - 房间管理]API使用示例
// API完整参数列表可参考https://uos.unity.cn/docs/multiverse/room-api.html
// 注意:使用前需要填入_uosAppID、_uosAppSecret、_multiverseProfileId、_gameRegionId。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
namespace Lobby
{
public struct CreateRoomRequest
{
// required
// 待分配服务所属的multiverse profile id
public string multiverseProfileId;
// required
// 待分配服务所属的regionId
public string gameRegionId;
// optional
// 房间类型 例如:路人局,天梯赛,娱乐模式等,默认DEFAULT
[JsonProperty("namespace")] public string roomNamespace;
// optional
// 房间名称,默认DEFAULT
public string name;
// optional
// 最大玩家数
public int maxPlayers;
// optional
// 房间的可视性"PUBLIC"或"PRIVATE","PRIVATE"情况下joinCode不可为空
public string visibility;
// optional
// 自定义属性
public Dictionary<string, string> customProperties;
// optional
// 创建者的玩家Id
public string playerId;
// optional
// PRIVATE房间的加入密码
public string joinCode;
// optional
// 房间最长存活时间
public uint roomTTLInMinutes;
// optional
// 传递给服务的变量
public Dictionary<string, string> allocationEnvs;
}
public struct CreateRoomResponse
{
public DedicatedRoom RoomInfo;
public AllocationInfo AllocationInfo;
public List<string> Players;
}
public struct ListRoomsResponse
{
public string TotalCount;
public List<DedicatedRoom> Rooms;
}
public struct GetRoomResponse
{
public DedicatedRoom RoomInfo;
public AllocationInfo AllocationInfo;
public List<string> Players;
}
public struct JoinRoomRequest
{
// required
// 需要加入房间的玩家Id
public string playerId;
// 房间加入码,如果房间"Visibility"是"PRIVATE"则必填
public string joinCode;
}
public struct JoinRoomResponse
{
public DedicatedRoom RoomInfo;
public AllocationInfo AllocationInfo;
}
public struct UpdateRoomRequest
{
// 自定义属性 (全量更新)
public Dictionary<string, string> customProperties;
// 房主的PlayerId
[CanBeNull] public string ownerId;
}
public struct DedicatedRoom
{
public string Id;
public string RoomUUID;
public string MultiverseProfileId;
public string UosAppId;
public string Type;
public string OwnerId;
public string Status;
public string Namespace;
public string Name;
public string JoinCode;
public uint MaxPlayers;
public string Visibility;
public Dictionary<string, string> CustomProperties;
public DateTime ExpirationTime;
public DateTime CreatedAt;
public DateTime UpdatedAt;
public uint? PlayerCount;
}
public struct AllocationInfo
{
public string Uuid;
public string GameId;
public string ProfileId;
public string RegionId;
public string Ip;
public List<GameServerPort> GameServerPorts;
public string GameServerName;
public Timestamp CreatedAt;
public Timestamp FulfilledAt;
public string Status;
public string AllocationTTL;
public string RegionName;
public string ProfileName;
}
public struct Timestamp
{
public int Seconds;
public int Nanos;
}
public struct GameServerPort
{
public uint Port;
public string Protocol;
public string Name;
public string PortPolicy;
}
public class Dedicated
{
// 请填入自己UOS App的App ID和App Service Secret,可前往https://uos.unity.cn/apps下进入App后在「设置」中获取
private static string _uosAppID = "";
private static string _uosAppSecret = "";
// 请填入Multiverse的启动配置ID,可在UOS APP网页 - Multiverse - 启动配置 下创建启动配置后获取。创建后需要在启动配置下「添加」并「应用」镜像配置版本方可使用。
// 如需帮助,可先完成「示例教程BOSSROOM」:https://uos.unity.cn/docs/multiverse/tutorial-boss-room.html,并在此填入教程过程中创建并应用好镜像配置的启动配置ID
private static string _multiverseProfileId = "";
// 填入待分配服务所属的regionID,可在UOS APP网页 - Multiverse - 房间/服务器 页面上方地域详情中「拷贝地域ID」获取
private static string _gameRegionId = "";
private static string _endPoint = "https://s.unity.cn";
/// <summary>
/// 调用示例
/// </summary>
public static async void Test()
{
try
{
var roomOwner = "id0001";
var joinCode = "JOINCODE1";
Debug.Log("=======create room");
var createRoomReq = new CreateRoomRequest
{
multiverseProfileId = _multiverseProfileId,
gameRegionId = _gameRegionId,
roomNamespace = "testNamespace",
name = "名称",
maxPlayers = 10,
visibility = "PRIVATE",
playerId = roomOwner,
joinCode = joinCode,
roomTTLInMinutes = 10,
customProperties = new Dictionary<string, string>
{
{ "key", "value" }
},
allocationEnvs = new Dictionary<string, string>
{
{ "key2", "value2" }
},
};
var createRoomResp = await CreateRoom(createRoomReq);
Debug.Log(JsonConvert.SerializeObject(createRoomResp, Formatting.Indented));
var roomUUID = createRoomResp.RoomInfo.RoomUUID;
Debug.Log("=======Owner Join room");
var joinRoomResp = await JoinRoom(roomUUID, new JoinRoomRequest()
{
playerId = roomOwner,
joinCode = joinCode
});
Debug.Log(JsonConvert.SerializeObject(joinRoomResp, Formatting.Indented));
Debug.Log("=======ChangeRoomStatus");
var changeRoomStatusResp = await ChangeRoomStatus(roomUUID, "READY");
Debug.Log(JsonConvert.SerializeObject(changeRoomStatusResp, Formatting.Indented));
Debug.Log("=======List rooms");
var status = new List<string> { "READY" };
var listRoomsResp = await ListRooms(status: status);
Debug.Log(JsonConvert.SerializeObject(listRoomsResp, Formatting.Indented));
Debug.Log("=======Player Join room");
var joinRoomResp2 = await JoinRoom(roomUUID, new JoinRoomRequest
{
playerId = "0022",
joinCode = joinCode
});
Debug.Log(JsonConvert.SerializeObject(joinRoomResp2, Formatting.Indented));
Debug.Log("=======Update room");
var updateResp = await UpdateRoom(roomUUID, new UpdateRoomRequest
{
customProperties = new Dictionary<string, string>
{
{ "key2", "value2" }
},
});
Debug.Log(JsonConvert.SerializeObject(updateResp, Formatting.Indented));
Debug.Log("=======Get room");
var getRoomResp = await GetRoom(roomUUID);
Debug.Log(JsonConvert.SerializeObject(getRoomResp, Formatting.Indented));
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
/// <summary>
/// 创建房间
/// </summary>
/// <param name="req">创建房间请求内容</param>
/// <returns>房间信息</returns>
public static async Task<CreateRoomResponse> CreateRoom(CreateRoomRequest req)
{
var jsonData = JsonConvert.SerializeObject(req);
var response =
await SendRequest<CreateRoomResponse>(_endPoint+"/service/rooms", "POST", data: jsonData);
return response;
}
/// <summary>
/// 查询房间列表
/// </summary>
/// <param name="start">查询起始位置</param>
/// <param name="count">查询个数,默认为10,最大为100</param>
/// <param name="name">房间名(可模糊查询)</param>
/// <param name="roomNamespace">房间类型,例如:路人局,天梯赛,娱乐模式等</param>
/// <param name="ownerId">房主的ID</param>
/// <param name="visibility">房间可见性</param>
/// <param name="roomUUID">房间UUID</param>
/// <param name="status">房间状态SERVER_ALLOCATED/READY/RUNNING</param>
/// <param name="profileId">启动配置ID</param>
/// <returns>房间列表</returns>
public static async Task<ListRoomsResponse> ListRooms(uint start = 0, uint count = 10, string name = null,
string roomNamespace = null,
string ownerId = null, string visibility = null, string roomUUID = null, List<string> status = null,
string profileId = null)
{
var query = new Dictionary<string, object>
{
{ "start", start.ToString() },
{ "count", count.ToString() },
};
if (name != null)
{
query.Add("name", name);
}
if (roomNamespace != null)
{
query.Add("namespace", roomNamespace);
}
if (ownerId != null)
{
query.Add("ownerId", ownerId);
}
if (visibility != null)
{
query.Add("visibility", visibility);
}
if (roomUUID != null)
{
query.Add("roomUUID", roomUUID);
}
if (status != null)
{
query.Add("status", status.ToArray());
}
if (profileId != null)
{
query.Add("profileId", profileId);
}
var response =
await SendRequest<ListRoomsResponse>(_endPoint+"/service/rooms", "GET", queryParams: query);
return response;
}
/// <summary>
/// 查询房间信息
/// </summary>
/// <param name="roomUUID">房间UUID</param>
/// <returns>房间信息</returns>
public static async Task<GetRoomResponse> GetRoom(string roomUUID)
{
var response =
await SendRequest<GetRoomResponse>(_endPoint+"/service/rooms/" + roomUUID, "GET");
return response;
}
/// <summary>
/// 加入房间
/// </summary>
/// <param name="roomUUID">房间UUID</param>
/// <param name="req">加入房间请求内容</param>
/// <returns>房间信息</returns>
public static async Task<JoinRoomResponse> JoinRoom(string roomUUID, JoinRoomRequest req)
{
var jsonData = JsonConvert.SerializeObject(req);
var response =
await SendRequest<JoinRoomResponse>(_endPoint+"/service/rooms/" + roomUUID + "/join", "POST",
data: jsonData);
return response;
}
/// <summary>
/// 更新房间状态
/// </summary>
/// <param name="roomUUID">房间UUID</param>
/// <param name="status">需要更新至的房间状态,READY/RUNNING</param>
/// <returns>房间信息</returns>
public static async Task<DedicatedRoom> ChangeRoomStatus(string roomUUID, string status)
{
var response =
await SendRequest<DedicatedRoom>(_endPoint+"/service/rooms/" + roomUUID + "/status/" + status, "PUT");
return response;
}
/// <summary>
/// 更新房间
/// </summary>
/// <param name="roomUUID">房间UUID</param>
/// <param name="req">更新内容</param>
/// <returns>房间信息</returns>
public static async Task<DedicatedRoom> UpdateRoom(string roomUUID, UpdateRoomRequest req)
{
var jsonData = JsonConvert.SerializeObject(req);
var response =
await SendRequest<DedicatedRoom>(_endPoint+"/service/rooms/" + roomUUID, "PUT", data: jsonData);
return response;
}
public static async Task<T> SendRequest<T>(
string url,
string method,
string data = "",
Dictionary<string, object> queryParams = null,
Dictionary<string, string> headers = null,
bool logEnable = true
)
{
var requestUrl = ConstructUrl(url, queryParams);
using var uwr = new UnityWebRequest(requestUrl, method);
ConfigAuthentication(uwr);
if (headers != null)
{
foreach (var kvp in headers)
{
uwr.SetRequestHeader(kvp.Key, kvp.Value);
}
}
uwr.disposeDownloadHandlerOnDispose = true;
uwr.disposeUploadHandlerOnDispose = true;
if (data != "")
{
uwr.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(data));
}
uwr.downloadHandler = new DownloadHandlerBuffer();
if (logEnable)
{
Debug.Log($"UOS Request {method} {url}");
}
var sendOperation = uwr.SendWebRequest();
while (!sendOperation.isDone)
{
await Task.Yield();
}
if (uwr.error != null)
{
throw new Exception(uwr.downloadHandler.text);
}
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
return JsonConvert.DeserializeObject<T>(uwr.downloadHandler.text, settings);
}
private static void ConfigAuthentication(UnityWebRequest webRequest)
{
string nonce = Guid.NewGuid().ToString();
long timestamp = EncipherUtility.GetUnixTimeStampSeconds(DateTime.UtcNow);
string data = $"{_uosAppID}:{_uosAppSecret}:{timestamp}:{nonce}";
string authData = EncipherUtility.hexString(EncipherUtility.sha256(data));
webRequest.SetRequestHeader("X-APPID", _uosAppID);
webRequest.SetRequestHeader("X-TIMESTAMP", $"{timestamp}");
webRequest.SetRequestHeader("X-NONCE", nonce);
webRequest.SetRequestHeader("Authorization", "nonce " + authData);
webRequest.SetRequestHeader("content-type", "application/json;charset=utf-8");
}
public static class EncipherUtility
{
public static byte[] sha256(string data)
{
byte[] bytes = Encoding.UTF8.GetBytes(data);
using (SHA256 mySHA256 = SHA256.Create())
{
byte[] hash = mySHA256.ComputeHash(bytes);
return hash;
}
}
public static string hexString(byte[] data)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
builder.Append(data[i].ToString("X2").ToLower());
}
return builder.ToString();
}
public static long GetUnixTimeStampSeconds(DateTime dt)
{
DateTime dateStart = new DateTime(1970, 1, 1, 0, 0, 0);
return Convert.ToInt64((dt - dateStart).TotalSeconds);
}
}
private static string ConstructUrl(string url, Dictionary<string, object> queryParams)
{
var requestUrl = url;
if (queryParams != null)
{
var str2 = string.Join("&", queryParams.Where(kv => kv.Value != null).Select(kv =>
{
if (!kv.Value.GetType().IsArray)
{
return kv.Key + "=" + Uri.EscapeDataString(kv.Value.ToString());
}
if (!(kv.Value is IEnumerable values))
{
return "";
}
return string.Join("&",
values.Cast<object>().Select(value => kv.Key + "=" + Uri.EscapeDataString(value.ToString())));
}));
requestUrl += $"?{str2}";
}
return requestUrl;
}
}
}Python
# [UOS Multiverse - 房间管理]服务端API使用示例
# 功能模块具体使用方法可参考https://uos.unity.cn/docs/multiverse/concept.html
# API完整参数列表可参考https://uos.unity.cn/docs/multiverse/room-api.html
# -*-coding: utf-8-*-
import requests
import base64
import json
API_ENDPOINT = "https://s.unity.cn"
# 请填入自己UOS App的App ID和App Service Secret,可前往https://uos.unity.cn/apps下进入App后在「设置」中获取
print("============ 请确保已在UOS APP网页 - Multiverse - 「项目设置」中开启「房间管理」 ============")
APP_ID = ''
APP_SERVICE_SECRET = ''
print("============ 建议先完成「示例教程BOSSROOM」,可使用教程中创建并应用好镜像的启动配置ID填入此示例代码的MULTIVERSE_PROFILE_ID。教程地址:https://uos.unity.cn/docs/multiverse/tutorial-boss-room.html ============\n")
# 请填入Multiverse的启动配置ID,可在UOS APP网页 - Multiverse - 启动配置 下创建启动配置后获取。创建后需要在启动配置下「添加」并「应用」镜像配置版本方可使用。
# 如需帮助,可先完成「示例教程BOSSROOM」:https://uos.unity.cn/docs/multiverse/tutorial-boss-room.html,并在此填入教程过程中创建并应用好镜像配置的启动配置ID
MULTIVERSE_PROFILE_ID = ''
# 请填入待分配服务所属的regionID,可在UOS APP网页 - Multiverse - 房间/服务器 页面上方地域详情中「拷贝地域ID」获取
GAME_REGION_ID = ''
if len(APP_ID) == 0 or len(APP_SERVICE_SECRET) == 0:
print("请填入自己UOS App的App ID和App Secret,可前往https://uos.unity.cn/apps下进入App后在「设置」中获取")
exit(1)
if len(MULTIVERSE_PROFILE_ID) == 0:
print("请在MULTIVERSE_PROFILE_ID处填入Multiverse的启动配置ID,可在UOS APP网页 - Multiverse - 启动配置 下创建启动配置后获取。创建后需要在启动配置下「添加」并「应用」镜像配置版本。")
print("建议先完成「示例教程BOSSROOM」,可使用教程中创建并应用好镜像的启动配置ID填入此示例代码的MULTIVERSE_PROFILE_ID。教程地址:https://uos.unity.cn/docs/multiverse/tutorial-boss-room.html")
exit(1)
if len(GAME_REGION_ID) == 0:
print("请在GAME_REGION_ID处填入待分配服务所属的regionID,可在UOS APP网页 - Multiverse - 房间/服务器 页面上方地域详情中「拷贝地域ID」获取")
exit(1)
def run():
print("============ 创建房间 ============")
response = create_room(MULTIVERSE_PROFILE_ID, GAME_REGION_ID)
print(response)
room_uuid = response.get('roomInfo').get('roomUUID')
print("============ 房主加入房间 ============")
# 需要加入房间的房主玩家ID,此处以"owner1"为例
owner_id = 'owner1'
response = join_room(room_uuid, owner_id)
print(response)
print("============ 确认房主加入房间 ============")
response = confirm_join_room(room_uuid, owner_id)
print(response)
print("============ 更新房间状态至READY ============")
response = update_room_status(room_uuid, status="READY")
print(response)
print("============ 查询房间列表 ============")
response = list_rooms()
print(response)
print("============ 查询房间信息 ============")
response = get_room(room_uuid)
print(response)
print("============ 玩家加入房间 ============")
# 需要加入房间的玩家ID,此处以"player1"为例
player_id = 'player1'
response = join_room(room_uuid, player_id)
print(response)
print("============ 确认玩家加入房间 ============")
response = confirm_join_room(room_uuid, player_id)
print(response)
print("============ 更新房间状态至RUNNING(假设此时房间已满员或不再允许新玩家加入) ============")
response = update_room_status(room_uuid, status="RUNNING")
print(response)
print("============ 玩家离开房间 ============")
response = leave_room(room_uuid, player_id)
print(response)
print("============ 更新房间属性 ============")
custom_properties = {
"level": "2"
}
response = update_room_properties(room_uuid, custom_properties)
print(response)
def create_room(multiverse_profile_id, game_region_id):
""" 创建房间 """
url = API_ENDPOINT + '/service/rooms'
data = {
"multiverseProfileId": multiverse_profile_id,
"gameRegionId": game_region_id
}
response = requests.post(url, headers=headers, json=data)
check_response(response)
return response.json()
def join_room(room_uuid, player_id):
""" 加入房间 """
url = API_ENDPOINT + '/service/rooms/' + room_uuid + '/join'
data = {
"playerId": player_id
}
response = requests.post(url, headers=headers, json=data)
check_response(response)
return response.json()
def confirm_join_room(room_uuid, player_id):
""" 确认房间加入 """
url = API_ENDPOINT + '/service/rooms/' + room_uuid + '/confirm-join'
data = {
"playerId": player_id
}
response = requests.post(url, headers=headers, json=data)
check_response(response)
return response
def update_room_status(room_uuid, status):
""" 确认房间加入 """
url = API_ENDPOINT + '/service/rooms/' + room_uuid + '/status/' + status
response = requests.put(url, headers=headers)
check_response(response)
return response.json()
def list_rooms():
""" 查询房间列表 """
url = API_ENDPOINT + '/service/rooms'
response = requests.get(url, headers=headers)
check_response(response)
return response.json()
def get_room(room_uuid):
""" 查询房间信息 """
url = API_ENDPOINT + '/service/rooms/' + room_uuid
response = requests.get(url, headers=headers)
check_response(response)
return response.json()
def leave_room(room_uuid, player_id):
""" 离开房间 """
url = API_ENDPOINT + '/service/rooms/' + room_uuid + '/leave'
data = {
"playerId": player_id
}
response = requests.post(url, headers=headers, json=data)
check_response(response)
return response
def update_room_properties(room_uuid, custom_properties):
""" 更新房间 """
url = API_ENDPOINT + '/service/rooms/' + room_uuid
data = {
"customProperties": custom_properties
}
response = requests.put(url, headers=headers, json=data)
check_response(response)
return response.json()
def get_basic_authorization(app_id, app_secret):
""" 获取basic auth的Header """
credentials = f'{app_id}:{app_secret}'
encoded_credentials = base64.b64encode(credentials.encode("utf-8")).decode("utf-8")
return {'Authorization': f'Basic {encoded_credentials}'}
headers = get_basic_authorization(APP_ID, APP_SERVICE_SECRET)
# 校验Response
def check_response(response):
""" 校验Response,如果有错误,抛出异常值 """
if not response.ok:
try:
error_message = response.json()
if error_message.get('errorCode') == 10012:
print("该启动配置下无已应用的配置版本。需要在启动配置下「添加」并「应用」镜像配置版本方可使用。")
if error_message.get('errorMsg') == 'Invalid app: dedicated room service is not enabled':
print(
"未开启房间管理功能,请在UOS APP网页 - Multiverse - 「项目设置」中开启「房间管理」")
except json.JSONDecodeError:
error_message = response.text
raise Exception(f"Error {response.status_code}: {error_message}")
if __name__ == "__main__":
try:
run()
except Exception as e:
print(e)房间管理 API列表
API Endpoint: https://s.unity.cn