GitHub Documentation

[Defold] room.state.on_change does not get triggered on state change



  • Hi all,

    I am seeing what seems to me to be inconsistent results when registering callbacks for room state changes.

    Here I register a callback for base state changes, like in @endel's example here: https://github.com/endel/colyseus-tic-tac-toe/blob/master/defold/scripts/game_controller.script.

    room.state['on_change'] = function (changes)
    	for i, change in ipairs(changes) do
    		print("base state change")
    		print(change.field)
    		print(change.value)
    		print(change.previousValue)
    	end
    end
    

    Here I register a callback for something more specific in the state:

    room.state.players.on_add = function(player, sessionId)
    	player.character.position.on_change = function(changes)
                    local position = {}
    		for i, change in ipairs(changes) do
    			if change.field == "x" then
    				position["x"] = change.value
    			end
    			if change.field == "y" then
    				position["y"] = change.value
    			end
    		end
                    print("new position", inspect(changes))
    	end
    end
    

    I know that the state changes are successfully making it from one client, to the server, and back to the other client, because I see the player on one client move on the other (and also from the logs).

    When one client moves, therefore updating the state, I see only messages from the more specific callbacks:

    DEBUG:SCRIPT: new position	{
      x = 869.49731445313,
      y = 370.85791015625
    }
    

    However I expect to see not only that, but also a message like:

    DEBUG:SCRIPT: base state change
    

    Do I misunderstand how these callbacks work? I would assume that if I assign a callback to the root state, it would fire any time anything changes within that state (recursively).

    Also, in the docs here (https://docs.colyseus.io/state/overview/) it says that binary patches of the state are sent to the client every 50ms. Is it the case that if there are no changes, it sends nothing, and therefore the callback doesn't fire?

    One specific reason I want a generic callback is I want to estimate how often I receive updates from the client so I can lerp the other players' movements accurately, though I think having a base callback might be useful in other ways.

    In short, I'm not quite sure how on_change works, and I can't really figure it out from the docs ("this event is triggered when the server updates its state", it doesn't really elaborate on which callbacks get called for which state).

    Thanks everyone!


  • administrator

    Hi @banool!

    I think you're looking for room:on("statechange", ...): https://docs.colyseus.io/client/room/#onstatechange

    Thanks for the observation about the documentation, it is not clear indeed. The "on change" callbacks are not recursive since colyseus@0.14 - the new schema implementation introduced a concept of refId and instance references. Changes are triggered directly and only on the instance in which a change has happened by their refId.

    I hope this helps! Feel free to post any issues and/or suggestions here or on Discord! Cheers!



  • Hi!

    Thanks for the super quick response. I see different options in different places:

    • room.state.on_change
    • room.state["on_change"]
    • room:on("statechange")

    I'll go with the latter from now on.

    Good to know that the on change callbacks are not recursive. I can put up a PR to make this a bit clearer on the docs.

    Thanks!


  • administrator

    No worries! In fact room.state.on_change and room.state["on_change"] are just different in syntax, they are actually equal!

    I can put up a PR to make this a bit clearer on the docs.

    That'd be much appreciated! 🙏

    Cheers!


 

© 2021 Lucid Sight, Inc