Sign In Register

How can we help you today?

Start a new topic
Answered

Sharing data between players in pending match

Hi,

is there a way to share data between players that are in a pending match during matchmaking process?

there is a matchData but it seems read-only...


what I want to do is:

players start matchmaking for a 4-player match

while there are exactly 2 players in the pending match, they can set a flag to play the 2-player variant (by pressing a button int their UI)

if both players have set the flag, abort the matchmaking process and put them in a separate 2-player match (instantly)

(then wait for the MatchFoundMessage to start a RT session)


Best Answer
Hey Mauro,

There is an option when setting up a match to have it accept the min number of players. You can also enable the match to be drop-in/drop-out.
So in your example, a match has min-2, max-4 players, and a match can accept the min number of players.
This means that when two players join the match, they both get matchFound messages, and a match ID.

The match ID is important, as you can use this to find the match using the SparkMultiplayer API.
The process would work as follows....

[1] - you create a custom event which will load the match.
[2] - you then use the SparkMatch API to set the match data stating that this player has opted for a 1v1 match.
[3] - if more than one player has opted into the match, create a new match with only those two player IDs
[4] - cancel matchmaking for each player

This will cause the two players to get MatchFound messages for their 1v1 match.

Does that make sense?
Let me know if you need anymore info on this, i have included an outline of how this can be done in a cloud-code script attached.

Thanks,
Sean

 

js

Answer
Hey Mauro,

There is an option when setting up a match to have it accept the min number of players. You can also enable the match to be drop-in/drop-out.
So in your example, a match has min-2, max-4 players, and a match can accept the min number of players.
This means that when two players join the match, they both get matchFound messages, and a match ID.

The match ID is important, as you can use this to find the match using the SparkMultiplayer API.
The process would work as follows....

[1] - you create a custom event which will load the match.
[2] - you then use the SparkMatch API to set the match data stating that this player has opted for a 1v1 match.
[3] - if more than one player has opted into the match, create a new match with only those two player IDs
[4] - cancel matchmaking for each player

This will cause the two players to get MatchFound messages for their 1v1 match.

Does that make sense?
Let me know if you need anymore info on this, i have included an outline of how this can be done in a cloud-code script attached.

Thanks,
Sean

 

js

Hi,

I am starting to experiment with your process, except I am using realtime, so if I have the match (and the session) early I can sync everything there.

for now I do:

[1] - players do a LogEventRequest_CreatePendingMatch, which in turn it does a Spark.getConfig().getMatchConfig(data.match).createPendingMatch(data.matchGroup , skill, playerData)

  [1.1] I use a custom event because I am planing to support players creating [pending]matches with friends, then search for random players to fill the empty positions (game is default 4 players 2v2, a player will be able to play alone with 3 random others or invite X friends [x in 1..3] and find (3-X) random players to match - those players may already be paired with 1 friend and "count 2")

[2] - Players get a MatchFoundMessage and start a RT session

[3] - player will stay in a waiting state (i.e. bot in RT session and in matchmaking) until either:

  [3a] 4 players join the session

  [3b] exactly 2 players join the session and bot have the flag set (flag will be sent as RT packet)

[4] match starts


what I am still missing is: 

[1] prevent other players to join the match if the game is started (I check after they join and kick them out) - is cancelling matchmaking enough?

  [1.1] more generally, if i cancel the matchmaking can someone else still join my match (and RT session)?

[2] have a MFM as early as I create the [pending] match - this will cover the following cases:

  [2.1] less duplication between before and after the RT session - now I have to do the same stuff twice depending if I am still alone or not

  [2.2] having 1 player vs 3 bots if there isn't enough players online - see my question here

    [2.2.1] I tried createPendingMatch with 3 players I created as bots, but it seems GameSparks doesn't match them if they are not online


Hey Mauro,

So, unfortunately there is no ability to 'close' a match like this at the moment, but i am going to investigate adding that ability to the platform. I will keep you updated on what comes from that.
Cancelling matchmaking will only cancel it for a player who is currently looking. You do want to allow every player to continue to look for other match instances, so this might not be what you are after.

One alternative solution would be to disconnect the two players from the current RT session and create a new 2 player match with their IDs manually.

Im not sure what you mean by MFM, so if you could explain to me a bit on that topic i can help further. Sorry about that.

As for the bots, what i suggest is setting up a system to run a custom match when the player gets the MatchNotFoundMessage (you may need to add some script data to this message so you can tell the client to ignore any dialogue you may have by default for failed matches). This code can take the playerId and the IDs of 3 bot-players you keep a list of, and manually setup a match with those players.
Does that make sense?

Let us know if that advice is clear or if you need further information.

Thanks,
Sean

 

sorry, MFM stands for MatchFoundMessage


I am currently trying to do this (cancelling matchmaking, disconnect the RT and create a match with the IDs) without disrupting the existing code too much (which starts the RT and then manages internally the state - waiting or playing - and I literally rewrote to account for dropin/dropout)


I have to evaluate if it's better to create a separate RT script (duplicating code) or do everything in a single script


I noticed a "realtime modules" section appeared in my cloud code, but I can't find any docs. is it usable? 


for the MatchNotFoundMessage stuff:

1 - I tried to do a createPendingMatch before, but it seems to match only online players - is it a limitation of pendingMatch or the fact it's realtime? 

2 - for now I generate the bots client-side with a random GUID and sync them with the RT - what would be the preferred way to get a bot-player to match and how many do I need in total? is using the same 3 players to join every match that needs a bot enough or they would be removed from the other matches and I need to use a big enough player pool for this?

I dont think a separate script will make any difference, and you also have a small performance consideration that the RT script will be cached the first time it is used and for any following connection while that script is running in an instance.

So it would be slightly quicker, as you will most likely have many of the normal match instances running.

Now, i may be misunderstanding your question and you mean you will need a new script for the 1 player/3 bots match.

In this case i do recommend a separate script as your bots will have behaviors specific to that kind of match if you are going to balance it properly. But i reckon, in that case, it might be a good idea to take the match offline altogether and just simulate the match on the client.



[1] - You should be able to use createMatchById() to match players directly, you shouldnt use pending match for this example.


[2] - As mentioned above, bots with RT scripts are tricky.
Adding in dummy players to act as bots and complete the match will mean you get charged for those players as they will count towards your MAUs.


You also have no idea how many dummy-players you need. Though you could easily create a system in cloud code that finds a dummy-player not currently in a match and uses them; when there are no available dummy-players to join, you create a new one in cloud-code.


One thing you could do is have special match setup so that when MatchNotFound message is fired, all players in the pending match get put into a new match which has bots that run from the RT script and no dummy-players.

i.e, in a 4 player match, if two players stay pending for 30s or more, they get a MNF message. In there, you take those two playerIds and create a "2playerV2bot" match, which accepts only 2 players, but the RT script can send a message on connection to tell the user to spawn two additional players in the client that it will send packets to control those.

Does that make sense?
Please let me know if that is a suitable alternative.

Thanks,
Sean




Hi,

bots are already managed client-side (no server-side logic is needed, so my teammates can test the game offline). the only thing I miss is having a RT session for 1 human / 3 bots for which I need to put at least one fake player in there to start the RT session


for now, I have a StartPlaying event with the following code:

 

 var matchOrder = JSON.parse(data.matchOrder);
    var players = [];
    matchOrder.forEach(function(s) {
        switch (s.Status) {
            case 2: // PlayerSeated
                var p = Spark.loadPlayer(s.UserId);
                players.push(p);
                Spark.getMultiplayer().cancelMatchmaking(p, data.shortCode, data.matchGroup);
                break;
            case 3: // Bot
                // TODO bot
                break;
            default:break;// should not happen
        }
    });
    var matchId = Spark.getMultiplayer().createMatch(players);
    Spark.getLog().info({matchId:matchId});
    var match = Spark.getMultiplayer().loadMatch(matchId);
    
    match.enableRealtime("Game3");
    match.setMatchData({
        i:"hope this is in the MFM" //temp value, to be filled with actual parameters
    });
    Spark.setScriptData("newMatchId", matchId);
    Spark.setScriptData("participants", match.getParticipants().length);

 it seems to create the match (i get the matchId correctly and it doesn't crash in the line following loadMatch) but it doesn't fire any MatchFoundMessage. do I need to send it manually? (or, how to retrieve the RT args to connect the client?)

I found the RT connection parameters

match.getServer().getHost();
match.getServer().getPort();
match.getParticipants()[x].getAccessToken();

then I return them to the RT script that forwards to each player his access token


but something strange happened: GameSparks is not anymore able to refresh my RT scripts, it hangs for 5 second when I try to connect and load an old version. this afternoon I "fixed" it by removing code (even if I commented out everything it still hanged, I had to drop it) but then it reappeared. now I split my game script into waiting and playing states, (duplicating about 50%) it worked for a couple of minutes and then broke again.

I have no feedback of what the problem could be, the only log I have is about a function not defined but I removed that and it persists regardless (last time only, the other times nothing whatsoever)

 

 Hey Mauro,

I dont think you will get the 1 player /3 bots working with RT, even if you manage to force a connection with a dummy-player in order to complete the match, you need the second player to connect using the SDK, which you wont be able to do. So the 'match' might be completed, but you cant start the session properly as you'll only have one player. The RT script will also be set to relay information to another player, so im not sure what will happen if you force it to send packets to a player not connected. We have not yet tested those cases,


It makes more sense to take the whole match offline at this point, as introducing the server will add extra communication with the server that is no longer needed if all your bots are running on the client. You would effectively be introducing a round-trip time that doesnt need to be there.


As for the RT script issue, if all matches of a particular shortcode are finished and you try start a new session, it will cache the RT script. This usually results in a delay of a few seconds, after which there wont be a delay until you wait a few minutes (usually around 5mins) after the last match has ended.

But this hang sounds like the RT script is broken.
Can you check the RT script log to see if there are any errors there?
There other thing you need to bear in mind is that if there are errors in the RT script, it could also take 5mins after all matches have ended before your changes to the script take affect.

This is a pain to deal with from a workflow point of view, but it comes from some optimizations we have in place for our live clusters with high volumes of players.

Sean

Hi,


for the 1 player / 3 bots RT: I am not directly sending packets between players, the client is sending all packets to the server (peer 0) which performs simple validation and sends a corresponding packet (possibly adding/removing fields) to all clients, including the original sender. this way all clients experience the same round-trip time both for their packets and for other player's.

I want RT with a single player to have the same behaviour, both from a code perspective and from a UX perspective. ideally, a player should not be able to distinguish a bot from another human. (anyway, this use case is a fallback for the case there is no match found and we don't plan to actively have single-player)


for the RT issue: it started friday afternoon and I didn't have any logs ( I searched NoSQL realtime.log with query {"source":"<my short code>"}) then I bisected the code (i.e. I removed everything and added one function at a time) and found an error in my script (i was calling an RTSession function with the wrong number of parameters). I fixed that and it started working again, but after a short while it broke again. I bisected the code but there was no apparent issue and the script broke after a certain amount of code was included, didn't matter which (I had 615 lines and it broke, I removed one function and it worked, i restored that function and removed another one and still worked) I then removed some RTSession.getLogger().debug("....") around to go under 600 lines and it worked. it broke again after I added other code.

I then split the code in 2 parts: a "Game" script and a "Waiting" script. waiting script is now 481 lines and broken.

friday night I had some logs that complained about this function not being defined at line 36:

function listen(opCode,callback) {
    RTSession.onPacket(opCode, function(packet){
        try {
            callback(packet);
        } catch (err) {
            trace("error",[err,err.stack]);
            sendError(opCode, err.stack || err);
        }
    })
}

 but this function does exist and around line 36 there was only definitions of "enum" values I use around.

the log remained the same even if I moved around most of the code.

this morning I retried (without modifying the code since last time) and there is no more log message but script it still broken


for the 5min delay: I am only in preview mode, is there no way to bypass those optimizations and/or at least get a meaningful error message?

(btw the line number on logs is wrong if there is a statement that spans multiple lines above the log statement)

ok, I tried with a new match config with this exact RT script:  

 

// ====================================================================================================
//
// Cloud Code for module, write your code here to customise the GameSparks platform.
//
// For details of the GameSparks Cloud Code API see https://portal.gamesparks.net/docs.htm			
//
// ====================================================================================================

var counter = 0;

RTSession.setInterval(function(){
    ++counter;
    RTSession.newPacket()
        .setReliable(true)
        .setOpCode(1)
        .setData(RTSession.newData().setNumber(1, counter))
        .send();
}, 1000);
RTSession.onPlayerConnect(function(player){
    RTSession.getLogger().info("player connected: "+player.getPlayerId()+" as "+player.getPeerId());
})

 

this is the same script I used for exploring RT API some weeks ago (shortcode "ExampleRT") and I didn't modify it since then.

STILL NO LOG FROM IT and no packet sent to the client (my MatchFoundMessage has the new shortcode in it and its config has been created directly with ExampleRT script attached). it seems the entire RT platform is broken


ok, I tried with a new match config with the attached RT script.

this is the same script I used for exploring RT API some weeks ago (shortcode "ExampleRT") and I didn't modify it since then.

STILL NO LOG FROM IT and no packet sent to the client (my MatchFoundMessage has the new shortcode in it and its config has been created directly with ExampleRT script attached). it seems the entire RT platform is broken


js
(773 Bytes)

Hey Mauro,

Just wanted to keep you informed on this post.
I will try setup a match using this criteria to test your setup and let you know how it goes.

My thinking is that this will be a special 2 player match which you can create from the live player and one of your bots.
Then you can add in the code to run the 3 bots yourself?
You could add 3 dummy players into a 4 player match, but if you can get it working with only 2 players matched it would reduce the MAU caused by using these dummy players.

Sean

ok thanks.


I noticed that sometimes i lose some packets:

each client sends a Init packet inside its OnReady callback (with GameSparksRT.DeliveryIntent.RELIABLE) but the first one doesn't arrive on the server (it sends it before getting OnPlayerConnected for the other player - is it a bug or I need to wait something else before sending packets?

this (Init) is the only packet for which I noticed this loss, other packets I send after seems to arrive just fine

 

Hey Mauro,


So i have a solution to setting up your 1v4 match with bots.
This will work for a 1vbot with 2 bots controlled by client or RT script, or setup between 1player and 3bots.

[1] Create a new custom event.

[2] search for an available bot using whatever username you use to define bots.

[3] create a new match using the ID of the the player and your bots.

[4] enable realtime on this match (and add the specific script you need, see api )

[5] return the necessary data needed to connect to the server (port,host, access-token)


You only need the live player's data so you can return those details only.


Now, bear in mind that im not sure how the RT script will act if you try to send data to those players who are not connected.
But this will allow you to connect to the RT server.

Sean

js
(864 Bytes)
Login to post a comment