colyseus / colyseus-unity-sdk

⚔ Colyseus Multiplayer SDK for Unity
https://docs.colyseus.io/getting-started/unity-sdk/
MIT License
378 stars 104 forks source link

JoinById or JoinOrCreate... can not receive an exception when throw an exception from server #183

Open hung365dev opened 2 years ago

hung365dev commented 2 years ago

I think there is problem with onAuth(client: Client, options: any, request?: IncomingMessage) on the server side. When you return false or throw an exception in the onAuth method, on the Unity client side, at the first time, It will throw an exception, but when you join or create room one more time, It will not throw any exceptions. It only throw a Websocket closed! Code:4002, not an exception.

Server side:

onCreate() {
   this.maxClients = 2;
}

onAuth(client: Client, options: any, request?: IncomingMessage) {
    if (this.roomPasswordOption === options["roomPassword"]) {
      return true;
    } else {
      throw new ServerError(401, "auth error !");
  }

Unity client side:

try
        {
            while (_room == null || !_room.colyseusConnection.IsOpen)
            {
                _room = await client.JoinById<NetworkRoomState> (roomId, options);

                if (_room == null || !_room.colyseusConnection.IsOpen)
                {
                    LSLog.LogImportant ($"Failed to Connect to {roomId}.. Retrying in 5 Seconds...");
                    await Task.Delay (5000);
                }
            }
            LSLog.LogImportant ($"Connected to {roomId}..");
        }
        catch (Exception ex)
        {
            LSLog.LogError (ex.Message);              
            LSLog.LogError ("Failed to join room");
        }

Reproduce: 1: Client A create a room with a password. 2: Client B join to that room with a wrong password. 3: Client B have an onAuth exception => This is OK at the first time 4: Client B join to that room with a wrong password again. 5: Client B did not receive any exceptions again.

This is not only JoinById method, other methods like JoinOrCreate, Create.... also have this bug.

deveshbeniwal commented 1 year ago

I am able to get the ServerError thrown from my colyseus backend. I am using UniTask as i want to build game for Webgl and Try-Catch do not work for webgl, now I can use Try-Catch on webgl too. Below is my sample code for both server and client side, to throw and to receive error.

CLIENT END:

public async UniTaskVoid CreateRoom(Action success, Action<string> fail)
{
try
{
room = await client.Create<dynamic>(KEY_ROOMNAME, options).AsUniTask();
reconnection_data = room.ReconnectionToken;

success?.Invoke();
}
catch (Exception exception)
{
Debug.Log(exception.Message);
fail?.Invoke(exception.Message);
}
}

SERVER END:

async onAuth(client: Client, options: any) {
await super.onAuth(client, options);
throw new ServerError(401, "You don't have permission to join this room");
}
endel commented 1 year ago

Hi @deveshbeniwal, what would be the advantage of using .AsUniTask() / UniTaskVoid here? Honest question, I never used UniTask and I'm not sure of its advantages over the built-in types.

Does it work without using UniTask? Cheers

deveshbeniwal commented 1 year ago

@endel Unitask is a customized package to use Tasks, Async-Await in a better way. I used UniTask here because i wanted to use async code with webgl builds, Webgl build do not support async programming and Try-Catch block too( usually it will throw an error at if we use try catch on webgl build from unity ). Unitask helped me to use async programming and to use try catch in webgl build too as it internally work on unity main thread.

.AsUniTask() here is i am running this task as unitask which will work on main thread. UniTaskVoid is just like a async method with Task return type. I am focused towards webgl build so mostly use UniTask so that i can archive async programming on unity's main thread.

Apart from that UniTask is not the focus of my point. I just copy/pasted the code, LOL. My focus is that i am receiving errors thrown from server in try-catch block sucessfully.