Search Unity

Question How to add a "Bot" player to a lobby?

Discussion in 'Lobby' started by MidniteOil, May 22, 2023.

  1. MidniteOil

    MidniteOil

    Joined:
    Sep 25, 2019
    Posts:
    345
    Greetings,

    TL/DR getting "request failed validation" when trying to add a "bot" player to a lobby. Basically, the same player that created the lobby is trying to add another player that will be AI controlled.

    I've got a pretty complete real-time, cross-platform, multiplayer card game working with NetCode for GameObjects, Lobby and Relay.

    I want to add the ability for the player who created the lobby to add "bot" players.

    I created the lobby via the usual means:

    Code (CSharp):
    1.     public static async Task CreateLobbyWithAllocation(LobbyData lobbyData)
    2.     {
    3.         try
    4.         {
    5.             // Create a relay allocation and generate a join code to share with the lobby
    6.             Debug.Log($"RelayService.Instance.CreateAllocationAsync(maxPlayers: {lobbyData.MaxPlayers});");
    7.             var a = await RelayService.Instance.CreateAllocationAsync(lobbyData.MaxPlayers);
    8.             Debug.Log($"RelayService.Instance.GetJoinCodeAsync(allocationId: {a.AllocationId});");
    9.             var joinCode = await RelayService.Instance.GetJoinCodeAsync(a.AllocationId);
    10.  
    11.             // Create a lobby, adding the relay join code to the lobby data
    12.             var options = new CreateLobbyOptions
    13.             {
    14.                 Player = CurrentPlayer,
    15.                 Data = new Dictionary<string, DataObject>
    16.                 {
    17.                     { Constants.JoinKey, new DataObject(DataObject.VisibilityOptions.Member, joinCode) },
    18.                     {
    19.                         Constants.GameStateKey,
    20.                         new DataObject(DataObject.VisibilityOptions.Public, GameState.WaitingForPlayers.ToString())
    21.                     },
    22.                     {
    23.                         Constants.ProtocolVersionKey,
    24.                         new DataObject(DataObject.VisibilityOptions.Public, Application.version)
    25.                     }
    26.                 },
    27.                 IsPrivate = lobbyData.Private
    28.             };
    29.  
    30.             CurrentLobby = await Lobbies.Instance.CreateLobbyAsync(lobbyData.Name, lobbyData.MaxPlayers, options);
    31.  
    32.             Transport.SetHostRelayData(a.RelayServer.IpV4, (ushort)a.RelayServer.Port, a.AllocationIdBytes, a.Key,  a.ConnectionData);
    33.  
    34.             Heartbeat();
    35.             PeriodicallyRefreshLobby();
    36.         }
    37.         catch (Exception exception)
    38.         {
    39.             Debug.LogError($"Error creating lobby {lobbyData.Name}.\n{exception}");
    40.         }
    41.     }
    To add a "bot" I'm simply creating a new player object, giving it a name and a portrait index and appending an integer to its client id:

    Code (CSharp):
    1.     static Player CreateBotPlayer()
    2.     {
    3.         var botIndex = CurrentLobby.GetRandomBotIndex();
    4.         var playerName = PlayerExtensions.BotNames[botIndex];
    5.         var clientId = $"{NetworkManager.Singleton.LocalClientId.ToString()}-{botIndex:D2}";
    6.         return new Player(
    7.             $"BotPlayer{botIndex}",
    8.             null,
    9.             new Dictionary<string, PlayerDataObject>
    10.             {
    11.                 {Constants.ClientIdKey, new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, clientId)},
    12.                 {Constants.PlayerNameKey, new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, playerName)},
    13.                 {Constants.PlayerPortraitKey, new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, botIndex.ToString())}
    14.             });
    15.     }
    And adding it to the lobby as follows:

    Code (CSharp):
    1.     public static async Task AddBotPlayer()
    2.     {
    3.         try
    4.         {
    5.             await Lobbies.Instance.JoinLobbyByIdAsync(CurrentLobby.Id, new JoinLobbyByIdOptions
    6.             {
    7.                 Player = CreateBotPlayer()
    8.             });
    9.         }
    10.         catch (Exception e)
    11.         {
    12.             Debug.LogError($"Failed to add bot player {CurrentLobby?.Name}: {e}");
    13.         }
    14.     }
    This is failing with the following (not very informative) error:

    Failed to add bot player Duncan's game: Unity.Services.Lobbies.LobbyServiceException: request failed validation ---> Unity.Services.Lobbies.Http.HttpException`1[Unity.Services.Lobbies.Models.ErrorStatus]: HTTP/1.1 400 Bad Request
    at Unity.Services.Lobbies.Http.ResponseHandler.HandleAsyncResponse (Unity.Services.Lobbies.Http.HttpClientResponse response, System.Collections.Generic.Dictionary`2[TKey,TValue] statusCodeToTypeMap) [0x0007b] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Library\PackageCache\com.unity.services.lobby@1.0.3\Runtime\Http\ResponseHandler.cs:95
    at Unity.Services.Lobbies.Http.ResponseHandler.HandleAsyncResponse[T] (Unity.Services.Lobbies.Http.HttpClientResponse response, System.Collections.Generic.Dictionary`2[TKey,TValue] statusCodeToTypeMap) [0x00001] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Library\PackageCache\com.unity.services.lobby@1.0.3\Runtime\Http\ResponseHandler.cs:186
    at Unity.Services.Lobbies.Apis.Lobby.LobbyApiClient.JoinLobbyByIdAsync (Unity.Services.Lobbies.Lobby.JoinLobbyByIdRequest request, Unity.Services.Lobbies.Configuration operationConfiguration) [0x001bb] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Library\PackageCache\com.unity.services.lobby@1.0.3\Runtime\Apis\LobbyApi.cs:396
    at Unity.Services.Lobbies.Internal.WrappedLobbyService.TryCatchRequest[TRequest,TReturn] (System.Func`3[T1,T2,TResult] func, TRequest request) [0x00046] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Library\PackageCache\com.unity.services.lobby@1.0.3\Runtime\SDK\WrappedLobbyService.cs:355
    --- End of inner exception stack trace ---
    at Unity.Services.Lobbies.Internal.WrappedLobbyService.ResolveErrorWrapping (Unity.Services.Lobbies.LobbyExceptionReason reason, System.Exception exception) [0x000a1] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Library\PackageCache\com.unity.services.lobby@1.0.3\Runtime\SDK\WrappedLobbyService.cs:411
    at Unity.Services.Lobbies.Internal.WrappedLobbyService.TryCatchRequest[TRequest,TReturn] (System.Func`3[T1,T2,TResult] func, TRequest request) [0x000c3] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Library\PackageCache\com.unity.services.lobby@1.0.3\Runtime\SDK\WrappedLobbyService.cs:359
    at Unity.Services.Lobbies.Internal.WrappedLobbyService.JoinLobbyByIdAsync (System.String lobbyId, Unity.Services.Lobbies.JoinLobbyByIdOptions options) [0x000a3] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Library\PackageCache\com.unity.services.lobby@1.0.3\Runtime\SDK\WrappedLobbyService.cs:165
    at Unity.Services.Lobbies.Internal.WrappedLobbyService.JoinLobbyByIdAsync (System.String lobbyId, Unity.Services.Lobbies.JoinLobbyByIdOptions options) [0x00234] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Library\PackageCache\com.unity.services.lobby@1.0.3\Runtime\SDK\WrappedLobbyService.cs:179
    at MatchmakingService.AddBotPlayer () [0x00043] in F:\dev\Unity Projects\Highland Panic Root\ios_release\Assets\_highlandPanic\Lobby\Scripts\MatchmakingService.cs:167
    UnityEngine.Debug:LogError (object)
     
  2. Mj-Kkaya

    Mj-Kkaya

    Joined:
    Oct 10, 2017
    Posts:
    179
    Actually, you don't add bot players to the lobby, you just try to add yourself to the lobby for the second time.
    And it gives an error because you are already in the lobby.

    The "CreateBotPlayer()" method only creates a Player data, not a new player.
    I've never tried to create a bot player before but you should try NetworkPrefab to create bot player.
     
  3. MidniteOil

    MidniteOil

    Joined:
    Sep 25, 2019
    Posts:
    345
    How would you use NetworkPrefab with Lobby services? That seems more like a Netcode for GameObjects thing.
     
  4. Mj-Kkaya

    Mj-Kkaya

    Joined:
    Oct 10, 2017
    Posts:
    179
    I thought you added Netcode for GameObject to your project, didn't you?
    If you want to add AI on Lobby, you can prefer Lobby data.
     
  5. MidniteOil

    MidniteOil

    Joined:
    Sep 25, 2019
    Posts:
    345
    First of all, thank you for responding. Second, sorry for the confusion.

    Yes, I am using Netcode for GameObjects but that is for the "game play" portion of the game. The problem I am trying to solve is how to add non-human players to a lobby and have that be visible to players who have not yet joined any game. i.e. the lobby list should reflect the number of players (including bots) in any given game so the client can know whether or not to enable the Join button on the game (you can't join a full lobby).

    Since the players have not yet joined the game Netcode for GameObjects is not an option.

    It sounds like my only option is to use lobby data (i.e. add a DataObject) for each "bot" added to the game which was my initial approach but that seems kludgy to me which I why I reached out to the community to see how others go about doing this.

    I am certainly not the first person to add bots to their game :)

    I had thought there might be a way to add additional players to the Lobby but it's looking more and more like that's not possible.
     
  6. Mj-Kkaya

    Mj-Kkaya

    Joined:
    Oct 10, 2017
    Posts:
    179
    Yes, that was clear explanation :)
    When I was working with PUN I also used Bot players and I added Bot players to the lobby properties. I wasn't able to change lobby data's max player count or player count variables at runtime.
     
    MidniteOil likes this.
  7. MidniteOil

    MidniteOil

    Joined:
    Sep 25, 2019
    Posts:
    345
    Thanks. Leaving this thread open in case anyone else wants to chime in.
     
    Mj-Kkaya likes this.