Sending subjects to unique waitrooms

25 views
Skip to first unread message

Arjen Stolk

unread,
Nov 23, 2024, 1:13:07 PM11/23/24
to nodeGame
Hi Stefano et al.,

Thanks again for a fantastic platform. I have a question that seems conceptually simple but isn't clear to me in terms of implementation. 

In one of our current games, up to 2 subjects can join a waitroom, and if nobody else joins, the subject is paired with a bot. What I'd like to achieve is for every subject to end up playing the game with a bot, while still having the waitroom experience. 

One potential solution might be to forward each subject to a unique waitroom that cannot be joined by others, so that they still experience the waitroom and are paired with the bot.

I'm wondering how best to accomplish this. I've tried changing the MIN_PLAYERS and GROUP_SIZE flags in the settings, but none of these have yielded the desired outcome. Is there a way to configure the system so that participants are directed to unique waitrooms?

Best regards,
Arjen

Stefano Balietti

unread,
Nov 23, 2024, 1:33:35 PM11/23/24
to node...@googlegroups.com
Hi Arjen,

To implement a "fake" waiting room I would do the following.

Immediately dispatch a player to a _real_ room, where the first step is the "fake" waiting room. In this way, you are guaranteed to have one player and one bot in the same room. Notice the Waiting Room is a widget, so you could replicate the exact same behavior/appearance of a real waiting room. I have never tried this, but it should work. 

This is not directing players to new waiting rooms, but perhaps it solves your problem. Let me know, if it does not.

Cheers,
Stefano



--
You received this message because you are subscribed to the Google Groups "nodeGame" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nodegame+u...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/nodegame/CAAiwptQTkadsBonag3ka75HXwyWoO5M%3DitSXLFLzPXFV6XwBZg%40mail.gmail.com.

Arjen Stolk

unread,
Nov 23, 2024, 4:14:02 PM11/23/24
to node...@googlegroups.com
Hi Stefano,

Thanks for the quick response. Could another approach be to have the waitroom dispatch participants to individual rooms with a bot after "timeout", rather than to a shared room, as it does now when two players join? Do you think this is feasible in the high level code?

For completeness, the game has an individual practice, after which it sends people to the consent form followed by the waitroom, after which they're forwarded to the main game/"level".

Best,
Arjen

    ON_TIMEOUT_SERVER: function(player) {
this.CHOSEN_TREATMENT = 'bot';
this.dispatchWithBots();
return false; // prevents disposing the client
},


Stefano Balietti

unread,
Nov 24, 2024, 3:15:14 PM11/24/24
to node...@googlegroups.com
Hi Arjen,

Not sure I understood the question, but is this parameter perhaps what you are looking for?

  • DISPATCH_TO_SAME_ROOM: (boolean) If TRUE, every new group of players will be added to the same game room -- one per each treatment as returned by CHOSEN_TREATMENT. Default, FALSE. Notice: game should be a single-player task, or it must support adding new players while it is running.


Best,
Stefano


Arjen Stolk

unread,
Nov 24, 2024, 9:04:22 PM11/24/24
to node...@googlegroups.com
Hi Stefano,

It seems closely related: The option I'm looking for would be something like DISPATCH_TO_DIFFERENT_ROOM, to ensure that each player currently in the waiting room is dispatched to their own room (with a bot). If there's no straightforward way to enable this option, that's okay -- I'll leave it as it is and instead set a short timeout (obviously, the clean implementation would be a fake waitroom, as you initially suggested). This should reduce the likelihood of one human participant joining while another is already in the waiting room, leading to them playing together instead of each playing with a bot.

Best,
Arjen

Stefano Balietti

unread,
Nov 25, 2024, 3:26:35 AM11/25/24
to node...@googlegroups.com
Hi,

I see, now I understand. You could try this:

// At the top of the file:
const { PlayerList } = require('nodegame-client');

// ...

ON_TIMEOUT_SERVER: function(client) {
      
      // Connect one bot.
      const botOptions = {
        room: this,
        clientType: 'bot', // or other type
        setup: {}
     };
     const bot = this.channel.connectBot(botOptions);
    
      // Create custom dispatch List
      const pList = new PlayerList();
      // Timed out player.
      pList.add(client);
      // Bot.
      pList.add(bot);
      
      this.dispatch( { pList: pList });
}

This should dispatch the player that timed out with one bot in a new room. If you would like to dispatch _all_ players in the waiting room you can go through all objects inside:

this.clients.player // type Playerlist, e.g., this.clients.player.each(p => { ... });

Let me know if this is what you want.

Cheers,
Stefano

 





Arjen Stolk

unread,
Nov 25, 2024, 2:16:50 PM11/25/24
to node...@googlegroups.com
Hi Stefano,

Thank you for the suggestion. I've tried implementing it, but it seems that player.id remains undefined instead of being a string. I'm wondering if this behavior might be related to interactions with the previous waitroom settings. 

Could you please take a look at the relevant code to see if that's the case? Here's the link for reference: https://github.com/StolkArjen/tcg_kids/blob/main/levels/tcg_kids/waitroom/waitroom.settings.js ?

Looking forward to hearing your thoughts!

Best,
Arjen

Stefano Balietti

unread,
Nov 26, 2024, 3:38:59 AM11/26/24
to node...@googlegroups.com
Hi,

I could not run your game because of some errors, but I think I found some issues with the script I gave you earlier. Please try this updated script, it should work:

ON_TIMEOUT_SERVER: function (client) {

        // Connect one bot.
        const botOptions = {
            room: this,
            clientType: 'bot', // or other type
            setup: {}
        };
        const bot = this.channel.connectBot(botOptions);

        // Create custom dispatch List
        const pList = new PlayerList();
        // Timed out player.
        pList.add(client);
        
        // Add Bot data.
        pList.add(bot.player);
        this.dispatch({ pList: pList });

        // Prevent disconnect.
        return false;
    },

Cheers,
Stefano

Arjen Stolk

unread,
Nov 26, 2024, 10:09:13 AM11/26/24
to node...@googlegroups.com
Awesome, this works well most of the time -- thank you.

When one player times out, this leaves the other player stuck. You mentioned that it's possible to assign each player to a room with a bot (" this.clients.player.each(p => { ... });"). Could you provide some guidance on how to implement this? Specifically, how would I dynamically create rooms and assign each player to a bot in the event of a timeout?

Best,
Arjen


Stefano B

unread,
Nov 26, 2024, 10:33:02 AM11/26/24
to node...@googlegroups.com
Hi,

I am not at the computer, so I will give you a quick answer now. You basically have to move the current function (beside return false) inside the for-loop and each time you do this.dispatch({ pList: pList }); a new room is created for that group. Return false should be outside the for-loop.

Let me know if the hint is sufficient, otherwise I can provide the code later.

Best,
Stefano

Arjen Stolk

unread,
Nov 26, 2024, 2:59:23 PM11/26/24
to node...@googlegroups.com
Thanks, some code will go a long way. It’s not immediately clear to me what the sequence of events is when more than one player is connected.

On Nov 26, 2024, at 10:33 AM, Stefano B <stefanoba...@gmail.com> wrote:



Stefano B

unread,
Nov 27, 2024, 4:59:12 AM11/27/24
to node...@googlegroups.com
Hi Arjen,

If I understand your usecase correctly, you have two players that are together (perhaps in the lab) and you want to make them believe they play with each other, but they are playing with a bot at the same time. If this is correct, here is some code.

     // I have used the ON_CONNECT callback to avoid interference with normal dispatch calls.

     EXECUTION_MODE: 'WAIT_FOR_DISPATCH',

    GROUP_SIZE: 2,

    MAX_WAIT_TIME: 60000, // Any amount larger than the timeout below.
 
    ON_CONNECT: function(waitRoom, player) {
        // Auto play with bots on connect.
        if (player.clientType === 'bot') return;

        if (waitRoom.clients.player.size() === waitRoom.GROUP_SIZE) {

            setTimeout(() => {
                this.clients.player.each(client => {

                    // Connect one bot.
                    const botOptions = {
                        room: this,
                        clientType: 'bot', // or other type
                        setup: {},

                    };
                    const bot = this.channel.connectBot(botOptions);
       
                    // Create custom dispatch List
                    const pList = new PlayerList();
                    // Timed out player.
                    pList.add(client);
                    // Bot.
                    pList.add(bot.player);
                    this.dispatch({ pList: pList });
                });

            // TIMEOUT AFTER THE SECOND PLAYERS CONNECT.
            }, 5000);
        }
    },





Arjen Stolk

unread,
Nov 28, 2024, 9:39:40 PM11/28/24
to node...@googlegroups.com
Hi Stefano,

Thanks for sharing this code. I think we're getting closer, but my use case is slightly different. Essentially, there are two possible scenarios:

1) Someone (not in the lab) connects to the server, completes the consent process, waits in the waiting room, times out, and ultimately plays the game with a bot (as desired).
2) Similar to scenario #1, but a second player joins the waiting room while the first player is still there. In this case, the two players are paired to play together. However, the desired behavior is for each player to independently play the game with a bot (as in scenario #1), rather than with each other.

The provided code achieves the desired behavior in situation #1 but not in situation #2. For context, we're planning to deploy the game online, and we want to ensure that each player interacts with a bot, avoiding player-player interactions when two players coincidentally enter the waiting room at the same time.

Looking forward to your thoughts!

Best,
Arjen



Stefano B

unread,
Nov 29, 2024, 3:20:30 AM11/29/24
to node...@googlegroups.com
Hi Arjen,

I guess I don't understand scenario 2, because I would say that it is covered by the code. As soon as the second player connects, the game starts for both players and the two play independently. What am I missing? 

Best,
Stefano

Arjen Stolk

unread,
Nov 29, 2024, 2:20:39 PM11/29/24
to node...@googlegroups.com
Hi Stefano,

I'm not entirely sure. In instances where it works as intended, one player is assigned a bot, and the other one also gets assigned a bot after seeing the message "unfortunately, you were not connected with ...". It takes a few seconds, and then the game reloads for that player with a bot. 

However, in many cases, the players are still paired with each other instead of being matched with bots individually. I've tried various combinations of execution modes and callbacks (e.g., on_timeout_server, on_dispatch, and on_connect), but could not achieve consistent results.

Perhaps I'm still missing something. If you don't mind taking one last look at my settings, here's the link: https://github.com/StolkArjen/tcg_kids/blob/main/levels/tcg_kids/waitroom/waitroom.settings.js 
Alternatively, it might be best to move forward with the suboptimal but perhaps sufficient 'solution' of setting a low timeout time to minimize the likelihood of people entering the waiting room simultaneously.

Best,
Arjen


Stefano Balietti

unread,
Nov 29, 2024, 5:16:03 PM11/29/24
to node...@googlegroups.com
The issue is that you still have MAX_WAIT_TIME set. I wasn't using it, but then you don't get the timer displayed. 

You get that weird behavior because dispatchWithBots adds bots only if needed, and if the second player connects rather late in the timeout of the waiting room, the dispatch that is in the ON_CONNECT callback happens after that in the ON_TIMEOUT_SERVER callback (because of the timeout in the function), and players are paired together.

To keep MAX_WAIT_TIME in your current solution you just have to keep track of how many players are connected in ON_TIMEOUT_SERVER

    ON_TIMEOUT_SERVER: function(code) {
        // Wait! Somebody connect just before the timeout was about to expire.
        if (this.clients.player.size() >=2) return false;
        // ... dispatch with bots
    }

You also want to drastically reduce the timeout inside ON_CONNECT, or you can also remove it completely, but then the second player doesn't even see the waiting room, which could be fine.

I believe we got it right now, let me know.

Stefano

Arjen Stolk

unread,
Nov 29, 2024, 9:01:45 PM11/29/24
to node...@googlegroups.com
Hi Stefano,

I'm afraid something is off. The players are still frequently being paired together. For now, I'm planning to leave it for what it is. 

Just to be sure, could you double-check if I've correctly implemented your suggestion https://github.com/StolkArjen/tcg_kids/blob/main/levels/tcg_kids/waitroom/waitroom.settings.js
Note: I've tested both the timeout and wait_for_dispatch execution modes.

Best,
Arjen

Stefano Balietti

unread,
Dec 3, 2024, 9:22:16 AM12/3/24
to node...@googlegroups.com
Hi Arjen,

I had another go at checking your settings and I found two issues.

1) It's probably a bug of nodegame, but if game.setup is not found, it can lead to crashing the new game room inside a level. Please copy the game.setup file from the game inside the level.

2) The settings of the waiting room that I just pulled were a bit off.

Here are the relevant settings:


const { PlayerList } = require('nodegame-client')

   ON_CONNECT: function(waitRoom, player) {
        // Auto play with bots on connect.
        if (player.clientType === 'bot') return;

        if (waitRoom.clients.player.size() === waitRoom.GROUP_SIZE) {

            setTimeout(() => {
                this.clients.player.each(client => {
                    // Connect one bot.
                    const botOptions = {
                        room: this,
                        clientType: 'bot', // or other type
                        setup: {},
                    //id: 'bot_' + botCounter++

                    };
                    const bot = this.channel.connectBot(botOptions);
       
                    // Create custom dispatch List
                    const pList = new PlayerList();
                    // Timed out player.
                    pList.add(client);
                    // Bot.
                    pList.add(bot.player);
                    this.dispatch({ pList: pList });
                });

            }, 200);
        }
    },

    ON_TIMEOUT_SERVER: function(code) {

    if (this.clients.player.size() >=2) return false;
        this.CHOSEN_TREATMENT = 'bot';
        this.dispatchWithBots();

        console.log('*** I am timed out! ', code.id);
        return false;
    },

MAX_WAIT_TIME: 15000,

 GROUP_SIZE: 2,

 EXECUTION_MODE: 'TIMEOUT'


----------

With those changes the game seems to run well (for testing I was sending a msg 'skip_practice' ).

Let me know if we managed to solve it this time :)

Best,
Stefano



Arjen Stolk

unread,
Dec 4, 2024, 4:59:50 PM12/4/24
to node...@googlegroups.com
Hi Stefano,

Thanks for pushing on -- your persistence is a big part of why nodeGame is such a great platform!* The crashes seem to have been resolved, yet there still seems to be some randomness in the pairing process: sometimes players remain paired together, and other times each is paired with a bot. When paired with a bot, both are sometimes assigned as senders (which is correct), but in other cases, one is assigned as the sender and the other as receiver (which is incorrect). I've tried to catch this in the logic, ensuring that the bot is assigned the second player/role, but to no avail.

Additionally, the first dispatched player is always labeled as receiving the standard treatment (incorrect), even when they actually end up playing with a bot. This happens despite the fact that on_dispatch is supposed to change the treatment to "bot" when a bot is detected.

I suspect an underlying issue where nodeGame struggles to overwrite the initial assignment of the first player at some level, but I'm unsure if and where this might be happening. I've pushed the latest code to github, but if you'd like me to demo the game/issue, I'd be happy to hop on a zoom call!

Best,
Arjen

*We're currently in the process of writing up our first study using it!

Stefano Balietti

unread,
Dec 10, 2024, 4:05:24 AM12/10/24
to node...@googlegroups.com
Hi Arjen,

Sorry for the delay. Let's hop on a Zoom call, it will be easier to understand what's going on. Please let's coordinate off the mailing list.

Cheers,
Stefano

shakty

unread,
Dec 16, 2024, 3:03:44 AM12/16/24
to nodeGame

For future reference, the issue was caused by an incompatibility of the option PING_BEFORE_DISPATCH in version 7.10 stable. The issue is fixed in current development version v8.
Reply all
Reply to author
Forward
0 new messages