Sign In Register

How can we help you today?

Start a new topic
Answered

Get random player data

Hello,


I know that some people already asked a similar question but their question was about challenges. My game is a city builder game similar to Clash Of Clans. I want at some point in the game the player will be able to get a random player in the same level and access his "scriptData". He will be changing the random's player data (Stealing Gold for example)

I don't think that this can be considered as a challenge, right? The other player in this case won't do anything except being robbed!


Best Answer

So first of all you would want to do this with cloud code via an event. The problem is that the gamesparks system "player" collection is unqueryable via cloud code. But this is actually good for you because you probably don't want to store all the info you will need on a player for a city building game in the player's script data. That will get messy and complex really quickly. But there's a solution! Create a custom collection for storing all this info with a document for each player. See the article by gamesparks here for how to set that up:

https://support.gamesparks.net/support/discussions/topics/1000070846


Once you do that you'd have a playerList collection with id = player id and a level. Then you can create an event with cloud code something like this:  

 getRandomPlayerState();    

function getRandomPlayerState(){
    var query =  { 
        "_id" : { "$ne" : Spark.getPlayer().getPlayerId() }//,
    };
    var fields = {};
    
    // Iinefficient, switch to $sample aggregation when Gamesparks upgrades to mongodb v3.2
    var count = Spark.runtimeCollection("playerList").find(query, fields).count();
    var rand = Math.floor(Math.random()*count);
    var results = Spark.runtimeCollection("playerList").find(query, fields).skip(rand).limit(1).toArray();
    
    if(results){
        var playerToRob = results[0];
    }
}

 

That will grab a random playerList doc from the collection not including the player who is robbing (so he doesn't rob himself!). As far as matching the player level, you'd either first have to do a separate query for the robbing player's own level (if it's only stored in the playerList), or you might be able to write a really clever aggregation to get it. In fact, once gamesparks upgrades to mongodb v3.2 you might be able to make one really clever aggregation get the random player in one database query (something like $match all players $ne to self with level = to self level, $group to count, and then $sample to randomly pick one). To see an intro to aggregation by gamesparks check here:

https://docs.gamesparks.net/howtos/cloud-data/partial-updates


From there you have a random player, you can call Spark.loadPlayer(playerToRob's id) to be able to debit currency from them. And finally you could then send a message to both the robber and the robbed players from cloud code to notify them. Whew, hope that helps you get started!


Awesome! Glad to be of help.

Hi Ryan, that's really fantastic! Thanks a lot!

I even slightly modified the match, so it doesn't peek the same player that does the request and to allow me to select a type of player:

var match = {"$match": { "level": { "$gte": MIN_LEVEL, "$lte": MAX_LEVEL }, "type" : type, "player_id" : { "$ne" : playerID } } };

Thanks again! Really helpful!


1 person likes this

Also note, using multiple aggregation stages (e.g. match and sample in this case) in GS is a little weird (unless they have fixed that).


-In the NoSQL explorer, if you have multiple aggregation stages, you have to put them in an array [{...}, {...}]

-According to the docs, in cloud code, the method signature is the first stage followed by an array of the rest of the stages

-But I have had success using 2 stages without an array in cloud code, like I showed above


All that to say if something's not working with the aggregation method call, play around with the params / putting them in an array.

Ryan Fuller here, haha. 


Assuming you have a runtime collection named "playerState" with a field on the documents named "level" something like the following should work:


var match =   {"$match": { "level": { "$gte": MIN_LEVEL, "$lte": MAX_LEVEL } };

var sample = { "$sample": { "size": 1 } };

var result = Spark.runtimeCollection("playerState").aggregate(match, sample);

var randomPlayer = result[0];

 


1 person likes this

I know this question is a bit old, but would anyone actually know how to use aggregate as Ryan Fuller suggested?
I basically need the same solution: find a random player within a level range, but I'm not really familiar with MongoDB hence the doubt.

Thanks!

Yes, sorry I dint updated here that I alredy have it working! My problem was I dont fully understand how setScriptData works >.<

Now I do and I have it working and just a moment ago I was able to solve the next step, Load the enemy player data in Unity!

Thanks for the help Ryan!

So if you don't need to send a message to the random player, it's much simpler (i.e. if you only need the player who's sending the request to receive the response), you can just set the player to the scriptData in cloud code:

var randomPlayer = // Code you already have

Spark.setScriptData("randomPlayer", randomPlayer);

 

And as to how you grab it on the client, get it from the response scriptData:

new GameSparks.Api.Requests.LogEventRequest() .SetEventKey("FIND_PLAYER").Send((response) => {
	if(response.HasErrors){
		// Log the errors
	}
	else {
		GSData randomPlayer = response.ScriptData.GetObject("randomPlayer");

		// Get details about player (dependant on the structure of the player)
		// For example:
		// int level = randomPlayer.GetInt("level") ?? 0;
	}
}

 


1 person likes this

Yes I'm developing it in Unity, I have created a new Cloud Code named "FIND_PLAYER" with the code you wrote.


Then I was calling it from Unity something like:

new GameSparks.Api.Requests.LogEventRequest() .SetEventKey("FIND_PLAYER").Send((response) => {

Here I dont know what to do to get the generated random ID

}


I cant find sendmessage in the api documentation to know how it works. I know is much to ask but you give me an example?

Thanks!

Hey it's the same guy who gave the original answer.


Are you saying you have all the stuff I wrote set up in cloud code but you don't know how to send the playerId of the random player to the client? 


If so, all you need to do is use the script sendmessage api from cloud code, and then add a listener to your C# to receive the message and respond.


GameSparks - Messaging


1 person likes this

I know this is quite old post, but I cant figure out how to load the random player ID into Unity. Can someone help?

No problem!

Thanks a lot for the help :)

Answer

So first of all you would want to do this with cloud code via an event. The problem is that the gamesparks system "player" collection is unqueryable via cloud code. But this is actually good for you because you probably don't want to store all the info you will need on a player for a city building game in the player's script data. That will get messy and complex really quickly. But there's a solution! Create a custom collection for storing all this info with a document for each player. See the article by gamesparks here for how to set that up:

https://support.gamesparks.net/support/discussions/topics/1000070846


Once you do that you'd have a playerList collection with id = player id and a level. Then you can create an event with cloud code something like this:  

 getRandomPlayerState();    

function getRandomPlayerState(){
    var query =  { 
        "_id" : { "$ne" : Spark.getPlayer().getPlayerId() }//,
    };
    var fields = {};
    
    // Iinefficient, switch to $sample aggregation when Gamesparks upgrades to mongodb v3.2
    var count = Spark.runtimeCollection("playerList").find(query, fields).count();
    var rand = Math.floor(Math.random()*count);
    var results = Spark.runtimeCollection("playerList").find(query, fields).skip(rand).limit(1).toArray();
    
    if(results){
        var playerToRob = results[0];
    }
}

 

That will grab a random playerList doc from the collection not including the player who is robbing (so he doesn't rob himself!). As far as matching the player level, you'd either first have to do a separate query for the robbing player's own level (if it's only stored in the playerList), or you might be able to write a really clever aggregation to get it. In fact, once gamesparks upgrades to mongodb v3.2 you might be able to make one really clever aggregation get the random player in one database query (something like $match all players $ne to self with level = to self level, $group to count, and then $sample to randomly pick one). To see an intro to aggregation by gamesparks check here:

https://docs.gamesparks.net/howtos/cloud-data/partial-updates


From there you have a random player, you can call Spark.loadPlayer(playerToRob's id) to be able to debit currency from them. And finally you could then send a message to both the robber and the robbed players from cloud code to notify them. Whew, hope that helps you get started!

Login to post a comment