Server Runtime Examples #

Initialize a user #

User a register hook to write records for the new user after their registration has completed.

The “register_after” hook can be used with one of the "authenticaterequest_*" message types to tell the server to run a function after that message has been processed. It’s important to note that the server does not distinguish between register and login messages so we use a conditional write to store the records.

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 to 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 to 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
}
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let initializeUser : nkruntime.AfterHookFunction<nkruntime.Session, nkruntime.AuthenticateDeviceRequest> = function (ctx: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama, out: nkruntime.Session, data: nkruntime.AuthenticateDeviceRequest) : nkruntime.Session {
  const changeset = {
    "coins": 10, // Add 10 coins to the user's wallet
    "gems": 5, // Add 5 gems to the user's wallet
    "artifacts": 0 // No artifacts to start with
  };
  
  nk.walletUpdate(ctx.userId, changeset, null, true);
  return out;
};

// Register as after hook, this call should be in InitModule.
initializer.registerAfterAuthenticateDevice(initializeUser);

Storage #

Writing to storage #

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
25
26
27
28
29
func AuthoritativeWriteRPC(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
	userID, _ := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)

	data := map[string]interface{}{
		"achievementPoints": 100,
		"unlockedAchievements": []string{"max-level", "defeat-boss-2", "equip-rare-gear"},
	}

	bytes, err := json.Marshal(data)
	if err != nil {
		return "", runtime.NewError("error marshaling data", 13)
	}

	write := &runtime.StorageWrite{
		Collection:      "Unlocks",
		Key:             "Achievements",
		UserID:          userID,
		Value:           string(bytes),
		PermissionRead:  1, // Only the server and owner can read
		PermissionWrite: 0, // Only the server can write
	}

	_, err = nk.StorageWrite(ctx, []*runtime.StorageWrite{write})
	if err != nil {
		return "", runtime.NewError("error saving data", 13)
	}
	
	return "<JsonResponse>", nil
}
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
let authoritativeWriteRpc : nkruntime.RpcFunction = function (ctx: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama, payload: string) : string | void {
  const data = {
    achievementPoints: 100,
    unlockedAchievements: ['max-level', 'defeat-boss-2', 'equip-rare-gear']
  };

  const write : StorageWriteRequest = {
    collection: 'Unlocks',
    key: 'Achievements',
    userId: ctx.userId,
    value: data,
    permissionRead: 1, // Only the server and owner can read
    permissionWrite: 0 // Only the server can write
  };

  nk.storageWrite([write]);

  return "<JsonResponse>";
};
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
local authoritative_write_rpc = function(context, payload)
    local data = {
        ["achievementPoints"] = 100,
        ["unlockedAchievements"] = { "max-level", "defeat-boss-2", "equip-rare-gear" }
    }

    local write = {
        collection = "Unlocks",
        key = "Achievements",
        user_id = context.user_id,
        value = data,
        permission_read = 1,
        permission_write = 0
    }
    
    nk.storage_write({ write })

    return "<JsonResponse>"
end

Related Pages