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

unity-module-create-joinable-session-p2p-overview-use-accelbyte-sdk-to-create-match-session

Last updated on February 4, 2026

注釈:本資料はAI技術を用いて翻訳されています。

備考

AccelByte Gaming Services (AGS) SDK for Unity は WebGL 上での P2P をサポートしていません。このモジュールは WebGL ビルドでは使用できません。

ラッパーを開く

このチュートリアルでは、AccelByte Gaming Services (AGS) Software Development Kit (SDK) を使用して AGS マッチメイキングを実装する方法を学びます。Byte Wars では、ゲームインスタンスラッパーが MatchSessionP2PWrapper クラスで定義されています。このラッパーは、ゲームセッションの作成や閲覧などのゲームセッション関連のアクションを管理します。このチュートリアルでは、MatchSessionP2PWrapper クラスのスターターバージョンである MatchSessionP2PWrapper_Starter クラスを使用します。

スターターパックの内容

このチュートリアルに従うには、MatchSessionP2PWrapper_Starter というスターターラッパークラスを使用します。このクラスは、以下のファイルで定義されている MatchSessionEssentialsWrapper クラスを継承しています。

  • C# ファイル: Assets/Resources/Modules/Play/MatchSessionEssentials/Scripts/MatchSessionEssentialsWrapper.cs

MatchSessionP2PWrapper_Starter クラスは以下のファイルで定義されています。

  • C# ファイル: Assets/Resources/Modules/Play/MatchSessionP2P/Scripts/MatchSessionP2PWrapper_Starter.cs

さらに、ヘルパー関数と変数を含むモデルクラスが以下のファイルで定義されています。

  • C# ファイル: Assets/Resources/Modules/Play/OnlineSessionUtils/Scripts/AccelByteWarsOnlineSessionModels.cs
  • C# ファイル: Assets/Resources/Modules/Play/MatchSessionEssentials/Scripts/MatchSessionEssentialsModels.cs

MatchSessionEssentialsWrapper 自体は SessionEssentialsWrapper クラスを継承しており、このクラスには参加、退出、セッション招待の拒否などの基本的なセッション管理機能が含まれています。この機能の実装方法については、前の Introduction to Session モジュールで学習しました。

MatchSessionEssentialsWrapper のルート親クラスである AccelByteWarsOnlineSession クラスには、以下を含むいくつかの事前定義されたヘルパーコンポーネントも含まれています。

  • ピアツーピアホストを開始し、ゲームクライアントをピアツーピアホストに接続するヘルパーメソッド。AccelByte SDK を使用して P2P ネットワーキングを統合するには、ネットワークトランスポートとして AccelByteNetworkTransportManager プラグインを使用する必要があります。

    public virtual void TravelToP2PHost(SessionV2GameSession session, InGameMode gameMode)
    {
    AccelByteNetworkTransportManager transportManager = NetworkManager.Singleton.GetComponent<AccelByteNetworkTransportManager>();
    if (transportManager == null)
    {
    transportManager = NetworkManager.Singleton.gameObject.AddComponent<AccelByteNetworkTransportManager>();
    transportManager.Initialize(AccelByteSDK.GetClientRegistry().GetApi());
    transportManager.OnTransportEvent += GameManager.Instance.OnTransportEvent;
    }

    InitialConnectionData initialData = new InitialConnectionData()
    {
    inGameMode = gameMode,
    serverSessionId = session.id,
    userId = GameData.CachedPlayerState.PlayerId
    };
    NetworkManager.Singleton.NetworkConfig.ConnectionData = GameUtility.ToByteArray(initialData);
    NetworkManager.Singleton.NetworkConfig.NetworkTransport = transportManager;

    bool isHost = session.leaderId == GameData.CachedPlayerState.PlayerId;
    GameManager.Instance.ShowTravelingLoading(() =>
    {
    GameManager.Instance.ResetCache();
    GameData.ServerType = ServerType.OnlinePeer2Peer;

    if (isHost)
    {
    BytewarsLogger.Log("Start as P2P host");
    GameData.ServerSessionID = session.id;
    NetworkManager.Singleton.StartHost();
    }
    else
    {
    BytewarsLogger.Log($"Start as P2P client. Target host: {session.leaderId}");
    transportManager.SetTargetHostUserId(session.leaderId);
    NetworkManager.Singleton.StartClient();
    }
    },
    isHost ? StartingAsHostMessage : WaitingHostMessage);
    }

AccelByteWarsOnlineSessionModels ファイルには、以下を含むいくつかの事前定義されたヘルパーコンポーネントが含まれています。

  • Admin Portal で設定された Session Template に基づいて、セッションテンプレート名を保存する文字列定数:

    public const string EliminationP2PSessionTemplateName = "unity-elimination-p2p";
    public const string TeamDeathmatchP2PSessionTemplateName = "unity-teamdeathmatch-p2p";
  • セッションテンプレート名に基づいて、ゲーム内モードをセッションリクエストモデルにマッピングするヘルパー辞書:

    public static readonly Dictionary<InGameMode, Dictionary<GameSessionServerType, SessionV2GameSessionCreateRequest>> SessionCreateRequestModels = new()
    {
    ...
    {
    InGameMode.CreateMatchElimination, new()
    {
    ...
    {
    GameSessionServerType.PeerToPeer,
    new SessionV2GameSessionCreateRequest()
    {
    type = SessionConfigurationTemplateType.P2P,
    joinability = SessionV2Joinability.OPEN,
    configurationName = EliminationP2PSessionTemplateName,
    matchPool = EliminationP2PSessionTemplateName,
    }
    },
    ...
    }
    },
    {
    InGameMode.CreateMatchTeamDeathmatch, new()
    {
    ...
    {
    GameSessionServerType.PeerToPeer,
    new SessionV2GameSessionCreateRequest()
    {
    type = SessionConfigurationTemplateType.P2P,
    joinability = SessionV2Joinability.OPEN,
    configurationName = TeamDeathmatchP2PSessionTemplateName,
    matchPool = TeamDeathmatchP2PSessionTemplateName,
    }
    },
    ...
    }
    }
    ...
    };
  • ゲーム内モードでセッションリクエストモデルを取得するヘルパー関数:

    public static SessionV2GameSessionCreateRequest GetGameSessionRequestModel(
    InGameMode gameMode,
    GameSessionServerType serverType)
    {
    if (!SessionCreateRequestModels.TryGetValue(gameMode, out var matchTypeDict))
    {
    return null;
    }

    matchTypeDict.TryGetValue(serverType, out var request);
    return request;
    }

MatchSessionEssentialsModels ファイルには、以下を含むいくつかの事前定義されたヘルパーコンポーネントが含まれています。

  • サーバータイプに基づいてゲームセッションクエリをフィルタリングするために使用されるカスタム定数。

    public static readonly string MatchSessionAttributeKey = "match_session_type";
    public static readonly string MatchSessionP2PAttributeValue = "unity_match_session_p2p";

    public static readonly Dictionary<string, object> MatchSessionP2PAttribute = new()
    {
    { MatchSessionAttributeKey, MatchSessionP2PAttributeValue }
    };
  • ゲームセッションの閲覧結果を構築するヘルパークラス。

    public class BrowseSessionModel
    {
    public SessionV2GameSession Session { get; private set; }
    public AccountUserPlatformData Owner { get; private set; }
    public int CurrentMemberCount { get; private set; }
    public int MaxMemberCount { get; private set; }
    public InGameMode GameMode { get; private set; }
    public GameSessionServerType ServerType { get; private set; }

    public BrowseSessionModel()
    {
    Session = null;
    Owner = null;

    CurrentMemberCount = 0;
    MaxMemberCount = 0;

    GameMode = InGameMode.None;
    ServerType = GameSessionServerType.None;
    }

    public BrowseSessionModel(SessionV2GameSession session, AccountUserPlatformData owner)
    {
    Session = session;
    Owner = owner;

    CurrentMemberCount = session.members.Count(member => member.status == SessionV2MemberStatus.JOINED);
    MaxMemberCount = session.configuration.maxPlayers;

    GameMode = GetGameSessionGameMode(session);
    ServerType = GetGameSessionServerType(session);
    }
    }

    public class BrowseSessionResult
    {
    public readonly Dictionary<string, object> QueryAttribute;
    public readonly PaginatedResponse<BrowseSessionModel> Result;

    public BrowseSessionResult(
    Dictionary<string, object> queryAttribute,
    PaginatedResponse<BrowseSessionModel> result)
    {
    QueryAttribute = queryAttribute;
    Result = result;
    }
    }

マッチセッションを作成する

このセクションでは、AGS SDK を使用してピアツーピアでゲームセッションを作成する方法を説明します。

  1. MatchSessionP2PWrapper_Starter クラスを開き、以下の関数を作成します。この関数は、いくつかの属性を追加してセッション作成リクエストを充実させます。次に、親クラスの関数を呼び出してセッション作成リクエストを送信します。これは Introduction to Session モジュールで学習した内容です。リクエストが完了すると、ピアツーピアホストが接続可能かどうかを確認します。以下のコードから、オプションの属性にいくつかの値を追加してリクエストを充実させていることがわかります。これらの属性の機能は次のとおりです。

    • members: セッションメンバーを追加するために使用される属性。この場合、パーティーメンバーをゲームセッションに参加させるために使用されます。
    • attributes: ゲームセッションに追加できるカスタム属性リスト。この場合、カスタム MatchSessionP2PAttribute 属性を使用してサーバータイプでセッションをフィルタリングするために使用されます。
    public override void CreateGameSession(
    SessionV2GameSessionCreateRequest request,
    ResultCallback<SessionV2GameSession> onComplete)
    {
    // Add party session id for playing with party feature.
    if (CachedParty != null && !string.IsNullOrEmpty(CachedParty.id))
    {
    request.teams = new SessionV2TeamData[]
    {
    new SessionV2TeamData
    {
    TeamId = CachedParty.id,
    userIds = CachedParty.members.Where(m => m.StatusV2 == SessionV2MemberStatus.JOINED).Select(m => m.id).ToArray()
    }
    };
    }

    // Add custom attribute as filter for session browser.
    request.attributes = MatchSessionP2PAttribute;

    base.CreateGameSession(request, (result =>
    {
    if (!result.IsError)
    {
    InGameMode requestedGameMode = GetGameSessionGameMode(result.Value);
    if (requestedGameMode == InGameMode.None)
    {
    BytewarsLogger.LogWarning($"Failed to travel to the P2P host. Session's game mode is not supported by the game.");
    onComplete?.Invoke(Result<SessionV2GameSession>.CreateError(ErrorCode.NotAcceptable, InvalidSessionTypeMessage));
    return;
    }
    TravelToP2PHost(result.Value, requestedGameMode);
    }

    onComplete?.Invoke(result);
    }));
    }

マッチセッションに参加する

このセクションでは、AGS SDK を使用してピアツーピアでゲームセッションに参加する方法を説明します。

  1. MatchSessionDSWrapper_Starter クラスを開き、以下の関数を作成します。この関数は、親クラスの関数を呼び出してセッション参加リクエストを送信します。これは Introduction to Session モジュールで学習した内容です。リクエストが完了すると、ピアツーピアホストが接続可能かどうかを確認します。

    public override void JoinGameSession(
    string sessionId,
    ResultCallback<SessionV2GameSession> onComplete)
    {
    base.JoinGameSession(sessionId, (result) =>
    {
    if (!result.IsError)
    {
    InGameMode requestedGameMode = GetGameSessionGameMode(result.Value);
    if (requestedGameMode == InGameMode.None)
    {
    BytewarsLogger.LogWarning($"Failed to travel to the P2P host. Session's game mode is not supported by the game.");
    onComplete?.Invoke(Result<SessionV2GameSession>.CreateError(ErrorCode.NotAcceptable, InvalidSessionTypeMessage));
    return;
    }
    TravelToP2PHost(result.Value, requestedGameMode);
    }

    onComplete?.Invoke(result);
    });
    }

マッチセッションを閲覧する

このセクションでは、AGS SDK を使用してゲームセッションをクエリする方法を説明します。

  1. MatchSessionP2PWrapper_Starter クラスを開き、特定の属性に基づいてゲームセッションをクエリする以下の関数を作成します。この場合、MatchSessionP2PAttribute を使用してピアツーピアタイプを持つゲームセッションのみをフィルタリングします。読み込む特定のページがある場合は、ページネーション URL を解析してクエリ属性に追加しようとします。最後に、ゲームセッションのクエリを開始し、セッションオーナーの詳細とともに結果を返します。

    public override void BrowseGameSessions(
    string pageUrl,
    ResultCallback<BrowseSessionResult> onComplete)
    {
    // If provided, try parse the pagination URL parameters and add them to the query attributes.
    Dictionary<string, object> queryAttributes = new(MatchSessionP2PAttribute);
    if (!string.IsNullOrEmpty(pageUrl))
    {
    Dictionary<string, object> queryParams = ParseQuerySessionParams(pageUrl);
    if (queryParams == null)
    {
    BytewarsLogger.LogWarning($"Failed to find game sessions. Pagination URL is invalid.");
    onComplete?.Invoke(Result<BrowseSessionResult>.CreateError(ErrorCode.InvalidArgument, InvalidSessionPaginationMessage));
    return;
    }
    queryParams.ToList().ForEach(x => queryAttributes[x.Key] = x.Value);
    }

    // Query game sessions and filter them based on the custom attributes.
    Session.QueryGameSession(queryAttributes, sessionResult =>
    {
    if (sessionResult.IsError)
    {
    BytewarsLogger.LogWarning(
    $"Failed to query game sessions. " +
    $"Error {sessionResult.Error.Code}: {sessionResult.Error.Message}");
    onComplete?.Invoke(Result<BrowseSessionResult>.CreateError(sessionResult.Error));
    return;
    }

    BytewarsLogger.Log("Success to query game sessions.");

    // Return immediately if result is empty.
    if (sessionResult.Value.data.Length <= 0)
    {
    onComplete?.Invoke(Result<BrowseSessionResult>.CreateOk(
    new BrowseSessionResult(
    queryAttributes,
    new PaginatedResponse<BrowseSessionModel>()
    {
    data = Array.Empty<BrowseSessionModel>(),
    paging = sessionResult.Value.paging
    })));
    return;
    }

    // Query the session owner user information.
    string[] sessionOwners = sessionResult.Value.data.Select(x => x.createdBy).ToArray();
    User.GetUserOtherPlatformBasicPublicInfo("ACCELBYTE", sessionOwners, (userResult) =>
    {
    if (userResult.IsError)
    {
    BytewarsLogger.LogWarning(
    $"Failed to query game sessions. " +
    $"Error {userResult.Error.Code}: {userResult.Error.Message}");
    onComplete?.Invoke(Result<BrowseSessionResult>.CreateError(userResult.Error));
    return;
    }

    // Construct session results.
    List<BrowseSessionModel> result = new();
    foreach (SessionV2GameSession session in sessionResult.Value.data)
    {
    AccountUserPlatformData ownerData = userResult.Value.Data.FirstOrDefault(x => x.UserId == session.createdBy);
    if (session != null && ownerData != null)
    {
    result.Add(new(session, ownerData));
    }
    }

    // Return results.
    onComplete?.Invoke(Result<BrowseSessionResult>.CreateOk(
    new BrowseSessionResult(
    queryAttributes,
    new PaginatedResponse<BrowseSessionModel>()
    {
    data = result.ToArray(),
    paging = sessionResult.Value.paging
    })));
    });
    });
    }

マッチセッションイベントをリッスンする

このセクションでは、ゲームセッションイベントをリッスンする方法を説明します。

  1. MatchSessionP2PWrapper_Starter クラスを開き、事前定義された Awake() 関数を以下のコードに置き換えます。このコードは、閲覧メニューが表示されたときにリッスンするデリゲートをバインドします。それが発生すると、閲覧セッション関数をトリガーし、メニューに表示される結果を返します。

    protected override void Awake()
    {
    base.Awake();

    BrowseMatchMenu.OnBrowseP2PMatch += BrowseGameSessions;
    }

リソース