Can't get new Netcode for Entities Approval flow to work

Trying to convert old code into using the new approval flow but itis not working, not sure why.
I followed the code in the docs:
https://docs.unity3d.com/Packages/com.unity.netcode@1.3/manual/network-connection.html
(scroll down to connection approval section)

I set RequireConnectionApproval = true on both the server and client right before calling Listen and Connect.

My client connection request system:

[BurstCompile]
  [WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)]
  public partial struct ClientConnectionRequestSystem : ISystem
  {
    //private EntityQuery m_pendingNetworkIdQuery;

    //================================================================
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
      //var builder = new EntityQueryBuilder(Allocator.Temp).WithAll<NetworkId>().WithNone<NetworkStreamInGame>();
      //m_pendingNetworkIdQuery = state.GetEntityQuery(builder);
      //state.RequireForUpdate(m_pendingNetworkIdQuery);
      state.RequireForUpdate<ClientLoginCredentialsComponent>();
      state.RequireForUpdate<RpcCollection>();
    }

    //================================================================
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
      var clientLoginCredentials = SystemAPI.GetSingleton<ClientLoginCredentialsComponent>();
      var ecb = new EntityCommandBuffer(Allocator.Temp);
      //var pendingNetworkIds = m_pendingNetworkIdQuery.ToEntityArray(Allocator.Temp);
      //foreach (var pendingNetworkId in pendingNetworkIds) {
      foreach (var (connection, entity) in SystemAPI.Query<RefRW<NetworkStreamConnection>>().WithNone<NetworkId>().WithNone<ClientApprovalStartedComponent>().WithEntityAccess()) { 
        //ecb.AddComponent<NetworkStreamInGame>(pendingNetworkId);
        Logger.log_debug($"Creating Entity for RequestServerConnectionRPC");
        var requestServerConnection = ecb.CreateEntity();
        ecb.AddComponent(requestServerConnection, new RequestServerConnectionRPC {
          ServerPassword = clientLoginCredentials.Password,
          PlayerSessionToken = clientLoginCredentials.SessionToken,
          PlayerID = clientLoginCredentials.PlayerID,
          PlayerUsername = clientLoginCredentials.Username
        });
        //ecb.AddComponent(requestServerConnection, new SendRpcCommandRequest { TargetConnection = pendingNetworkId });
        ecb.AddComponent<SendRpcCommandRequest>(requestServerConnection);
        ecb.AddComponent<ClientApprovalStartedComponent>(entity);
        Logger.log_debug($"Sending RequestServerConnectionRPC");
      }
      ecb.Playback(state.EntityManager);
    }
  }

RequestServerConnectionRPC is an IApprovalRpcCommand

Server System:

//================================================================
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
      //var builder = new EntityQueryBuilder(Allocator.Temp).WithAll<RequestServerConnectionRPC, ReceiveRpcCommandRequest>();
      //state.RequireForUpdate(state.GetEntityQuery(builder));
      m_playerQuery = state.GetEntityQuery(ComponentType.ReadOnly<PlayerComponent>());
      m_AdminQuery = state.GetEntityQuery(ComponentType.ReadOnly<AdminComponent>());
      m_GameMasterQuery = state.GetEntityQuery(ComponentType.ReadOnly<GameMasterComponent>());
    }

    //================================================================
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
      var ecb = new EntityCommandBuffer(Allocator.Temp);

      var serverLoginCredentials = SystemAPI.GetSingleton<ServerLoginCredentialsComponent>();
      var serverInfo = SystemAPI.GetSingletonRW<MultiplayerServerRecordComponent>().ValueRW;
      
      //foreach (var (requestServerConnection, requestSource, requestEntity) in SystemAPI.Query<RequestServerConnectionRPC, ReceiveRpcCommandRequest>().WithEntityAccess()) {
      Logger.log_info($"Connection request OnUpdate");      
      foreach (var (receiveRpc, requestServerConnection, requestEntity) in SystemAPI.Query<RefRO<ReceiveRpcCommandRequest>, RefRW<RequestServerConnectionRPC>>().WithEntityAccess()) {
        Logger.log_info($"Connection request...");        
        var connectionEntity = receiveRpc.ValueRO.SourceConnection;
        Logger.log_info($"Connection request from {requestServerConnection.ValueRO.PlayerUsername}");
        int currentPlayerCount = m_playerQuery.CalculateEntityCount();
        PlayerType playerType = handle_player_login(requestServerConnection.ValueRO, serverLoginCredentials, currentPlayerCount);
        if (playerType != PlayerType.Invalid) {
          ecb.AddComponent<ConnectionApproved>(connectionEntity);
          PlayerInfoComponent playerInfo = new PlayerInfoComponent {
            PlayerType = playerType,
            PlayerId = requestServerConnection.ValueRO.PlayerID,
            Username = requestServerConnection.ValueRO.PlayerUsername
          };
          ecb.AddComponent(connectionEntity, playerInfo);
          ecb.DestroyEntity(requestEntity);
          send_connection_notifications(ecb, playerType, requestServerConnection.ValueRO, connectionEntity, serverInfo);          
        } else {
          //Connection failed validation, drop them.
          Logger.log_info($"Login failed validation");
          ecb.AddComponent<NetworkStreamRequestDisconnect>(connectionEntity);
        }

      }
      ecb.Playback(state.EntityManager);
    }

Client sends the request and I can see both the “Creating Entity for RequestServerConnectionRPC” and “Sending RequestServerConnectionRPC” logs appear.

The server never generates the “Connection request…” log at all indicating the foreach was never entered, yet this is using the same query code specified in the docs.

I get a log message for Netcode saying the approval timed out after 5000ms. My connection tests are entirely localhost/127.0.0.1 so 5 seconds should be more than enough time to resolve. If I turn connectionApproval back off and restore my original ‘manual’ approval code, everything works fine.

Hi, in your server system query, you are querying directly for the components, but you need to query for RefRO/RefRW version of those components. Try and update this and let me know if it works.

EDIT: Ah, nevermind, I looked at the commented query. Could you check that the connection and that the RPC actually exists via the Entities Hierarchy on the server? Also, does the “Connection request OnUpdate” get logged before the query?

You likely already have, but for posterity, also check for any Warnings in the console - we recently improved RPC error logging when failing to send (or receive) RPCs, and see RpcCommandRequest.SendRpcData.ValidateAndQueueRpc for an example of this kind of internal validation.


A network connection approval entity shows up in the server hierarchy briefly before disappearing. Is this the one you mean?

It is rather difficult to easily find entities of interest in the hierarchy. Is there a setting somewhere that I can change to tag entities of interest with a color or better name so they stand out more easily? Also is there a setting in the approval connection to increase the timeout to longer than 5000ms so I can view the item before it’s gone?

“Connection request OnUpdate” does appear in the logs.
@NikiWalker I have not seen any warnings in the console for either the server or the client thus far.

There is a search bar at the top of the entities hierarchy, you can use that to filter for the specific RPC your are looking for.

When you say the NetworkConnection entity is there briefly, do you mean like a single frame-ish time, or closer to the 5 seconds that is the timeout?

With the filter, are you able to see any RPCs show up at all? You can specifically look for this with the any=ReceiveRpcCommandRequest filter.

The 5 seconds. If it was one frame I’d have never had time to swap to the entities tab and screenshot it while it was present or probably even notice it to begin with.

using the any=ReceiveRpcCommandRequest filter shows no results.

below is my approval payload package.

  public struct RequestServerConnectionRPC : IApprovalRpcCommand //IRpcCommand
  {
    public FixedString32Bytes ServerPassword;
    public FixedString4096Bytes PlayerSessionToken;
    public FixedString32Bytes PlayerID;
    public FixedString64Bytes PlayerUsername;
  }

Given that no RPC shows up at all, it seems there is either an issue with the connection flow, or a bug in the approval system blocking the RPC from being sent. Given that you mentioned the connection flow works without the authentication flow, I think it’s likely a bug. Can you report a bug via the in-editor bug reporter and post the case number here? Then we can get a full repro from the project and investigate further.

Agreed, this sounds odd.

Yeah, it’s ClientServerTickRate.HandshakeApprovalTimeoutMS.

Agreed. I’d recommend opening the Window > ECS > Components tab, selecting your RPC, and seeing which worlds it exists on as you single step through frames during your connection attempt.