다음을 통해 공유


사용자 지정 CloudScript 작성

CloudScript는 PlayFab의 가장 다능한 기능 중 하나입니다. 이를 통해 클라이언트 코드는 구현할 수 있는 모든 종류의 사용자 지정 서버측 기능의 실행을 요청할 수 있으며 사실상 모든 것과 함께 사용할 수 있습니다. 클라이언트 또는 서버 코드의 명시적 실행 요청 외에도 CloudScript는 PlayStream 이벤트에 대한 응답으로(규칙 생성) 또는 예약된 작업의 일부로 실행될 수 있습니다.

참고 항목

Azure Functions를 사용하는 CloudScript는 더 많은 지원 언어와 더 나은 디버깅 워크플로를 통해 CloudScript를 훌륭하게 만든 요소를 개선합니다.

이 자습서에서는 CloudScript 코드 작성에 대해 설명합니다. CloudScript 파일을 타이틀에 업로드하는 데 도움이 되는 CloudScript 빠른 시작을 참조하세요.

참고 항목

이 자습서는 Unity 코드 샘플만 설명하지만 CloudScript는 모든 SDK에서 유사하게 기능합니다.

이 자습서의 사전 조건:

  • PlayFab Unity SDK로 설정된 Unity 환경
    • 타이틀 ID는 PlayFabSharedSettings 개체에서 설정합니다.
    • 프로젝트는 사용자를 성공적으로 로그인할 수 있습니다.

시작하기: helloWorld

우리의 helloWorld 예는 게임 관리자 수정 없이 완전 새로운 타이틀에서 기능합니다. 새 타이틀을 위한 기본 CloudScript 파일은 helloWorld라는 처리기를 포함합니다. 그것은 몇 가지 기본 기능, 입력 매개 변수, 로깅, currentPlayerId, 반환 매개 변수를 활용합니다.

다음 샘플은 기본 helloWorld 함수 코드를 보여 줍니다(주석 없음).

// CloudScript (JavaScript)
handlers.helloWorld = function (args, context) {
    var message = "Hello " + currentPlayerId + "!";
    log.info(message);
    var inputValue = null;
    if (args && args.hasOwnProperty("inputValue"))
        inputValue = args.inputValue;
    log.debug("helloWorld:", { input: inputValue });
    return { messageValue: message };
}

코드 분해

처리기 개체는 PlayFab CloudScript 환경에서 미리 정의됩니다. 이 개체에 CloudScript 함수 중 하나를 추가해야 합니다.

  • helloWorld은(는) 처리기 개체에 정의되어 있으므로 타이틀과 SDK에서 사용할 수 있는 함수입니다.

  • args은(는) 호출자로부터 오는 임의의 개체입니다. JSON에서 구문 분석되며 형식이 지정된 모든 데이터를 포함할 수 있습니다.

다음 섹션의 FunctionParameter를 참조하세요.

Warning

이 개체는 제로 트러스트로 처리해야 합니다. 해킹된 클라이언트 또는 악의적인 사용자는 여기에 ‘어떤’ 정보든 ‘어떤’ 형식으로든 제공할 수 있습니다.

  • Context은(는) 고급 매개 변수입니다. 이 예에서는 null입니다. 이 매개 변수는 서버에 의해 통제되며 안전합니다.

  • currentPlayerId은(는) 이 호출을 요청하는 플레이어의 PlayFabId로 설정되는 전역 변수입니다. 이 매개 변수는 서버에 의해 통제되며 안전합니다. 참고: ExecuteEntityCloudScript API를 사용하는 경우 엔터티의 엔터티 체인에 MasterPlayerID가 없는 한 이 매개 변수는 null입니다.

  • log.info: log은(는) 전역 개체입니다. 주로 CloudScript 디버깅에 사용됩니다. log 개체는 info, debug, error메서드를 노출합니다. 자세한 내용은 이 자습서 나중에 있습니다.

  • return: 반환하는 개체는 JSON으로서 직결화되며, 호출자에게 반환됩니다. 원하는 데이터와 함께 JSON 직렬화 가능 개체를 반환할 수 있습니다.

Warning

CloudScript가 클라이언트에 기밀 데이터를 반환하는 경우 그것은 귀하의 책임입니다. 귀하가 일반적 게임 플레이에서 반환된 데이터를 사용자에게 표시하지 않는 ‘경우에도’ 해킹된 클라이언트 또는 악의적인 사용자는 그것을 확인할 수 있습니다.

Unity 게임 클라이언트에서 CloudScript 함수 실행

클라이언트 내에서 CloudScript 함수 호출은 간단합니다. 먼저 ExecuteCloudScriptRequest를 생성하고, 실행하기 원하는 CloudScript 함수의 이름에 ActionId 속성(이 경우에는 helloWorld)을 설정한 다음, 개체를 API를 통해 PlayFab으로 보내야 합니다.

참고 항목

처리기 JavaScript 개체에 연결된 CloudScript 메서드만 호출할 수 있습니다.

CloudScript 메서드를 실행하려면 클라이언트에 다음 코드 줄이 필요합니다.

// Build the request object and access the API
private static void StartCloudHelloWorld()
{
    PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest()
    {
        FunctionName = "helloWorld", // Arbitrary function name (must exist in your uploaded cloud.js file)
        FunctionParameter = new { inputValue = "YOUR NAME" }, // The parameter provided to your function
        GeneratePlayStreamEvent = true, // Optional - Shows this event in PlayStream
    }, OnCloudHelloWorld, OnErrorShared);
}
// OnCloudHelloWorld defined in the next code block

코드 분해

ExecuteCloudScriptRequestPlayFabClientAPI.ExecuteCloudScript 호출을 위한 요청 유형입니다.

  • ExecuteCloudScriptRequest.FunctionName은(는) 문자열입니다. 그 값은 CloudScript에 정의된 함수의 이름과 일치해야 합니다. 이 경우, helloWorld입니다.

  • ExecuteCloudScriptRequest.FunctionParameter은(는) JSON으로 직렬화할 수 있는 모든 개체가 될 수 있습니다. 그것은 helloWorld함수에서 첫 번째 인수 매개 변수가 됩니다(이전 섹션의 인수 참조).

  • ExecuteCloudScriptRequest.GeneratePlayStreamEvent은(는) 선택 사항입니다. true인 경우 이벤트가 PlayStream에 게시되며 게임 관리자에서 보거나 다른 PlayStream 트리거에 활용할 수 있습니다.

언어에 따라 ExecuteCloudScript 줄의 마지막 부분에는 PlayFab CloudScript 서버에 요청을 만드는 것과 관련된 결과오류 처리 부분이 포함됩니다. 언어.

예컨대, Unity, JavaScript, AS3에서 오류 및 결과 처리는 콜백 함수를 사용해 제공됩니다.

다음은 오류 처리 방법의 예입니다.

private static void OnCloudHelloWorld(ExecuteCloudScriptResult result) {
    // CloudScript returns arbitrary results, so you have to evaluate them one step and one parameter at a time
    Debug.Log(JsonWrapper.SerializeObject(result.FunctionResult));
    JsonObject jsonResult = (JsonObject)result.FunctionResult;
    object messageValue;
    jsonResult.TryGetValue("messageValue", out messageValue); // note how "messageValue" directly corresponds to the JSON values set in CloudScript
    Debug.Log((string)messageValue);
}

private static void OnErrorShared(PlayFabError error)
{
    Debug.Log(error.GenerateErrorReport());
}

중급 개요: 전역 및 고급 인수

CloudScript는 V8를 사용해 컴파일되고 PlayFab의 서버에 호스트된 JavaScript 함수 집합입니다. 그것은 PlayFab API 참조 문서에 열거된 서버 API와 함께 ‘로거’, CloudScript를 요청하는 플레이어의 PlayFab ID, 요청에 포함된 정보(모두 사전 설정된 개체 형식)에 액세스할 수 있습니다.

CloudScript 함수 자체는 전역 처리기 개체의 속성입니다. 다음 표는 이러한 미리 정의된 변수의 전체 목록을 보여 줍니다.

이름 사용
server PlayFab API 참조 문서에 열거된 모든 서버측 API 호출에 액세스할 수 있습니다. 다음과 같이 (동기적으로) 호출할 수 있습니다: var result = server.AuthenticateUserTicket(request);
http 다음과 같이 동기 HTTP 요청을 수행합니다. http.request(url, method, content, contentType, headers, logRequestAndResponse). headers 개체에는 다양한 헤더 및 해당 값에 해당하는 속성이 포함되어 있습니다. logRequestAndResponse은(는) 타이틀이 응답의 일부로 요청의 오류를 기록해야 하는지 여부를 결정하는 부울입니다.
log 로그 문을 만들고 응답에 추가합니다. 로그에는 log.info(), log.debug(), log.error()의 세 가지 수준이 있습니다. 세 가지 수준 모두 로그에 포함할 메시지 문자열과 함께 추가 데이터가 든 선택적 개체를 포함합니다. 예: log.info('hello!', { time: new Date() });
currentPlayerId CloudScript 호출을 트리거한 플레이어의 PlayFab ID입니다.
handlers 타이틀을 위한 모든 CloudScript 함수를 포함하는 전역 개체입니다. 함수는 이 개체를 통해 추가하거나 호출할 수 있습니다. 예: handlers.pop = function() {};, handlers.pop();
스크립트 RevisiontitleId를 포함하는 전역 개체입니다. Revision은(는) 현재 실행 중인 CloudScript의 수정 번호이고 titleId은(는) 현재 타이틀의 ID를 나타냅니다.

또한, 모든 처리기 함수에는 아래 자세히 설명된 두 매개 변수가 전달됩니다.

이름 사용
args 처리기 함수의 첫 번째 매개 변수입니다. ExecuteCloudscript 요청의 FunctionParameter 필드의 개체 표현입니다.
context 처리기 함수의 두 번째 매개 변수입니다. 작업을 트리거한 이벤트의 데이터(context.playStreamEvent) 및 관련된 플레이어의 프로필 데이터를 포함하여 요청이 PlayStream 이벤트 작업에 의해 트리거될 때 해당 요청에 관한 추가 정보입니다. (context.playerProfile)

CloudScript 함수는 ExecuteCloudScript API를 통해 또는 사전 설정된 PlayStream 이벤트 작업에 의해 호출될 수 있습니다.

ExecuteCloudScript 응답에 대한 상세 설명은 ExecuteCloudScriptResult에서 찾을 수 있습니다.

중급: FunctionParameter 및 args

이전 섹션에서는 request.FunctionParameter를 채우는 방법과 args 매개 변수에서 해당 정보를 확인하는 방법을 설명했습니다. CloudScript 빠른 시작에서는 새 CloudScript를 업로드하는 방법을 보여 줍니다.

둘을 합치면 클라이언트의 인수를 CloudScript에 전달하는 방법의 다른 예를 제공할 수 있습니다. 이전 예를 취하여 CloudScript 코드와 클라이언트 코드를 다음과 같이 수정하세요.

handlers.helloWorld = function (args) {
    // ALWAYS validate args parameter passed in from clients (Better than we do here)
    var message = "Hello " + args.name + "!"; // Utilize the name parameter sent from client
    log.info(message);
    return { messageValue: message };
}
// Build the request object and access the API
private static void StartCloudHelloWorld()
{
    PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest()
    {
        FunctionName = "helloWorld", // Arbitrary function name (must exist in your uploaded cloud.js file)
        FunctionParameter = new { name = "YOUR NAME" }, // The parameter provided to your function
        GeneratePlayStreamEvent = true, // Optional - Shows this event in PlayStream
    }, OnCloudHelloWorld, OnErrorShared);
}

private static void OnCloudHelloWorld(ExecuteCloudScriptResult result) {
    // CloudScript returns arbitrary results, so you have to evaluate them one step and one parameter at a time
    Debug.Log(JsonWrapper.SerializeObject(result.FunctionResult));
    JsonObject jsonResult = (JsonObject)result.FunctionResult;
    object messageValue;
    jsonResult.TryGetValue("messageValue", out messageValue); // note how "messageValue" directly corresponds to the JSON values set in CloudScript
    Debug.Log((string)messageValue);
}

private static void OnErrorShared(PlayFabError error)
{
    Debug.Log(error.GenerateErrorReport());
}

이러한 변경을 하면 이제 CloudScript와 귀하의 클라이언트 사이에서 데이터를 쉽게 보내고 받을 수 있습니다.

참고 항목

클라이언트에서 오는 데이터는 해킹과 악용에 취약함을 지적하는 것이 중요합니다.

백엔드를 업데이트하기 ‘전에’ 항상 입력 매개 변수를 검증하는 것이 좋습니다. 입력 매개 변수를 검증하는 프로세스는 타이틀별로 다르지만 가장 기본적인 검증법은 입력이 허용 가능한 범위와 기간 내에 있는지 확인하는 것입니다.

중급: 서버 API 호출

앞에서 언급한 바와 같이 CloudScript 메서드 내에서 서버 API 호출의 전체 집합에 액세스할 수 있습니다. 그러면 클라우드 코드가 전용 서버 역할을 할 수 있습니다.

공통 서버 작업:

  • 플레이어 통계와 데이터를 업데이트합니다.
  • 아이템과 통화를 부여합니다.
  • 게임 데이터를 무작위로 생성합니다.
  • 배틀 결과 등을 안전하게 계산합니다...

필수 매개 변수와 개체 구조는 PlayFab API 참조 문서에 열거된 서버 API를 참조하세요.

다음 예는 잠재적 CloudScript 처리기 내에서 나왔습니다.

// CloudScript (JavaScript)
//See: JSON.parse, JSON.stringify, parseInt and other built-in javascript helper functions for manipulating data
var currentState; // here we are calculating the current player's game state

// here we are fetching the "SaveState" key from PlayFab,
var playerData = server.GetUserReadOnlyData({"PlayFabId" : currentPlayerId, "Keys" : ["SaveState"]});
var previousState = {}; //if we return a matching key-value pair, then we can proceed otherwise we will need to create a new record.

if(playerData.Data.hasOwnProperty("SaveState"))
{
    previousState = playerData.Data["SaveState"];
}

var writeToServer = {};
writeToServer["SaveState"] = previousState + currentState; // pseudo Code showing that the previous state is updated to the current state

var result = server.UpdateUserReadOnlyData({"PlayFabId" : currentPlayerId, "Data" : writeToServer, "Permission":"Public" });

if(result)
{
    log.info(result);
}
else
{
    log.error(result);
}

고급: PlayStream 이벤트 작업

CloudScript 함수는 PlayStream 이벤트에 대한 응답으로 실행되도록 구성할 수 있습니다.

  1. 브라우저에서:
    • PlayFab 게임 관리자를 방문합니다.
    • 타이틀을 찾습니다.
    • 사이드바의 빌드에서 자동화 탭으로 이동합니다.
    • 규칙 탭으로 이동합니다.

페이지는 아래에 제공된 예와 같습니다.

게임 관리자 - PlayStream - 이벤트 작업

  1. 새 규칙 버튼을 사용하여 새 규칙을 만듭니다.

    • 규칙에 이름을 지정합니다.
    • 조건 또는 작업의 트리거로 사용할 이벤트 유형을 선택합니다.
    • 규칙이 CloudScript 기능을 트리거하도록 하려면 해당 섹션의 버튼과 함께 작업을 추가하세요.
    • 이어서 유형 드롭다운 메뉴에서 옵션을 선택합니다.
    • Cloud Script Function 드롭다운 메뉴에서 helloWorld 함수를 선택합니다.
    • 작업 저장 버튼을 선택합니다.

    게임 관리자 - PlayStream - 작업 저장

  2. 이제 이 규칙은 선택한 유형의 모든 이벤트에서 트리거되도록 설정되었습니다. 테스트하는 방법:

    • Publish results as PlayStream Event(결과를 PlayStream 이벤트로서 게시) 확인란을 선택합니다.
    • 작업을 저장합니다.
    • 이어서 이벤트를 트리거합니다.
    • PlayStream Monitor에는 적절한 정보가 포함된 CloudScript 실행에 해당하는 새 이벤트가 있어야 합니다.
    • 디버거에서 PlayStream 이벤트에 대한 자세한 설명은 고급: CloudScript 디버깅 섹션을 참조하세요.

    참고 항목

    CloudScript 함수를 호출할 때 이벤트 작업은 라이브 수정만 사용할 수 있습니다. 드롭다운 메뉴에서 helloWorld 함수를 찾을 수 없는 경우, 이것이 가장 큰 이유입니다.

고급: CloudScript 디버깅

참고 항목

Azure Functions를 사용하는 CloudScript를 사용하면 디버깅이 훨씬 쉽습니다. Azure Functions를 사용하여 CloudScript에 로컬 디버깅을 사용하는 방법에 대해 자세히 알아봅니다.

로깅

코드를 디버깅하기 위한 가장 중요한 도구 중 하나는 ‘로깅’입니다. CloudScript는 이 기능을 수행하기 위한 유틸리티를 제공합니다.

이는 log 개체 형식을 취하며, Info, Debug, Error 메서드를 사용하여 원하는 메시지를 기록할 수 있습니다.

그뿐만 아니라, HTTP 개체는 logRequestAndResponse 매개 변수를 설정하여 요청하는 중 발생하는 오류를 기록합니다. 이러한 로그를 설정하는 것은 간단하지만 액세스하는 데는 ‘약간의’ 수완이 요구됩니다.

다음은 모두 4가지 유형의 로그를 사용하는 CloudScript 함수의 예입니다.

handlers.logTest = function(args, context) {
    log.info("This is a log statement!");
    log.debug("This is a debug statement.");
    log.error("This is... an error statement?");
    // the last parameter indicates we want logging on errors
    http.request('https://httpbin.org/status/404', 'post', '', 'text/plain', null, true);
};

이 예를 실행하려면 라이브 수정에 이 함수를 추가한 후에 진행하세요.

logTest 함수는 아래와 같이 ExecuteCloudScript를 사용하여 호출할 수 있습니다.

// Invoke this on start of your application
void Login() {
    PlayFabClientAPI.LoginWithCustomID(new LoginWithCustomIDRequest {
        CreateAccount = true,
        CustomId = "Starter"
    }, result => RunLogTest(), null);
}

void RunLogTest() {
    PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest {
        FunctionName = "logTest",
        // duplicates the response of the request to PlayStream
        GeneratePlayStreamEvent = true
    }, null, null);
}
// Logs evaluated in next code block

GeneratePlayStreamEvent를 설정하면 CloudScript 함수 호출이 PlayStream 이벤트를 생성하는 데, 응답의 콘텐츠가 포함됩니다. PlayStream 이벤트의 콘텐츠를 찾는 방법:

  • 타이틀게임 관리자 홈페이지 또는 해당 PlayStream 탭으로 이동합니다.

  • 이벤트가 들어오는 대로 PlayStream 디버거가 이벤트를 표시합니다.

  • 도착하면, 아래 그림과 같이 이벤트의 오른쪽 위에 있는 작은 파란색 정보 아이콘을 선택합니다.

    게임 관리자 - PlayStream - 디버거

이것을 선택하면 이벤트의 원시 JSON이 표시되는 데, 그것은 여기에서 각 이벤트에 대해 자세히 설명되어 있습니다. 이 JSON의 예를 다음 예에서 볼 수 있습니다.

  • 장면에 LogScript MonoBehavior를 추가하는 경우, 게임을 실행하면 PlayStream에서 다음이 생성됩니다.

    게임 관리자 - PlayStream - JSON 이벤트 로그

ExecuteCloudScript 호출의 결과에는 CloudScript 함수에서 생성한 로그 개체 목록인 Logs라는 필드가 포함됩니다.

세 로그 호출뿐만 아니라 잘못된 HTTP 요청의 로그도 볼 수 있습니다. HTTP 요청 로그는 로그 호출과 달리 Data 필드도 사용합니다.

이 필드는 JavaScript 개체로서 로그 문에 관련된 어떤 정보든 채울 수 있습니다. 로그 호출은 아래 설명처럼 두 번째 매개 변수를 사용해 이 필드도 사용할 수 있습니다.

handlers.logTest = function(args, context) {
    log.info("This is a log statement!", { what: "Here on business." });
    log.debug("This is a debug statement.", { who: "I am a doctor, sir" });
    log.error("This is... an error statement?", { why: "I'm here to fix the plumbing. Probably.", errCode: 123 });
};

이러한 호출은 Data 필드를 두 번째 매개 변수의 결과로 모두 채울 것입니다.

로그가 결과에 포함되므로 클라이언트 쪽 코드가 로그 문에 대응할 수 있습니다. logTest 함수의 오류는 강제되지만 클라이언트 코드는 거기에 대응하도록 조정될 수 있습니다.

void RunLogTest()
{
    PlayFabClientAPI.ExecuteCloudScript(
        new ExecuteCloudScriptRequest
        {
            FunctionName = "logTest",
            // handy for logs because the response will be duplicated on PlayStream
            GeneratePlayStreamEvent = true
        },
        result =>
        {
            var error123Present = false;
            foreach (var log in result.Logs)
            {
                if (log.Level != "Error") continue;
                var errData = (JsonObject) log.Data;
                object errCode;
                var errCodePresent = errData.TryGetValue("errCode", out errCode);
                if (errCodePresent && (ulong) errCode == 123) error123Present = true;
            }

            if (error123Present)
                Debug.Log("There was a bad, bad error!");
            else
                Debug.Log("Nice weather we're having.");
        }, null);
}

이 코드를 실행하는 경우, 출력은 오류의 존재를 표시해야 합니다. 현실적 오류 응답은 UI에 오류를 표시하거나 값을 로그 파일에 저장하는 것일 수 있습니다.

고급: 오류

개발에서 CloudScript 오류는 log.error의 경우처럼 종종 수동으로는 트리거되지 않을 것입니다.

다행히, ExecuteCloudScript 응답은 ScriptExecutionError 필드가 포함된 ExecuteCloudScriptResult를 포함합니다. 로깅 섹션의 마지막 예를 조정하여 아래처럼 사용할 수 있습니다.

void RunLogTest() {
    PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest {
        FunctionName = "logTest",
        // handy for logs because the response will be duplicated on PlayStream
        GeneratePlayStreamEvent = true
    }, result => {
        if(result.Error != null) {
            Debug.Log(string.Format("There was error in the CloudScript function {0}:\n Error Code: {1}\n Message: {2}"
            , result.FunctionName, result.Error.Error, result.Error.Message));
        }
    },
    null);
}

어떤 오류가 발생하는 경우, 이 코드가 로그에 그것을 표시할 것입니다.