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

Thats right.
The server would have no connection after Disconnect() is called, so there would be no way for it to trigger the callback itself. I suppose we can investigate having the SDK call it when it loses connection.

Sean

 

ps: I noticed when I call GameSparksRTUnity.Instance.Disconnect() it doesn't fire OnReady(false) as I would expect. is this intended (for now I poll GameSparksRTUnity.Instance.Ready each frame)

ok thanks.


I actually found out I am sending a "PlayerPause" packet in onPlayerConnect so I used that (I am manually tracking player connection by pinging each player constantly (every 15 seconds) and consider them paused if they don't respond in 10s, so if they have the app in background but their socket is not killed I can put bots in their place)


[2] by "available" you mean I should manually track whether a particular bot-player is currently in an RT session and use only free ones?

Good point. I was originally thinking you might encounter problems trying to match two players who are already in an existing match, but it would appear that forcing the match means you can just re-use that same player.


[2.1] if so, is there an "RTSession ended" callback i should use?

There is not, but if you need this information in the future you can query the 'matchInstance' collection for a matching playerID in the participant data there.



is there a range of OpCodes I can/should use for RT? (is 0 allowed? negatives? int.maxValue?) for now I stayed safe and used [1-127] but I'd like to put that new "pre-init" before (or at least grouped with my other init-ish opCodes)

The value does have to be positive cannot be 0, anything over that is allowed. op-code is a 'uint' so max value is around 4M.


ok, so

[1] I already have a custom event to switch from "Waiting" to "Game" mode, so I already have setup something similar

[2] by "available" you mean I should manually track whether a particular bot-player is currently in an RT session and use only free ones?

  [2.1] if so, is there an "RTSession ended" callback i should use?

  [2.2] if not, can I use a single bot player to act as a "ghost" only for the connection phase to start the session (that player will "join" the RT session but will never connect and I don't care if it leaves instantly, only that the session itself is up

[3][4][5] exactly what I already do (except now is human-only)


is there a range of OpCodes I can/should use for RT? (is 0 allowed? negatives? int.maxValue?) for now I stayed safe and used [1-127] but I'd like to put that new "pre-init" before (or at least grouped with my other init-ish opCodes)

Regarding the init-packet, it is possible that the server isnt fully config'd by the time OnReady is called.
I would suggest sending an packet from Onplayerconnected server-side to notify the player it is okay to send the init-packet.

Sean

 

 

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)

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,

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, 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)

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


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)

 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

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)

 

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?)

Login to post a comment