[Defold] ERROR:WEBSOCKET: Failed to setup callback when player joins room

Hi all,

I have code that functionally looks like this:

splash.gui_script

-- When the user presses Create Game
function create_game()
    client:join_or_create("lobby", {}, function(err, _room)
        if err then
            print("Failed to create the lobby:", err)
            return
        end
        room_module:set_room(_room)
    end)
end

create_game()
r = room_module:get_room()
if r and r.state.players and r.state.players[r.sessionId] then
    msg.post("main:/loader", "load_level")
end

room.lua

local M = {}

function M.set_room(the_state, r)
    the_state.room = r
end

function M.get_room(the_state)
    return the_state.room
end

function M.add_callbacks(the_state)
    add_callbacks(the_state.room)
    print("Added room callbacks")
end

function M.new(r)
    local state = {
	room = r
    }
    return state
end

function add_callbacks(room)
    room.state.players.on_add = function(player, sessionId)
	print("new player", sessionId, player)
    end
end

loader.script

local function load_level(self)
    msg.post("#level", "load")
end

function on_message(self, message_id, message, sender)
    if message_id == hash("load_level") then
        unload_splash(self)
	load_level(self)
    end
end

level.script

local room_module = require "room"

function init(self)
    room_module:add_callbacks()
end

Functionally this is how it works:

  1. Load into main menu (splash).
  2. Press create game, which causes the code in splash.gui_script to run.
  3. The room object is created and stored globally in room.lua.
  4. splash.gui_script sends a message to loader.script to tell it to unload the splash and load the level.
  5. The level calls add_callbacks to add the callbacks to room. This ostensibly works correctly, because I see Added room callbacks after this point.

What I expect to happen is, after this point, if someone joins the game, I should see a message like this:

new player <session_id> <player>

However instead I see this:

ERROR:WEBSOCKET: Failed to setup callback

Importantly, I only see this error when the second player joins the room, not when I add the callbacks.

My schema pretty much looks like this:

export class MyLobbyRoomState extends Schema {
  @type({ map: Player })
  players = new MapSchema<Player>();
}

Player itself just has 3 fields in it: x: number, y: number, and name: string.

As far as I can tell, everything looks fine in the backend. I have logging that shows the two players connect:

onCreate: Created room: KRafbAeo9
onJoin: Joined: KRafbAeo9
onJoin: Options: []
Connected clients: [ 'kQITKomRu' ]
onJoin: Joined: KRafbAeo9
onJoin: Options: []
Connected clients: [ 'kQITKomRu', 'CHaf_yUQm' ]

If I add the callbacks immediately in set_room in room.lua, the callback works at first (it gets called for my own player joining). Later however, when the second player joins, I see the same websocket error, instead of the callback being called for the second player, which is very strange.

Furthermore, even if I could get that approach to work, it is too early to register the callbacks because at that point, the level has not loaded yet, since I join the room first and then load the level. I also feel like this is still a race, since the state change may happen before I assign the callback. The current approach, where I add the callbacks later, has the same problem. It seems to imply that I have to process the initial state first before relying on the callbacks on state change. Instead, I would love most of all to have all the callbacks get called retroactively based on the initial state. For example, if there are 2 players when someone joins, the callbacks for state.players.on_add gets called twice, but only after I have assigned the callback.

So two questions:

  1. How do I get more details about this error, ERROR:WEBSOCKET: Failed to setup callback. Currently it is very opaque, it doesn't tell me what specifically failed in setting up the callback.
  2. What is the best way to get it that I only have to write callbacks for state changes, instead of that and an additional function that processes the initial state. When I look at examples like this or this by @endel they seem to just set the callbacks without doing any initial state processing, so I feel this must be possible.

Any help would be very much appreciated!

Thanks for reporting @banool, I've replied to your post on the Defold forums as it might involve their WebSocket extension: https://forum.defold.com/t/colyseus-error-failed-to-setup-callback-when-player-joins-room/68165