Multiplayer online experiment

Hi,

We are hoping to run two experiments online using Pavlovia, both of which are multiplayer. One is a simple grid game similar to a Hawk-Dove game. But the other is more complex, and so we are avoiding Gorilla which has a clunky interface and only minimal online support/tutorials.

So, I was wondering if there was some existing knowledge on how to use PHP:MySQL within psychopy/Pavlovia to add multiple players to a lobby, pair players up, and then start an experiment for each pair of players where each player’s actions are added to an online database. Information can then be pulled from this database to update the other player’s screen. I am very familiar with online experiments in Pavlovia but not familiar with PHP or MySQL. We do not need particularly accurate timing information.

Any help would be much appreciated!

Many thanks,
James

There some documentation here about using the Shelf for multiplayer games. Hope this can help you get started with your task :slight_smile:

Thanks a lot! This looks very useful

Hi again,

Is there any way to speed up the get information calls to the shelf?
I noticed the task was taking a very long time, and it seems that the “await” calls to the shelf can take between 20 and 60 seconds to complete. They seem to take longer if the variable on the shelf has been interacted with just before the call (e.g., through a set… function), or if a variable value is fetched, edited, and then re-uploaded.

I need this functionality because at some point the code needs to fetch a list of participants, and then pair up participants if there is an even number of them, and then reupload the information about pairs.

The following code, where a dictionary value is fetched, edited and re-uploaded, takes 10-15 seconds.

startTime1 = globalClock.getTime()
participants= await psychoJS.shelf.getDictionaryFieldValue({key: ["General"], fieldName:'participants'})
participants=['blah']
psychoJS.shelf.setDictionaryFieldValue({key: ["General"], fieldName: 'participants', fieldValue : participants})
Diff1=(globalClock.getTime()-startTime1)
text2=Diff1.toString()

However, the code below, which occurs immediately after the previous code, takes around 25-35 seconds. Here there should be less happening (the information is fetched but not re-uploaded), and yet, perhaps because it has just been edited, this code takes much longer.

startTime1 = globalClock.getTime()
participants= await psychoJS.shelf.getDictionaryFieldValue({key: ["General"], fieldName:'participants'})
Diff1=(globalClock.getTime()-startTime1)
text3=Diff1.toString()

If say 10 participants come online and engage with the task at a similar time (to form 5 pairs), the shelf will have to manage requests from 10 people and each request may get even slower.

Many thanks for your help!
James

Hi James, I must admit my knowledge in pinging the shelf is quite limited but @apitiot should be able to provide better insight into making faster calls.

I also suggest contacting consultancy@opensciencetools.org to see if they have any alternative recommendations on building your task so that it could be less intensive on the shelf

Best,
Sue Lynn

In order to prevent calls to the shelf overloading the Pavlovia server there is a minimum time between calls (I think of about a second) and it seems that actual performance is often a lot worse than this. Is there a way you can reduce your calls?

I write my VESPR tools in php/mysql and could probably write a “lobby” tool from where participants could launch PsychoPy experiments in pairs. The pair id could be placed on the shelf when they arrive at the experiment or simply saved in the data file. How much interaction would be needed between the players during the experiment?

Hi!

Thanks for your help! There may not be a need for the php/mysql method yet, though it sounds useful.

I found that if I add a small wait (200ms) just before each attempt to write to or fetch data from the shelf, the lag reduces greatly, and each interaction with the shelf now takes only about 1 second, which is fine.

So I defined a simple function at the start.

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

And then use this function just before any call to the shelf, e.g.,

await sleep(200);
Participants = await psychoJS.shelf.getListValue({key: ["Participants"]})
// DO SOMETHING TO THE PARTICIPANT LIST
await sleep(200);
psychoJS.shelf.setListValue({key: ["Participants "], value: Participants})

Perhaps without this brief pause, requests were too close together, leading to longer delays.
This is all done in a ‘begin routine’ tab before any task begins, so shouldn’t affect the experiment timings too much (though we aren’t interested in accurate reaction times particularly).

Once participants are paired up, the interactions with the shelf are quite limited. It will be something like a prisoner’s dilemma game, so in each trial participants need to send their choice to the shelf and fetch the other participant’s choice.

At the moment, I have it set up so that there is a Boolean ‘edit’ variable on the shelf as well. Participants can only edit the participant and pair list if this edit variable is false, and once they start editing it is set to true to avoid other participants editing simultaneously. Otherwise, two participants might download the participant list, edit it, and then upload it together, with one overwriting the other.

1 Like

That is really useful info and is an exception to my “no sleep” advice (which is mostly when it gets used in an Each Frame tab – Begin Routine should definitely be fine.