3

I'm creating a nodejs server for Unity3D, using socketio for the networking. I have a function that serves as match room and I want to leave that function when the player leaves the game. Each time the player creates a new room it should enter the function and start over. Is it possible to break execution of parent function from a child callback?

exports.initGame = function (userdata) {
    //do prematch stuff with userdata and execute game logic on the callbaks

    socket.on("something", function (someNetdata)({
        // how do i stop parent function from here?
    });

    // more socket.on callbacks
}

EDIT: Forgot to mention that the function is being exported. Don't know if that change anything.

EDIT2: Given the suggestions discussed in jfriend00 answer, I'll give a more extended explanation of the problem.

The current flow is as it follows:

user connects and I define some functions on the Io "connected" callback. Relevant one is startMatchMaker(Io, socket, data). The matchMaker creates a room for the player (or joins one if there is one available) and proceed to executing the gameInit(io, socket, room, data) mentioned before.

The gameInit(...) function stores relevant data on global arrays with the room as key, for example, Players[room] = {/* player object */}. The match is 1 vs 1, so when one player abandons the game, I remove the entries from the arrays, referring that room: delete Players[room]. When the player moves, I update the player position on their object inside the global array. this is done on a callback, added inside the gameInit(...)

socket.on("move", function(data){
    //do movement logic and update player position, if it is valid. Omitting the rest of the code.
    Players[room].position = data.position;
});

Now lets imagine two players, player1 and player2 playing in room1. Player2 abandon the game by exiting the server. Player1 is still connected, but must leave that current game. All the variables are deleted (as mentioned before) and player1 joins a new game in room2. When player1 tries to move, 2 callbacks will be called: the one that was added in the first initGame with room = "room1" and another added upon execution of the second match: room = "room2". A exception is thrown because there is no entry in Players with key = room1.

Given this the solution is to remove the listeners from the previous match.

Community
  • 1
  • 1
Yuri Almeida
  • 139
  • 1
  • 9
  • The way stack overflow is designed to work, you should not keep editing the question with progressive discovery based on answers provided. This is meant to be a question and answer site. You ask a question (which are free to edit to clarify at any time) and we provide an answer. You do not continue to evolve the question as you get info from answers. This is not a threaded discussion site where we discuss your evolving problem. You ask ONE clear question, we provide an answer to that one question. What your question is asking should not ever change. You can clarify the original question. – jfriend00 Feb 01 '17 at 17:53
  • If, after getting your original question answered, you have additional questions that come out of what you learned, then you ask another separate question. – jfriend00 Feb 01 '17 at 17:54
  • Also, all the text trying to describe how your code works is far too complex for readers to follow. Just show the actual code (a few lines of code is worth a hundred lines of text) and then perhaps describe your goals for this code (what you're trying to accomplish) in text. – jfriend00 Feb 01 '17 at 17:55

2 Answers2

3

No. You can't stop execution of a parent function from within a child function. You could create a return value from the child function that would instruct the parent function what to do next and the parent function could then manage itself based on the return value.

But, in your example, initGame() is long since done executing when socket.on('something, ...) is called so your whole ask is just kind of wrong. In fact your event handler CANNOT get called until initGame() is already done. JS is single threaded so initGame() has to finish executing before any event handler can be called.

The sequence of events here is as follows:

  1. initGame() runs.
  2. While it is running, it sets up event handlers to listen for various socket messages. These are event handlers to respond to events that happen some time in the future.
  3. initGame() then finishes executing.
  4. Then, some time in the future, an event occurs and one of your event handlers runs. There is no initGame() running to even try to break execution of.

If you want more concrete help, you will need to show what you're actually trying to accomplish from within your socket.on('something', ...) event handler. The whole notion of "break execution of parent function" from an inner event handler just doesn't even make sense in Javascript. That situation can never happen in Javascript. The parent function is already done executing before the event handler could ever get called. You will have to show the actual problem you're trying to solve for us to help you in more detail.

One thing that seems slightly troubling here is that you reference socket, but that is not passed into initGame(), yet you are exporting initGame() and calling it from some other context so it is unclear how the socket variable could possibly be the right variable.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    @YuriAlmeida - I've explained what your current situation is given the code you've shown (and even added a bit more to my answer). You will have to show what you're actually trying to accomplish from an event handler for us to help further. Currently you've not described the real problem or shown the code related to the actual problem in any way. FYI, I think I have answered the question you literally asked - No, you can't do what you're asking because that function has already finished executing. – jfriend00 Feb 01 '17 at 16:45
  • Ohhh ok, got it! Let me elaborate more on what's happening: Player joins and the game stores a local string `room` inside `initGame()`. Several callbacks are added which uses the local variable `room` to access indexes on global arrays. player leaves the game and joins another. When he joins the second game, callbacks from first and second games are both called ( and throws erros because there are no more indexes with that `room` name on global arryes, since I deleted them when the player left the game). Since `initGame()` is no longer executing, then I have to remove the callbacks?if so, how? – Yuri Almeida Feb 01 '17 at 16:46
  • 1
    @YuriAlmeida - Must of what you describe in your comment sounds complicated and does not seem to show in the code you added to your question (don't see the callbacks you talk about). I'd suggest that if you have state you want to store for a given user, you just add your own property to the `socket` object for that user and store it there. That's just cleaner than what you are doing as the state is directly associated with the `socket` that it belongs to. Your current scheme would actually work for the code you show because it creates a lasting function closure, but is not the cleanest. – jfriend00 Feb 01 '17 at 16:51
  • ok, I think that might solve the problem! Thank you sir! I'm not used to javascript, almost all of my coding experience has been with C# and the notion that I can add properties to any object is still a little strange to me ^^ going to edit the question to better illustrate the problem and try you sugestion later, I'll let you know if it worked! ;) – Yuri Almeida Feb 01 '17 at 16:53
  • 1
    @YuriAlmeida - Please see the last paragraph I added to my answer. I'm concerned about how the `socket` variable could possibly have the right value in it. – jfriend00 Feb 01 '17 at 16:55
  • sorry, my bad. I pass the socket as a parameter. it will be clearer when I finish to edit the question. Once again, thank you for your time and sorry for not making it as clear as I could have :) – Yuri Almeida Feb 01 '17 at 16:57
1

Your notion of "parent" function is a little confused. There are no "parent functions" in Javascript.

Looking at your example above, it seems like inside the socket.on callback function you want to do something that affects code outside that function. The important thing to recognize here is that it's a callback function - when the socket receives a message identified as something, it calls the callback function. There's no parent/child relationship involved.

So now that's a little clearer, let's consider your problem. You haven't explained exactly what you want to do outside the callback, so it's not clear what function you want stopped. But that's not terribly important - basically, what you're trying to do is signal code outside the callback when something inside the callback happens. There are a number of ways to do this, but one basic technique is to use a variable as a signal.

It is important to note that node.js applications are (usually) event-driven. This means that your code will almost always be in callbacks responding to stuff that is happening - there is no "main loop" that is waiting for stuff to happen.

So your code might look something like this:

exports.initGame = function (userdata) {
    // do prematch stuff with userdata and execute game logic on
    // the callbacks

    // set up a variable to signal when something important happens
    var importantSignal = null;

    socket.on("something", function (someNetdata)({
        // something important has happened! let the rest of the application know about it
        importantSignal = someNetdata.message;

        // do some other stuff related to the callback
    });

    // another socket event
    socket.on("another", function (someNetData) {
        // has something important happened?
        if (importantSignal) {
            console.log("I see that 'something' has already happened!");
            console.log("Message = " + importantSignal);
        }
    });
}

This is a simple type of message passing between callbacks - notice that the second callback has access to some state that was set in the first callback. But there's no sense in which the code in the first callback "controls" the second callback, except insofar as the second callback makes decisions based on state set in the first callback.

Kryten
  • 15,230
  • 6
  • 45
  • 68