친구 #

친구는 소셜 커뮤니티를 구축하는 좋은 방법입니다. 사용자는 자신의 친구 목록에 다른 사용자를 추가하고, 온라인 상태 또는 마지막으로 온라인 상태였던 시간을 확인하고, 실시간으로 함께 채팅하고, 게임 플레이 또는 협업에서 함께 상호 작용할 수 있습니다.

각 사용자는 소셜 네트워크에서 이미 알고 있는 친구, 보내거나 받은 친구 요청 및 서버에서 알려주는 친구를 목록으로 작성합니다. 이 정보는 다른 사용자와 상호 작용할 수 있는 강력한 방식으로 시스템 내의 소셜 그래프에 저장됩니다. Twitter나 Facebook이 작동하는 방식과 매우 유사합니다.

모든 소셜 커뮤니티는 스팸이나 남용을 방지하기 위해 세심하게 관리해야 합니다. 이런 문제를 해결하기 위해 사용자가 더 이상 소통하고 싶지 않은 사용자를 차단하고, 서버가 서버 측 코드를 통해 사용자를 금지하여 계정을 완전히 비활성화하는 것도 가능합니다.

Nakama는 친구 또는 동료라는 뜻의 일본어입니다. 이 단어가 “가족보다 더 가깝게 여겨지는 사람"을 의미한다고 생각하는 사람들도 있지만 공식적이지는 않습니다. 개발자들이 자신들의 게임과 앱에 구현하기를 바라는 소셜 커뮤니티를 표현한 것 같습니다!

친구 추가 #

사용자는 해당 사용자의 ID 또는 사용자 이름으로 한 명 이상의 친구를 추가할 수 있습니다. 추가된 사용자가 친구 요청을 확인하기 전까지는 목록에 친구로 표시되지 않습니다. 요청을 받은 사용자는 사용자를 다시 추가하여 확인할 수 있습니다.

친구 요청이 전송되거나 사용자가 추가되면 인앱 알림이 전송됩니다. 자세한 내용은 인앱 알림 섹션을 참조하세요.

Client
1
2
3
var ids = ["user-id1", "user-id2"];
var usernames = ["username1"];
await client.addFriends(session, ids, usernames);
Client
1
2
3
var ids = new[] {"user-id1", "user-id2"};
var usernames = new[] {"username1"};
await client.AddFriendsAsync(session, ids, usernames);
Client
1
2
3
vector<string> ids = { "user-id1", "user-id2" };
vector<string> usernames = { "username1" };
client->addFriends(session, ids, usernames);
Client
1
2
3
List<String> ids = Arrays.asList("user-id1", "user-id2");
String[] usernames = new String[] {"username1"};
client.addFriends(session, ids, usernames).get();
Client
1
2
3
4
5
6
7
var ids = ["user-id1", "user-id2"]
var usernames = ["username1"]
var result : NakamaAsyncResult = yield(client.add_friends_async(session, ids, usernames), "completed")

if result.is_exception():
    print("An error occurred: %s" % result)
    return
Client
1
2
3
4
5
6
7
local ids = { "user-id1", "user-id2" }
local usernames = { "username1" }
local result = client.add_friends(ids, usernames)

if result.error then
  print(result.message)
end
Client
1
2
curl -X POST "http://127.0.0.1:7350/v2/friend?ids=user-id1&ids=user-id2&usernames=username1" \
  -H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
POST /v2/friend?ids=user-id1&ids=user-id2&usernames=username1
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>

두 사용자가 서로 친구로 추가하면 1:1 채널에서 실시간 채팅을 쉽게 시작할 수 있습니다. 자세한 내용은 실시간 채팅 섹션을 참조하세요.

친구 가져오기 #

Facebook, Steam 또는 다른 소셜 네트워크에 자신의 계정을 등록하거나 연결하는 사용자는 해당 네트워크의 친구를 친구 목록으로 가져올 수 있습니다.

또는 필요 시 친구 가져오기를 지원하는 Nakama를 통해 사용자가 언제든지 이 가져오기를 수행하도록 지정할 수 있습니다.

Facebook #

언제든지 사용자의 Facebook 친구를 자신의 앱으로 가져오고 현재 친구 목록을 선택적으로 reset 할 수 있습니다.

Client
1
2
3
const token = "<facebookAuthToken>";
const reset = true;
await client.importFacebookFriends(token, reset);
Client
1
2
3
var token = "<facebookAuthToken>";
var reset = true;
await client.ImportFacebookFriendsAsync(token, reset);
Client
1
2
3
string token = "<facebookAuthToken>";
bool reset = true;
client->importFacebookFriends(token, reset);
Client
1
2
3
String token = "<facebookAuthToken>";
Bool reset = true;
client.importFacebookFriends(token, reset).get();
Client
1
2
3
4
5
6
7
var token = "<facebookAuthToken>"
var reset = true
var result : NakamaAsyncResult = yield(client.import_facebook_friends(token, reset), "completed")

if result.is_exception():
    print("An error occurred: %s" % result)
    return
Client
1
2
3
4
5
6
7
local token = "<facebookAuthToken>"
local reset = true
local result = client.import_facebook_friends(token, nil, reset)

if result.error then
  print(result.message)
end
Client
1
2
3
curl -X POST "http://127.0.0.1:7350/v2/friend/facebook" \
  -H 'Authorization: Bearer <session token>'
  -d '{"token": <facebookAuthToken>, "reset": true}'
Client
1
2
3
4
5
6
7
8
9
POST /v2/friend/facebook
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{
  "token": "<facebookAuthToken>",
  "reset": true
}

Steam #

언제든지 사용자의 Facebook 친구를 자신의 앱으로 가져오고 현재 친구 목록을 선택적으로 reset 할 수 있습니다.

Client
1
2
3
const steamToken = "<steamToken>";
const reset = true;
await client.importSteamFriends(steamToken, reset);
Client
1
2
3
var steamToken = "<steamToken>";
var reset = true;
await client.ImportSteamFriendsAsync(steamToken, reset);
Client
1
2
3
string steamToken = "<steamToken>";
bool reset = true;
client->importSteamFriends(steamToken, reset);
Client
1
2
3
String steamToken = "<steamToken>";
Bool reset = true;
client.importSteamFriends(steamToken, reset).get();
Client
1
2
3
4
5
6
7
var steam_token = "<steam_token>"
var reset = true
var result : NakamaAsyncResult = yield(client.import_steam_friends(steam_token, reset), "completed")

if result.is_exception():
    print("An error occurred: %s" % result)
    return
Client
1
2
3
4
5
6
7
local steam_token = "<steam_token>";
local reset = true
local result = client.import_steam_friends(steam_token, nil, reset)

if result.error then
  print(result.message)
end
Client
1
2
3
curl -X POST "http://127.0.0.1:7350/v2/friend/steam" \
  -H 'Authorization: Bearer <session token>'
  -d '{"steamToken": <steamToken>, "reset": true}'
Client
1
2
3
4
5
6
7
8
9
POST /v2/friend/steam
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{
  "steamToken": "<steamToken>",
  "reset": true
}

친구 나열 #

사용자의 친구, 차단된 사용자, 받은 친구 요청(초대됨), 보낸 초대를 모두 나열할 수 있습니다. 이러한 상태는 친구 목록의 일부로 함께 반환되므로 UI에 쉽게 표시할 수 있습니다. 단일 친구 목록은 최대 1000명의 친구 페이지를 반환합니다. 반환된 커서를 후속 목록 호출에 전달하면 더 많은 친구 페이지가 검색됩니다.

Client
1
2
const friends = await client.listFriends(session);
console.info("Successfully retrieved friend list:", friends);
Client
1
2
3
4
5
6
var result = await client.ListFriendsAsync(session);

foreach (var f in result.Friends)
{
    System.Console.WriteLine("Friend '{0}' state '{1}'", f.User.Username, f.State);
}
Client
1
2
3
4
5
6
auto successCallback = [](NFriendsPtr friends)
{
    std::cout << "Successfully retrieved friend list: " << friends->friends.size() << std::endl;
};

client->listFriends(session, {}, {}, {}, successCallback);
Client
1
2
3
4
5
Friends friends = client.listFriends(session).get();

for (Friend friend : friends.getFriendsList()) {
  System.out.format("Friend %s state %d", friend.getUser().getUsername(), friend.getState());
}
Client
1
2
3
4
5
6
7
8
9
var list : NakamaAPI.ApiFriendList = yield(client.list_friends_async(session), "completed")

if list.is_exception():
    print("An error occurred: %s" % list)
    return

for f in list.friends:
    var friend = f as NakamaAPI.ApiFriend
    print("User %s, status %s" % [friend.user.id, friend.state])
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
local result = client.list_friends()

if result.error then
  print(result.message)
  return
end

for _,friend in ipairs(result.friends) do
  pprint(friend)
end
Client
1
2
curl -X GET "http://127.0.0.1:7350/v2/friend" \
  -H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
GET /v2/friend
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>

친구 제거 #

사용자는 친구를 제거하거나 받은 초대를 거부하거나 보낸 친구 요청을 취소하거나 사용자를 차단 해제할 수 있습니다. 사용자가 차단 해제되면 친구 목록에서 완전히 제거됩니다. 다시 추가하려면 각 사용자가 다른 사용자를 다시 추가해야 합니다.

친구 추가가 작동하는 방식과 유사하게 친구 제거를 재사용하여 다른 사용자의 현재 친구 상태를 취소하거나 실행 취소합니다.

Client
1
2
3
var ids = ["user-id1", "user-id2"];
var usernames = ["username1"];
await client.deleteFriends(session, ids, usernames);
Client
1
2
3
var ids = new[] {"user-id1", "user-id2"};
var usernames = new[] {"username1"};
await client.DeleteFriendsAsync(session, ids, usernames);
Client
1
2
3
vector<string> ids = { "user-id1", "user-id2" };
vector<string> usernames = { "username1" };
client->deleteFriends(session, ids, usernames);
Client
1
2
3
List<String> ids = Arrays.asList("user-id1", "user-id2");
String[] usernames = new String[] {"username1"};
client.deleteFriends(session, ids, usernames).get();
Client
1
2
3
4
5
6
7
8
9
var ids = ["user-id1", "user-id2"]
var usernames = ["username1"]
var remove : NakamaAsyncResult = yield(client.delete_friends_async(session, ids, usernames), "completed")

if remove.is_exception():
    print("An error occurred: %s" % remove)
    return

print("Remove friends: user ids %s, usernames %s" % [ids, usernames])
Client
1
2
3
4
5
6
7
local ids = { "user-id1", "user-id2" }
local usernames = { "username1" }
local result = client.delete_friends(ids, usernames)

if result.error then
  print(result.message)
end
Client
1
2
curl -X DELETE "http://127.0.0.1:7350/v2/friend?ids=user-id1&ids=user-id2&usernames=username1" \
  -H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
DELETE /v2/friend?ids=user-id1&ids=user-id2&usernames=username1
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>

친구 차단 #

친구를 차단하면 해당 친구는 1:1 채팅 또는 기타 소셜 기능을 사용하지 못합니다. 차단을 원하는 사용자는 메시지를 보내야 합니다. 나중에 친구 제거 메시지로 차단을 해제할 수 있습니다.

차단된 사용자는 자신을 차단한 사용자를 알 수 없습니다. 해당 사용자는 계속해서 친구를 추가하고 다른 사용자와 상호 작용할 수 있습니다.

Client
1
2
3
var ids = ["user-id1", "user-id2"];
var usernames = ["username1"];
await client.blockFriends(session, ids, usernames);
Client
1
2
3
var ids = new[] {"user-id1", "user-id2"};
var usernames = new[] {"username1"};
await client.BlockFriendsAsync(session, ids, usernames);
Client
1
2
3
vector<string> ids = { "user-id1", "user-id2" };
vector<string> usernames = { "username1" };
client->blockFriends(session, ids, usernames);
Client
1
2
3
List<String> ids = Arrays.asList("user-id1", "user-id2");
String[] usernames = new String[] {"username1"};
client.blockFriends(session, ids, usernames).get();
Client
1
2
3
4
5
6
7
8
9
var ids = ["user-id1", "user-id2"]
var usernames = ["username1"]
var block : NakamaAsyncResult = yield(client.block_friends_async(session, ids, usernames), "completed")

if block.is_exception():
    print("An error occurred: %s" % block)
    return

print("Remove friends: user ids %s, usernames %s" % [ids, usernames])
Client
1
2
3
4
5
6
7
local ids = { "user-id1", "user-id2" }
local usernames = { "username1" }
local result = client.block_friends(ids, usernames)

if result.error then
  print(result.message)
end
Client
1
2
curl -X POST "http://127.0.0.1:7350/v2/friend/block?ids=user-id1&ids=user-id2&usernames=username1" \
  -H 'Authorization: Bearer <session token>'
Client
1
2
3
4
5
POST /v2/friend/block?ids=user-id1&ids=user-id2&usernames=username1
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>

친구 금지 #

사용자는 서버 측 코드로 금지될 수 있습니다.

이것은 플레이어 커뮤니티 내의 중재자 시스템에서 사용하면 가장 좋습니다. 어떤 사용자를 영구적으로 금지하기 위해 RPC를 보낼 수 있는 기능을 특정 사용자에게 할당할 수 있습니다.

Server
1
2
3
4
5
6
7
8
local nk = require("nakama")

local bad_users = {"someuserid", "anotheruserid"}
local success, err = pcall(nk.users_ban_id, bad_users)

if (not success) then
  nk.logger_error(("Ban failed: %q"):format(err))
end
Server
1
2
3
4
5
6
if err := nk.UsersBanId(ctx, []string{
    "someruserid",
    "anotheruserid",
}); err != nil {
    logger.Error("Ban failed: %s", err.Error())
}
Server
1
2
3
4
5
6
7
let badUsers = ['someuserid', 'anotheruserid'];

try {
  nk.usersBanId(badUsers);
} catch (error) {
  // Handle error
}

사용자를 금지하면 나중에 서버에 연결하고 상호 작용할 수 없지만 암시적으로 로그아웃하거나 세션 연결이 끊어지지는 않습니다.

금지된 사용자가 여전히 유효한 인증 토큰을 사용해도 다시 연결할 수 없도록 하고, 열려 있는 소켓 연결이 닫히도록 하려면 사용자를 금지 로그아웃 하고 활성 세션을 연결 해제해야 합니다. 사용자 금지에 대한 전체 예를 참조하세요.

친구 상태 #

코드목적
0사용자는 서로 친구입니다.
1사용자 A가 초대를 보냈고 사용자 B의 수락을 대기 중입니다.
2사용자 A는 초대를 받았지만 아직 수락하지 않았습니다.
3사용자 A가 사용자 B를 금지했습니다.