새로운 사용자 초기화 #

새로운 사용자 등록 시 레코드 설정이 많은 경우에 유용하게 사용할 수 있습니다. 게임에서는 사용자의 가상 지갑, 초기 인벤토리 아이템 등에서 필요할 수 있습니다. 이번 튜토리얼에서는 이러한 사례를 해결할 수 있는 몇 가지 방법을 다루도록 하겠습니다.

콜백 등록 후 #

가장 간단한 방법은 클라이언트에서 등록 기능의 성공적인 콜백에 대해서 레코드를 작성하는 것입니다.

이 코드는 예시를 통해서 처리하는 방법에 대해서 설명합니다. 실제 사용하는 코드에서는 인증을 분리하고 연결과 재연결을 관리하는 방법에 따라 저장소 쓰기에서 로직을 연결합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var deviceId = SystemInfo.deviceUniqueIdentifier;
var session = await client.AuthenticateDeviceAsync(deviceId);

var json = "{\"coins\": 100, \"gems\": 10, \"artifacts\": 0}";
var object = new WriteStorageObject = {
  "collection" = "wallets",
  "key" = "mywallet",
  "value" = json
};
const storageWriteAck = await client.WriteStorageObjectsAsync(session, objects);
Debug.Log("Successfully setup new user's records.");

이 코드는 장단점이 있습니다. 레코드가 저장소에 작성되기 전에 연결이 해제될 수 있습니다. 사용자 설정이 완전하지 않아서 애플리케이션의 상태가 양호하지 않을 수 있습니다.

서버 측 코드를 작성하지 않거나 클라이언트 위에 재시도 로직을 빌드한 경우에 이 옵션을 선택하는 것이 좋습니다.

서버 측 후크 #

새로운 사용자에 대해서 레코드를 작성하는 다른 방법은 등록이 완료된 후에 서버 측 코드를 실행하는 것입니다. 등록 후크를 통해서 완료할 수 있습니다.

“register_after” 후크는 "authenticaterequest_*" 메시지 유형과 함께 사용하여 메시지가 처리된 후에 서버가 기능을 실행하도록 전달합니다. 서버에서는 등록과 로그인 메시지가 구분되지 않기 때문에 조건부 작성을 사용하여 레코드를 저장합니다.

Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
local function initialize_user(context, payload)
  if payload.created then
    -- Only run this logic if the account that has authenticated is new.
    local changeset = {
      coins = 10,   -- Add 10 coins to the user's wallet.
      gems = 5      -- Add 5 gems from the user's wallet.
      artifacts = 0 -- No artifacts to start with.
    }
    local metadata = {}
    nk.wallet_update(context.user_id, changeset, metadata, true)
  end
end

-- change to whatever message name matches your authentication type.
nk.register_req_after(initialize_user, "AuthenticateDevice")
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func InitializeUser(ctx context.Context, logger Logger, db *sql.DB, nk NakamaModule, out *api.Session, in *api.AuthenticateDeviceRequest) error {
  if out.Created {
    // Only run this logic if the account that has authenticated is new.
    userID, ok := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)
    if !ok {
      return "", errors.New("Invalid context")
    }
    changeset := map[string]interface{}{
      "coins": 10,    // Add 10 coins to the user's wallet.
      "gems":  5,     // Add 5 gems from the user's wallet.
      "artifacts": 0, // No artifacts to start with.
    }
    var metadata map[string]interface{}
    if err := nk.WalletUpdate(ctx, userID, changeset, metadata, true); err != nil {
      // Handle error.
    }
  }
}

// Register as after hook, this call should be in InitModule.
if err := initializer.RegisterAfterAuthenticateDevice(InitializeUser); err != nil {
  logger.Error("Unable to register: %v", err)
  return err
}
Code snippet for this language TypeScript has not been found. Please choose another language to show equivalent examples.

이 방법을 사용하면 클라이언트 연결 해제를 방지할 수 있지만 로그인 또는 등록 메시지 이후에 데이터베이스를 작성해야 합니다. 저장소 엔진에 데이터를 얼마나 자주 작성하는지에 따라서 허용될 수도 있으며, 빠른 재연결을 위해서 사용자 세션에 캐시를 적용하면 연결 해제를 최소화할 수 있습니다.