다른 Unity 서비스와 연동
Connect Cloud Code with other Unity Gaming Services using JavaScript Software Development Kits or REST APIs.
읽는 시간 8분최근 업데이트: 12시간 전
JavaScript Service SDK나 REST API를 통해 다른 Unity Gaming Services와 연결하면 Cloud Code의 기능을 최대한 활용할 수 있습니다. JavaScript SDK는 더 간단하며 더욱 일관된 경험을 제공합니다. 사용하려는 UGS 서비스에 아직 Cloud Code JavaScript SDK가 없는 경우에도 REST API를 통해 연결할 수 있습니다.
UGS SDK 사용
Cloud Code JavaScript SDK를 Cloud Code 스크립트로 바로 임포트할 수 있습니다. 사용 가능한 서비스 연동을 확인하고 각 서비스의 자세한 SDK 기술 자료와 변경 기록을 확인하려면 Cloud Code 서비스 SDK 기술 자료를 참고하십시오.
Cloud Code JavaScript SDK의 전체 목록과 각 기술 자료는 아래 표를 참고하십시오.
서비스 | SDK 기술 자료 | SDK 변경 기록 |
|---|---|---|
| Cloud Save | Cloud Save SDK | [Cloud Save SDK 변경 기록] |
| Economy | Economy SDK | [Economy SDK 변경 기록] |
| Remote Config | Remote Config SDK | [Remote Config SDK 변경 기록] |
| Vivox | Vivox SDK | [Vivox SDK 변경 기록] |
| Lobby | Lobby SDK | [Lobby SDK 변경 기록] |
| Leaderboards | Leaderboards SDK | [Leaderboards SDK 변경 기록] |
| Matchmaker | Matchmaker SDK | [Matchmaker SDK 변경 기록] |
| Multiplay | Multiplay SDK | [Multiplay SDK 변경 기록] |
| Friends | Friends SDK | [Friends SDK 변경 기록] |
| Player Names | Player Names SDK | [Player Names SDK 변경 기록] |
| Player Authentication | Player Authentication SDK | [Player Authentication SDK 변경 기록] |
Cloud Save SDK 사용
Cloud Save 서비스를 사용하여 게임의 영구 플레이어 데이터(예: 게임 진행률)를 클라우드에 저장할 수 있으며, 언제 어디서나 어떤 디바이스로든 플레이어 데이터에 액세스할 수 있습니다. 즉, Cloud Save를 사용하면 플레이어가 디바이스를 변경하거나 게임을 재설치할 때 데이터 손실을 줄일 수 있습니다.데이터 읽기 및 쓰기
Cloud Code를 사용하여 Cloud Save의 데이터를 저장하고 읽을 수 있습니다. 샘플 코드는 플레이어와 커스텀 엔티티에서 다양한 액세스 한정자를 사용하여 Cloud Save 데이터를 수정하는 방법을 보여 줍니다.JavaScript
const _ = require("lodash-4.17");const { DataApi } = require("@unity-services/cloud-save-1.4");module.exports = async ({ params, context, logger }) => { const { projectId, playerId, accessToken } = context; const cloudSaveApi = new DataApi(context); try { // Default item data, readable and writable by the player await cloudSaveApi.setItem(projectId, playerId, { key: "defaultData", value: "value" }); // Custom item - non-player entities // Record any game data! const customId = "gameLevelAttributes"; await cloudSaveApi.setCustomItem(projectId, customId, { key: "levelDifficulty", value: "easy" }); // Protected data can be read by player, but not written to await cloudSaveApi.setProtectedItem(projectId, playerId, { key: "protectedItem", value: "verySecretData" }); // Private data that should only be accessed by server/service accounts await cloudSaveApi.setPrivateCustomItem(projectId, customId, { key: "levelTimerInMinutes", value: 25, }); const result = await cloudSaveApi.getItems(projectId, playerId); logger.info(`Retrieved default items from Cloud Save: ${JSON.stringify(result.data)}`) const protectedDataResult = await cloudSaveApi.getProtectedItems(projectId, playerId, ["protectedItem"]); logger.info(`Retrieved protected item from Cloud Save: ${JSON.stringify(protectedDataResult.data)}`) const customDataResult = await cloudSaveApi.getPrivateCustomItems(projectId, customId); logger.info(`Retrieved private custom items from Cloud Save: ${JSON.stringify(customDataResult.data)}`) } catch (err) { logger.error("Error while calling out to Cloud Save", { "error.message": err.message }); throw err; }};
쿼리 데이터
Cloud Code를 사용하여 Cloud Save 데이터를 쿼리할 수 있습니다. 아래 샘플을 사용하려면 먼저 Cloud Save 서비스에서 쿼리를 생성해야 합니다. Unity Cloud Dashboard의 Cloud Save 서비스로 이동하여 다음 파라미터로 쿼리를 생성합니다.- 키에 대한 기본 액세스 클래스가 있는 플레이어 엔티티의 오름차순 쿼리입니다.
health - 키에 대한 비공개 액세스 클래스가 있는 커스텀 엔티티의 내림차순 쿼리입니다.
difficulty - 키에 대한 보호 액세스 클래스가 있는 플레이어 엔티티의 오름차순 쿼리입니다.
level
JavaScript
const _ = require("lodash-4.17");const { DataApi } = require("@unity-services/cloud-save-1.4");module.exports = async ({ params, context, logger }) => { const { projectId, playerId } = context; const cloudSaveApi = new DataApi(context); try { // -------------------------------------------------------------------------------- // Query player data with the key `health` to find players with health lower than 100 // Set data for player const requestData = { data: [{ key: "health", value: 95, }, { key: "stamina", value: 20, } ] }; await cloudSaveApi.setItemBatch(projectId, playerId, requestData); // Query and return player stamina for players with health less than 100 const query = { fields: [{ asc: true, key: 'health', op: 'LT', value: 100, }], returnKeys: ["stamina"] }; const queryRes = await cloudSaveApi.queryDefaultPlayerData(projectId, query); logger.info(`Query results: ${JSON.stringify(queryRes.data)}`) // -------------------------------------------------------------------------------- // Query private custom data to retrieve game levels with easy difficulty // Record two levels with different difficulty levels const casteLevelId = "castleLevel"; const anotherLevelId = "forestLevel"; await cloudSaveApi.setPrivateCustomItem(projectId, casteLevelId, { key: "difficulty", value: "easy" }); await cloudSaveApi.setPrivateCustomItem(projectId, anotherLevelId, { key: "difficulty", value: "hard" }); // Query levels with easy levels only const privateQuery = { fields: [{ asc: false, key: 'difficulty', op: 'EQ', value: 'easy' }], }; const privateQueryRes = await cloudSaveApi.queryPrivateCustomData(projectId, privateQuery); logger.info(`Private query results: ${JSON.stringify(privateQueryRes.data)}`) // -------------------------------------------------------------------------------- // Query protected player data for players that are over level 5 // Set data for player const protectedRequestData = { data: [{ key: "level", value: 15, }, { key: "experiencePoints", value: 20, } ] }; await cloudSaveApi.setProtectedItemBatch(projectId, playerId, protectedRequestData); // Query players over level 5, and return their health const protectedPlayerQuery = { fields: [{ asc: true, key: 'level', op: 'GT', value: 5, }], returnKeys: ["experiencePoints", "level"] }; const protectedPlayerRes = await cloudSaveApi.queryProtectedPlayerData(projectId, protectedPlayerQuery); logger.info(`Protected player query results: ${JSON.stringify(protectedPlayerRes.data)}`) // -------------------------------------------------------------------------------- } catch (err) { logger.error("Error while calling out to Cloud Save", { "error.message": err.message }); throw err; }};
Economy SDK 사용
Economy 서비스를 사용하면 다음 리소스를 사용하여 게임에서 경제 시스템을 생성, 관리하고 퍼블리시할 수 있습니다.- 재화를 통해 플레이어는 하나 이상의 재화/단위로 구성된 게임 내 잔액을 보유할 수 있습니다.
- 인벤토리 아이템은 구성의 일부로 생성하는 리소스의 정의를 나타냅니다. 플레이어는 인벤토리 아이템의 여러 인스턴스(예: 동일한 검, 방패, 모자 여러 개)를 소유할 수 있으며, 재화와 달리 각 인스턴스에 고유한 프로퍼티를 부여할 수 있습니다.
- 구매를 통해 플레이어는 다양한 게임 내 재화와 인벤토리 아이템을 게임 내 재화와 인벤토리 아이템으로 구매(가상 구매)하거나 디지털 스토어프론트를 통해 실제 현금으로 구매할 수 있습니다.
Economy SDK 플레이어 인벤토리
아래는 플레이어의 인벤토리에SWORDSWORDJavaScript
const { InventoryApi } = require("@unity-services/economy-2.4");module.exports = async ({ params, context, logger }) => { const { projectId, playerId, accessToken } = context; const inventory = new InventoryApi({ accessToken }); const addInventoryRequest = { inventoryItemId : "SWORD" }; try { await inventory.addInventoryItem({ addInventoryRequest, playerId, projectId }); const result = await inventory.getPlayerInventory({ projectId, playerId }); return result.data; } catch (err) { logger.error("Error while retrieving inventory items", {"error.message": err.message}); throw err; }}
Economy SDK 플레이어 재화
아래는 플레이어의 재화 잔액을 설정한 후에 증가하고 감소시키는 스크립트 예시입니다. 아래 샘플을 사용하려면 먼저 Economy 서비스에 퍼블리시된 재화가 있어야 합니다. 아래 스크립트는 필수 문자열 파라미터인currencyIdJavaScript
const { CurrenciesApi } = require("@unity-services/economy-2.4");module.exports = async ({ params, context, logger }) => { const { projectId, playerId, accessToken } = context; const { currencyId } = params; const currencies = new CurrenciesApi({ accessToken }); try { await currencies.setPlayerCurrencyBalance({ projectId, playerId, currencyId, currencyBalanceRequest: { balance: 100 } }); await currencies.decrementPlayerCurrencyBalance({ projectId, playerId, currencyId, currencyModifyBalanceRequest: { amount: 50 } }); await currencies.incrementPlayerCurrencyBalance({ projectId, playerId, currencyId, currencyModifyBalanceRequest: { amount: 10 } }); const result = await currencies.getPlayerCurrencies({ projectId, playerId }); return result.data; } catch (err) { logger.error("Error while updating currencies", {"error.message": err.message}, {"currencyId" : currencyId}); throw err; }}// Uncomment the code below to enable the inline parameter definition// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)//// module.exports.params = {// currencyId: { type: "String", required: true },// };
Economy SDK 가상 구매 사용
아래는 가상 구매 이후에 플레이어의 인벤토리에서 아이템을 삭제하는 스크립트 예시입니다. 아래 샘플을 사용하려면 먼저 Economy 서비스에서 가상 구매를 생성하고 새로운 구성을 퍼블리시해야 합니다. 스크립트는purchaseIdcurrencyIdcurrencyIdJavaScript
const { CurrenciesApi, PurchasesApi, InventoryApi } = require("@unity-services/economy-2.4");module.exports = async ({ params, context, logger }) => { const { projectId, playerId, accessToken } = context; const { purchaseId, currencyId } = params; const inventory = new InventoryApi({ accessToken }); const purchases = new PurchasesApi({ accessToken }); const currencies = new CurrenciesApi({ accessToken }); try { // Give a player some currency to complete the purchase await currencies.setPlayerCurrencyBalance({ projectId, playerId, currencyId, currencyBalanceRequest: { balance: 1 } }); const makeVirtualPurchaseResult = await purchases.makeVirtualPurchase({ projectId, playerId, playerPurchaseVirtualRequest: { id: purchaseId } }); const getPlayerInventoryResult = await inventory.getPlayerInventory({ projectId, playerId }); await inventory.deleteInventoryItem({ projectId, playerId, playersInventoryItemId: makeVirtualPurchaseResult.data.rewards.inventory[0].playersInventoryItemIds[0], inventoryDeleteRequest: {} }); return { makeVirtualPurchaseResult: makeVirtualPurchaseResult.data, getPlayerInventoryResult: getPlayerInventoryResult.data }; } catch (err) { logger.error("Error while calling out to Economy", {"error.message": err.message}); throw err; }}// Uncomment the code below to enable the inline parameter definition// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)//// module.exports.params = {// currencyId: { type: "String", required: true },// purchaseId: { type: "String", required: true },// };
Economy를 Game Overrides와 함께 사용
자세한 내용은 Cloud Code를 사용하는 Economy Game Overrides 기술 자료를 참고하십시오.Remote Config SDK 사용
Remote Config는 애플리케이션의 새 버전을 배포할 필요 없이 게임 설계를 조정할 수 있는 클라우드 서비스입니다. Remote Config는 네임스페이스에 저장된 키-값 파라미터들로 구성되며, 기존 파라미터를 오버라이드하거나 기존 파라미터에 추가되는 값 세트를 정의할 수 있습니다. Cloud Code 스크립트에서 Remote Config 설정을 수정할 수 있습니다. 아래는 플레이어에게 Remote Config 설정을 할당하는 방법을 보여 주는 샘플입니다.JavaScript
const { SettingsApi } = require("@unity-services/remote-config-1.1");module.exports = async ({ context, logger }) => { const { projectId, playerId, accessToken } = context; const remoteConfig = new SettingsApi({ accessToken }); try { const result = await remoteConfig.assignSettings({ projectId, "userId": playerId, "attributes": { "unity": {}, "app": {}, "user": {} } }); return result.data; } catch (err) { logger.error("Error while assigning settings", {"error.message": err.message}); throw err; }}
Vivox SDK 사용
Vivox는 게임을 위한 음성 및 텍스트 기반 커뮤니케이션 서비스를 제공합니다. Cloud Code로 Vivox 토큰을 생성할 수 있으며, 이를 통해 게임 클라이언트가 Vivox 서비스 작업에 안전하게 액세스합니다. 아래는 Cloud Code 스크립트로 Vivox 토큰을 생성하는 방법을 보여 주는 샘플입니다.JavaScript
const { TokenApi } = require("@unity-services/vivox-0.1");module.exports = (async e => { const o = { iss: "gary.charlton.oogabooga", exp: 1559359105, vxa: "join", vxi: 1, f: "sip:.username.@domain.vivox.com", t: "sip:confctl-g-channelname@domain.vivox.com" }; try { return TokenApi.generateVivoxToken("TEST_KEY", o) } catch (err) { logger.error("Error while generating vivox token", {"error.message": err.message}); throw err; }});
Lobby SDK 사용
Lobby를 사용하면 플레이어는 게임 세션 전이나 세션 중에 다른 플레이어와 연결할 수 있습니다. 플레이어가 간단한 게임 속성으로 공개 로비를 생성하면 다른 플레이어가 해당 로비를 검색, 발견하고 로비에 참여할 수 있습니다. 플레이어는 초대 전용 로비를 생성해서 특정 참가자만 참여할 수 있는 비공개 공간을 만들 수도 있습니다. 다음은 Cloud Code 스크립트를 사용하여 로비를 생성, 업데이트하고 하트비트하는 방법을 보여 주는 예시입니다. 이 샘플에서는 서비스 토큰을 사용하여 소유자가 없는 빈 로비를 생성합니다. 그다음 플레이어를 로비에 추가할 때 사용하는playerIdserviceId
아래 샘플은 비공개 로비를 생성하고, 로비 이름을 업데이트하고, 가상의 플레이어로 로비에 참여한 후 로비를 가져옵니다.
JavaScript
const { LobbyApi } = require("@unity-services/lobby-1.2");module.exports = async ({ params, context, logger }) => { const lobbyApi = new LobbyApi(context); const { serviceId, playerId } = params; try { // Create a private lobby without any initial players. const { data: lobby } = await lobbyApi.createLobby( serviceId, null, { name: "my new lobby name", maxPlayers: 4, isPrivate: true, } ); logger.info(`Created lobby: ${JSON.stringify(lobby)}`); // Heartbeat the lobby to keep it active. await lobbyApi.heartbeat(lobby.id, serviceId); // Update the lobby's name and get the updated lobby. const { data: updateResponse } = await lobbyApi.updateLobby( lobby.id, serviceId, null, { name: "my updated lobby name" } ); logger.info(`Lobby updated: ${JSON.stringify(updateResponse)}`); // Join the lobby as an impersonated player. const { data: joinResponse } = await lobbyApi.joinLobbyById(lobby.id, serviceId, playerId); logger.info(`Player joined: ${JSON.stringify(joinResponse)}`); // Get and return the lobby. const getResponse = await lobbyApi.getLobby(lobby.id, serviceId); return getResponse.data; } catch (err) { logger.error("Error while calling out to Lobby", {"error.message": err.message}); throw err; }};// Uncomment the code below to enable the inline parameter definition// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)//// module.exports.params = {// serviceId: { type: "String", required: true },// playerId: { type: "String", required: true },// };
Leaderboards SDK 사용
Leaderboards를 사용하면 게임에 리더보드를 생성하고 관리할 수 있습니다. 아래 샘플을 사용하려면 먼저 Leaderboards 서비스에서 리더보드를 생성해야 합니다. 아래는 리더보드에 점수를 추가하고 Cloud Code 스크립트로 리더보드 점수를 가져오는 방법을 보여 주는 샘플입니다. 이 샘플은leaderboardIdJavaScript
const { LeaderboardsApi } = require("@unity-services/leaderboards-1.1");module.exports = async ({ params, context, logger }) => { const leaderboardsApi = new LeaderboardsApi({accessToken : context.accessToken}); let result; try { await leaderboardsApi.addLeaderboardPlayerScore(context.projectId, params.leaderboardId, context.playerId, { score : 20}); const result = await leaderboardsApi.getLeaderboardScores(context.projectId, params.leaderboardId); return result.data; } catch (err) { logger.error("Error while calling out to Leaderboards", {"error.message": err.message}); throw err; }};// Uncomment the code below to enable the inline parameter definition// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)//// module.exports.params = {// leaderboardId: { type: "String", required: true },// };
Friends SDK 사용
Friends를 사용하면 게임에서 플레이어 간의 관계를 생성하고 관리할 수 있습니다. Friends로 게임 내 관계를 관리하고, 친구 요청을 보내고 수락하며, 상태 정보를 제어하고, 플레이어 간에 메시지를 전송할 수 있습니다. 아래 샘플에서는 Friends와 Cloud Code를 사용하여 친구 요청을 보내고, 친구를 검색하고, 알림 토큰을 검색하고, 상태 정보 설정은 물론 상태 정보를 수신하고, 메시지를 전송하는 방법을 보여 줍니다. Unity Cloud Dashboard에서 이 샘플을 테스트하려면 2개의 다른 브라우저 탭에서 2명의 서로 다른 플레이어로 인증된 상태로 스크립트를 실행합니다. 한 탭에서 첫 번째 플레이어 ID로 스크립트를 실행하고, 다른 탭에서 두 번째 플레이어 ID로 스크립트를 실행합니다.JavaScript
const { RelationshipsApi, PresenceApi, MessagingApi, NotificationsApi } = require("@unity-services/friends-1.0");module.exports = async ({ params, context, logger }) => { // Send friend requests and retrieve friends const relationshipsApi = new RelationshipsApi({ accessToken: context.accessToken }); try { const payload = { type: "FRIEND_REQUEST", members: [{ id: params.playerId }] }; const createRes = await relationshipsApi.createRelationship(true, true, payload); logger.info(`New relationship initiated: ${JSON.stringify(createRes.data)}`) } catch (err) { // The call will fail if the friend request has already been sent logger.error("Error while sending a friend request", { "error.message": err.message }); } try { const list = await relationshipsApi.getRelationships(10, 0, true, true, ["FRIEND_REQUEST", "FRIEND"]); logger.info(`Retrieved relationships: ${JSON.stringify(list.data)}`) } catch (err) { logger.error("Error while retrieving relationships", { "error.message": err.message }); } // ------------------------------------------------------------------------- // Retrieve a notification token const notificationsApi = new NotificationsApi({ accessToken: context.accessToken }); try { const auth = await notificationsApi.getNotificationsAuth(); logger.info(`Retrieved notifications subscription token: ${JSON.stringify(auth.data)}`) } catch (err) { logger.error("Error while retrieving notification subscription token", { "error.message": err.message }); } // ------------------------------------------------------------------------- // Set and receive presence const presenceApi = new PresenceApi({ accessToken: context.accessToken }); try { const newStatus = { activity: { // define any payload structure location: "In Menu", }, availability: "ONLINE", }; const setPresenceStatus = await presenceApi.setPresence(newStatus); logger.info(`Changed player presence status for player ${context.playerId}: ${JSON.stringify(setPresenceStatus.data)}`) } catch (err) { logger.error("Error while setting a presence status", { "error.message": err.message }); } try { // This call will fail if the requested user has not accepted the friend request! const presenceStatus = await presenceApi.getPresence(params.playerId); logger.info(`Retrieved player presence for player ${params.playerId}: ${JSON.stringify(presenceStatus.data)}`) } catch (err) { logger.error("Error while retrieving a presence status", { "error.message": err.message }); } // ------------------------------------------------------------------------- // Send messages const messagingApi = new MessagingApi({ accessToken: context.accessToken }); try { const messagePayload = { id: params.playerId, message: { // define any payload structure hello: "world", custom: "sending you a message!" } } // This call will fail if the requested user has not accepted the friend request! const messageResponse = await messagingApi.message(messagePayload); logger.info(`Sent a message to player ${params.playerId}`) } catch (err) { logger.error("Error while sending a message", { "error.message": err.message }); throw err; }}// Uncomment the code below to enable the inline parameter definition// - Requires Cloud Code JS dev environment setup with NodeJS (https://docs.unity3d.com/Packages/com.unity.services.cloudcode@latest/index.html?subfolder=/manual/Authoring/javascript_project.html)//// module.exports.params = {// playerId: { type: "String", required: true },// };
Player Names SDK 사용
Player Names를 사용하면 게임에서 플레이어의 이름을 검색할 수 있습니다. 이를 통해 플레이어가 아직 이름을 설정하지 않은 경우 플레이어의 새 이름을 생성하거나 기존 플레이어 이름을 업데이트할 수 있습니다.JavaScript
const { PlayerNamesApi } = require("@unity-services/player-names-1.0");module.exports = async ({ params, context, logger }) => { const playerNamesApi = new PlayerNamesApi({ accessToken: context.accessToken }); try { const playerData = await playerNamesApi.getName(context.playerId); logger.info(`The received player data is ${JSON.stringify(playerData.data)}`); const updatedData = await playerNamesApi.updateName(context.playerId, {name: "newCustomName"}); logger.info(`The updated player data is ${JSON.stringify(updatedData.data)})`); } catch (err) { logger.error("Error while calling out to Player Names", { "error.message": err.message }); throw err; }};
REST API를 통해 UGS와 연결
각 서비스의 REST API를 통해 서비스에 연결할 수도 있습니다. 이 방법은 아직 JavaScript SDK가 없는 서비스를 사용하려는 경우에 유용합니다.Authentication
사용 사례에 따라accessTokenserviceTokenserviceToken