メインコンテンツまでスキップ

ソーシャル機能

ソーシャルシステムは、リアルタイムチャット、ギルド、プレゼンス追跡付きフレンド、およびプレイヤー間のモンスター/アイテムトレードを提供します。すべてのサービスはNakamaの組み込みソーシャルAPI(Groups、Friends、Chatチャンネル)とリアルタイムマッチ(トレード用)を使用します。

アーキテクチャ概要​

クラスファイル責任
ChatServiceSocial/SocialServices.cs7つのチャンネルタイプを持つリアルタイムチャット
GuildServiceSocial/SocialServices.csNakama Groupsを使用したギルドCRUD、ロール、メンバー管理
FriendServiceSocial/SocialServices.csフレンドリスト、プレゼンス追跡、ブロック
TradeServiceSocial/SocialServices.csサーバー検証済みステートマシンによるP2Pトレード

NakamaManager.Instanceからアクセス:

var chat = NakamaManager.Instance.Chat;
var guilds = NakamaManager.Instance.Guilds;
var friends = NakamaManager.Instance.Friends;
var trade = NakamaManager.Instance.Trade;

チャットシステム​

ChatServiceはNakamaのチャンネルメッセージングを使用したマルチチャンネルリアルタイムチャットシステムを実装しています。

チャンネルタイプ​

ChatChannel列挙型は7つのチャンネルタイプを定義します:

チャンネル説明
Globalサーバー全体の公開チャット
Local近くのプレイヤーに表示(同じマップ/エリア)
Trade経済およびトレードの議論
Guildギルド専用メッセージ
Whisperプライベートな1対1のダイレクトメッセージ
Systemサーバーからのアナウンスと通知
Battleバトル関連のコミュニケーション

チャンネルへの参加​

グローバルチャンネルは接続中にJoinGlobalChannelAsync()を介して自動的に参加します。永続化が有効なNakamaのRoomタイプチャンネルを使用します:

// 接続時に自動化 -- ただし手動で呼び出すことも可能
await chat.JoinGlobalChannelAsync();

メッセージの送信​

// 公開チャンネルに送信
await chat.SendMessageAsync(ChatChannel.Global, "Hello everyone!");
await chat.SendMessageAsync(ChatChannel.Trade, "WTB: Rare Candy x10");

// ウィスパー(ダイレクトメッセージ)
await chat.SendMessageAsync(ChatChannel.Whisper, "Hey!", targetId: recipientUserId);

ウィスパーはNakamaのDirectMessageチャンネルタイプを使用します。サービスは送信前に自動的に対象ユーザーとのDMチャンネルに参加します。

メッセージの受信​

chat.OnMessageReceived += (ChatMessage msg) =>
{
// msg.SenderId, msg.SenderName, msg.Content
// msg.Channel (ChatChannel enum), msg.Timestamp
};

// メッセージ履歴にアクセス(ChatHistoryCountで上限)
IReadOnlyList<ChatMessage> history = chat.History;

メッセージ履歴はOnlineConfig.ChatHistoryCount(デフォルト:50)で上限が設定されています。上限を超えると最も古いメッセージが削除されます。

チャンネルイベント​

chat.OnChannelJoined += (ChatChannel channel) =>
{
Debug.Log($"Joined {channel} channel");
};

クリーンアップ​

すべてのチャンネルは切断時に退出されます:

await chat.LeaveAllChannelsAsync();

ギルドシステム​

GuildServiceはNakamaのGroups APIを使用してギルド(チーム/クラブ)を管理します。

ギルドの作成​

GuildInfo guild = await guilds.CreateGuildAsync(
name: "Team Rocket",
tag: "TR",
description: "Prepare for trouble!");

// guild.Id, guild.Name, guild.Tag, guild.MemberCount, guild.MaxMembers

ギルドあたりの最大メンバー数:OnlineConfig.MaxGuildMembers(デフォルト:50)。

参加と脱退​

bool joined = await guilds.JoinGuildAsync(guildId);
bool left = await guilds.LeaveGuildAsync();

ギルドロール​

GuildRole列挙型は権限階層を定義します:

ロール値権限
Leader0完全な制御(キック、昇格、解散)
Officer1メンバーのキック、設定の管理
Member2標準的な参加
Recruit3制限付きアクセス(試用期間)

メンバー管理​

// メンバーを昇格
await guilds.PromoteMemberAsync(memberId, GuildRole.Officer);

// メンバーをキック
await guilds.KickMemberAsync(memberId);

ギルドの検索​

List<GuildInfo> results = await guilds.SearchGuildsAsync("Rocket");

foreach (var g in results)
{
// g.Id, g.Name, g.Description
// g.MemberCount, g.MaxMembers
}

ギルド状態​

bool isInGuild = guilds.IsInGuild;
GuildInfo current = guilds.CurrentGuild;

guilds.OnGuildUpdated += (GuildInfo info) => { };
guilds.OnMemberJoined += (string userId) => { };
guilds.OnMemberLeft += (string userId) => { };

フレンドシステム​

FriendServiceはNakamaのFriends APIをステータスイベントによるリアルタイムプレゼンス追跡とともに使用します。

フレンドの読み込み​

フレンドは接続中に自動的に読み込まれます:

await friends.RefreshFriendsListAsync(userId);

これはClient.ListFriendsAsync(OnlineConfig.MaxFriendsまで、デフォルト:100)を呼び出し、その後Socket.FollowUsersAsync()で全てのフレンドのステータスをフォローしてリアルタイムプレゼンス更新を受信します。

フレンドリクエスト​

// フレンドリクエストを送信
bool sent = await friends.SendFriendRequestAsync(targetUserId);

// フレンドリクエストを承認
bool accepted = await friends.AcceptFriendRequestAsync(fromUserId);

// フレンドを削除
bool removed = await friends.RemoveFriendAsync(friendId);

プレゼンス追跡​

リアルタイムプレゼンス更新はソケットのReceivedStatusPresenceを介して届きます:

friends.OnFriendOnline += (FriendInfo info) =>
{
Debug.Log($"{info.DisplayName} is online!");
};

friends.OnFriendOffline += (string userId) =>
{
Debug.Log($"Friend {userId} went offline");
};

friends.OnFriendRequestReceived += (FriendInfo info) =>
{
// フレンドリクエスト通知を表示
};

フレンドデータ​

IReadOnlyList<FriendInfo> list = friends.FriendsList;

foreach (var f in list)
{
// f.UserId, f.DisplayName, f.IsOnline
// f.CurrentMap, f.Level
}

ブロック​

bool blocked = await friends.BlockUserAsync(userId);

NakamaのBlockFriendsAsyncを使用し、すべてのやり取りを防止します。

プレイヤー間トレード​

TradeServiceはNakamaのリアルタイムマッチとステートマシンプロトコルを使用した完全なP2Pトレードシステムを実装しています。

トレードプロトコルOpCode​

OpCode定数意味
100OP_TRADE_REQUEST初期トレードリクエスト
101OP_TRADE_OFFERプレイヤーがモンスターまたはアイテムを提示
102OP_TRADE_CONFIRMプレイヤーがトレードを確認
103OP_TRADE_CANCELプレイヤーがトレードをキャンセル
104OP_TRADE_COMPLETEサーバーがトレード完了を確認

トレード状態​

TradeState列挙型はトレードのライフサイクルを追跡します:

Pending -> Offering -> Confirming -> Completed(または任意の時点でCancelled)

トレードの開始​

string tradeId = await trade.RequestTradeAsync(targetUserId);

これによりトレードセッション用のNakamaマッチが作成され、trade_request RPCを介して対象者に通知されます。

アイテムの提示​

// モンスターを提示
await trade.OfferMonsterAsync(tradeId, monsterId);

// アイテムを提示
await trade.OfferItemAsync(tradeId, itemId: "rare_candy", quantity: 5);

提示はOP_TRADE_OFFERを使用したマッチ状態メッセージとして送信されます。

確認と完了​

// 両方のプレイヤーが確認する必要があります
await trade.ConfirmTradeAsync(tradeId);

両方のプレイヤーが確認すると、サーバーがトレードをアトミックに実行し、OP_TRADE_COMPLETEを送信します。

キャンセル​

await trade.CancelTradeAsync(tradeId);

OP_TRADE_CANCELを送信し、マッチを退出し、アクティブなトレードをクリアします。

トレードイベント​

trade.OnTradeRequestReceived += (string fromUserId, string fromName) => { };
trade.OnTradeStateChanged += (TradeState state) => { };
trade.OnTradeCompleted += (bool success) =>
{
if (success) Debug.Log("Trade completed!");
else Debug.Log("Trade was cancelled.");
};

トレード状態プロパティ​

bool isTrading = trade.IsTrading;
string activeTradeId = trade.ActiveTradeId;
string activeMatchId = trade.ActiveMatchId;

トレードマッチの状態はNakamaManagerのReceivedMatchStateハンドラーも経由し、Trade.HandleMatchState()に転送されます。

ソーシャル通知​

NakamaManagerはすべてのNakama通知を統合イベントを通じて提供します:

NakamaManager.Instance.OnNotification += (string subject, string content) =>
{
Debug.Log($"Notification: {subject} - {content}");
};

さらに、一般的なソーシャルアクション用の専用イベントも存在します:

NakamaManager.Instance.OnBattleInvite += (string fromUserId) => { };
NakamaManager.Instance.OnTradeRequest += (string fromUserId) => { };
NakamaManager.Instance.OnFriendRequest += (string fromUserId) => { };

設定リファレンス​

設定フィールドデフォルト説明
MaxFriends100プレイヤーあたりの最大フレンド数
MaxGuildMembers50最大ギルドメンバー数
ChatHistoryCount50メモリに保持するチャットメッセージ数