与其他 Unity 服务集成
要充分发挥 Cloud Code 的潜力,可以通过 C# Service SDK 或 REST API 将其与其他 Unity Gaming Services(Unity 游戏服务)连接起来。
C# SDK 更简单,并提供更一致的体验。但是,如果要使用的 UGS 服务还没有 Cloud Code C# SDK,可以通过其 REST API 与其连接。
使用 UGS SDK
要从 NuGet 访问 Cloud Code C# 服务 SDK,请搜索 Com.Unity.Services.CloudCode.Apis。安装该包后,您可以在 C# 模块中使用该包来简化与其他 Unity 服务的连接方式。
注意:Cloud Code C# SDK 的文档尚未完成。现在,您可以暂时参考 JavaScript 文档,其具有类似的结构。此外,请利用集成开发环境的自动补全和智能感知功能。
如需查看 Cloud Code C# SDK 的完整列表,请参阅可用库页面。
GameApiClient
类
GameApiClient
类是每个服务的 Cloud Code C# SDK 的包装器。从 Cloud Code 模块调用 UGS 服务时,可以使用此类提供的简化接口。
要使用 GameAPIClient
接口,请在 ICloudCodeSetup
配置器中将 GameApiClient
注册为单例:
C#
public class ModuleConfig : ICloudCodeSetup
{
public void Setup(ICloudCodeConfig config)
{
config.Dependencies.AddSingleton(GameApiClient.Create());
}
}
与 UGS 集成
您可以在归属于 CloudCodeFunction
的任何函数中使用 GameApiClient
类。要使用 GameApiClient
类,请将 IGameApiClient
接口作为参数传入函数。
以下示例演示了如何在 Cloud Save 中保存和读取数据:
C#
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Unity.Services.CloudCode.Apis;
using Unity.Services.CloudCode.Core;
using Unity.Services.CloudCode.Shared;
using Unity.Services.CloudSave.Model;
namespace ExampleModule;
public class CloudSaveSdkSample
{
private static ILogger<CloudSaveSdkSample> _logger;
public CloudSaveSdkSample(ILogger<CloudSaveSdkSample> logger)
{
_logger = logger;
}
[CloudCodeFunction("SaveData")]
public async Task SaveData(IExecutionContext context, IGameApiClient gameApiClient, string key, object value)
{
try
{
await gameApiClient.CloudSaveData.SetItemAsync(context, context.AccessToken, context.ProjectId,
context.PlayerId, new SetItemBody(key, value));
}
catch (ApiException ex)
{
_logger.LogError("Failed to save data. Error: {Error}", ex.Message);
throw new Exception($"Failed to save data for playerId {context.PlayerId}. Error: {ex.Message}");
}
}
[CloudCodeFunction("GetData")]
public async Task<object> GetData(IExecutionContext context, IGameApiClient gameApiClient, string key)
{
try
{
var result = await gameApiClient.CloudSaveData.GetItemsAsync(context, context.AccessToken,
context.ProjectId, context.PlayerId, new List<string> { key });
return result.Data.Results.First().Value;
}
catch (ApiException ex)
{
_logger.LogError("Failed to get data. Error: {Error}", ex.Message);
throw new Exception($"Failed to get data for playerId {context.PlayerId}. Error: {ex.Message}");
}
}
public class ModuleConfig : ICloudCodeSetup
{
public void Setup(ICloudCodeConfig config)
{
config.Dependencies.AddSingleton(GameApiClient.Create());
}
}
}
通过 REST API 与 UGS 进行连接
如果要使用尚无 C# SDK 的服务,也可以通过 REST API 直接与服务进行连接。
身份验证
根据您的用例,您可以使用 AccessToken
或 ServiceToken
对 API 调用进行身份验证。如果使用 ServiceToken
对 UGS Client API 进行身份验证,请确保要调用的服务支持服务令牌。如需查看支持服务令牌的服务和用例的列表,请参阅服务令牌和访问令牌支持文档。
**注意:**如果要调用的服务提供了 Cloud Code C# SDK,建议使用该 SDK,而不是直接调用服务 API。如需了解更多信息,请参阅可用库列表。
调用 API
通过依赖项注入可以将 API 接口创建为单例,并将它们注入到模块中。
除了 UGS API 之外,还可以将外部 API 实现为单例。如需查看如何实现外部 API 的示例,请参阅有关如何与外部服务集成的文档。
例如,您可以为 User Generated Content API 定义一个接口来创建和获取内容:
**注意:**需要先在项目中启用 User Generated Content 服务,然后才能使用该服务。
C#
using System.Net;
using Newtonsoft.Json;
using RestSharp;
using RestSharp.Authenticators;
using Unity.Services.CloudCode.Core;
namespace GeneratedContentSample;
public interface IGeneratedContentApi
{
public Task<GeneratedContentGetApiResponse?> GetGeneratedContentForPlayer(IExecutionContext context);
public Task<GeneratedContentPostApiResponse?> CreateContent(IExecutionContext context);
}
public class GeneratedContentPostApiResponse
{
public string? uploadThumbnailUrl { get; set; }
public string? uploadContentUrl { get; set; }
public string? version { get; set; }
public Content content { get; set; }
}
public class GeneratedContentGetApiResponse
{
public int? offset { get; set; }
public int? limit { get; set; }
public int? total { get; set; }
public Content[] results { get; set; }
}
public class Content
{
public string id { get; set; }
public string? name { get; set; }
public string? customId { get; set; }
public string? description { get; set; }
public string visibility { get; set; }
public string moderationStatus { get; set; }
public string? version { get; set; }
public string createdAt { get; set; }
public string updatedAt { get; set; }
public string deletedAt { get; set; }
public string projectId { get; set; }
public string environmentId { get; set; }
public string creatorAccountId { get; set; }
public string? thumbnailUrl { get; set; }
public string? downloadUrl { get; set; }
public string? portalUrl { get; set; }
public string? metadata { get; set; }
public float? averageRating { get; set; }
public bool isUserSubscribed { get; set; }
public string assetUploadStatus { get; set; }
public string thumbnailUploadStatus { get; set; }
public string? webhookEventName { get; set; }
}
public class GeneratedContentApi : IGeneratedContentApi
{
private readonly RestClient _httpClient;
public GeneratedContentApi()
{
_httpClient = new RestClient("https://ugc.services.api.unity.com/v1/");
}
public async Task<GeneratedContentGetApiResponse?> GetGeneratedContentForPlayer(IExecutionContext context)
{
var request = new RestRequest($"content/search")
{
Authenticator = new JwtAuthenticator(context.AccessToken)
};
// Pass through the analytics user id and Unity installation id to the service.
if (context.AnalyticsUserId != null)
request = request.AddHeader("analytics-user-id", context.AnalyticsUserId);
if (context.UnityInstallationId != null)
request = request.AddHeader("unity-installation-id", context.UnityInstallationId);
RestResponse response = await _httpClient.ExecuteAsync(request);
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception("Failed to get User Generated Content: " + response.Content);
return JsonConvert.DeserializeObject<GeneratedContentGetApiResponse?>(response.Content!);
}
public async Task<GeneratedContentPostApiResponse?> CreateContent(IExecutionContext context)
{
var request = new RestRequest($"projects/{context.ProjectId}/environments/{context.EnvironmentId}/content", Method.Post)
{
Authenticator = new JwtAuthenticator(context.AccessToken)
}.AddJsonBody(new
{
name = "a festive treat",
description = "banasco is a traditional british toast",
});
// Pass through the analytics user id and Unity installation id to the service.
if (context.AnalyticsUserId != null)
request = request.AddHeader("analytics-user-id", context.AnalyticsUserId);
if (context.UnityInstallationId != null)
request = request.AddHeader("unity-installation-id", context.UnityInstallationId);
RestResponse response = await _httpClient.ExecuteAsync(request);
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception("Failed to create user generated content: " + response.Content);
return JsonConvert.DeserializeObject<GeneratedContentPostApiResponse>(response.Content!);
}
}
然后可以将 GeneratedContentApi
添加为单例:
C#
public class ModuleConfig : ICloudCodeSetup
{
public void Setup(ICloudCodeConfig config)
{
config.Dependencies.AddSingleton<IGeneratedContentApi>(new GeneratedContentApi());
}
}
然后可以将 IGeneratedContentApi
接口作为函数参数传入模块函数,并访问 UGC API。
C#
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Unity.Services.CloudCode.Core;
namespace GeneratedContentSample;
public class GeneratedContent
{
private readonly ILogger<GeneratedContent> _logger;
public GeneratedContent(ILogger<GeneratedContent> logger)
{
_logger = logger;
}
[CloudCodeFunction("AddContent")]
public async Task<GeneratedContentPostApiResponse?> AddUserGeneratedContent(IExecutionContext ctx, IGeneratedContentApi contentClient)
{
try
{
return await contentClient.CreateContent(ctx);
}
catch (Exception e)
{
_logger.LogError("Failed to add content. Error: {Error}", e.Message);
throw new Exception($"Failed to add content for player {ctx.PlayerId}. Error: {e.Message}");
}
}
[CloudCodeFunction("GetContent")]
public async Task<GeneratedContentGetApiResponse?> GetContent(IExecutionContext ctx, IGeneratedContentApi contentClient)
{
try
{
return await contentClient.GetGeneratedContentForPlayer(ctx);
}
catch (Exception e)
{
_logger.LogError("Failed to get content. Error: {Error}", e.Message);
throw new Exception($"Failed to get content. Error: {e.Message}");
}
}
public class ModuleConfig : ICloudCodeSetup
{
public void Setup(ICloudCodeConfig config)
{
config.Dependencies.AddSingleton<IGeneratedContentApi>(new GeneratedContentApi());
}
}
}