Sign In Register

How can we help you today?

Start a new topic
Answered

Linking Player to Facebook in a Custom Collection

I have made a custom collection of players and I use that for most of the operations within my game. All the stats are stored in the custom collection, though I still the system collection for turns and other things automatically managed by GameSparks.


Now it may happen that a user, registered by device, wants to connect Facebook. The user doesn't want to loose all the progress up to that point when switching to Facebook.


I insert a new instance into the custom player list collection in the AuthenticationResponse code. What I am trying to do is to look if the new player is from Facebook and if so copying the statistics from the  device registered ID. But I can't see any field in the system collection that links the new Facebook player to the old device registered player.


How can I retrieve informations about the previous user when it's connecting to Facebook?


Best Answer

I sent a ticket to the support and we found out the problem was that I was deleting the players manually from the noSQL database when I should have used deletePlayer from the Cloud Code. The remedy was to delete all the entries in the externalAuthentication collection so that now when I connect Facebook, the account is merged and linked.


Now I can use your code, Christian. Thanks.


Hi Andrea,


If a user connected by device wants to connect with facebook, your game code will call FacebookConnectRequest. This will automatically link the current "player" with facebook authentication. So there's nothing else to do on your part. You custom collection of players will be linked to the same player.


If you want FacebookConnectRequest to create a new player you'll have to set doNotLinkToCurrentPlayer to true but this is what you want.


The doc:

https://docs.gamesparks.com/api-documentation/request-api/authentication/facebookconnectrequest.html

The problem is that I can't know what was the old device registered account of the new Facebook player... I needed because the custom collection is not linked. Why do you say that is linked even in the custom collection?


This is my code in the AuthenticationResponse for inserting a new player into my custom collection:

   

if( Spark.getData().newPlayer )
{
    var isFB = false;
    var fbID = null;
    if( Spark.getPlayer().getExternalIds().FB != undefined ) {
        isFB = true;
        fbID = Spark.getPlayer().getExternalIds().FB;
    }/*
    if( Spark.getPlayer().getUserName().split("_")[0].localeCompare("FB") === 0 ) {
        isFB = true;
        fbID = Spark.getPlayer().getUserName().split("_")[1];
    }*/
    
    var name;
    if(isFB)        name = Spark.getPlayer().getDisplayName();
    else            name = randomNames[Math.floor(Math.random()*randomNames.length)];
    
    Spark.runtimeCollection("playersList").insert( {
        "playerId" : Spark.getPlayer().getPlayerId(),
        "isFacebookConnected" : isFB,
        "facebookId" : fbID,
        "playerName" : name,
        "bio" : randomBios[Math.floor(Math.random()*randomBios.length)],
        "avatarIndex" : 0 ,
        "level" : 0,
        "totalSquarcuits" : 0,
        "totalWon" : 0,
        "totalLost" : 0
    } );

 I need a way to figure out if the new player is coming from a device registered account.  If so, then I can upload the player data as 'Facebook connected' instead to insert a new player into the runtime collection.

Here's what you can do if you don't mind hitting the db each time a user is connecting.


 

 

var player = Spark.getPlayer();
var playerId = player.getPlayerId();
var fbID = player.getExternalIds().FB;

//Only fetching the customPlayer.facebookId to make it as ligthweight as possible
var customPlayer = Spark.runtimeCollection("playersList").findOne({"playerId":playerId}, {"facebookId":true});

if (customPlayer !== null) {
	if (fbID !== undefined && customPlayer.facebookId !== fbID){
	    Spark.runtimeCollection("playersList").update({"playerId": playerId}, 
	    												{$set:{"isFacebookConnected":true, "facebookId":fbID, "playerName":player.getDisplayName()}},
	    												false, false);
	}
}
else {
    var isFB = fbID != undefined;   
    var name = isFB ? player.getDisplayName() : randomNames[Math.floor(Math.random()*randomNames.length)];
    
    Spark.runtimeCollection("playersList").insert( {
        "playerId" : playerId,
        "isFacebookConnected" : isFB,
        "facebookId" : fbID,
        "playerName" : name,
        "bio" : randomBios[Math.floor(Math.random()*randomBios.length)],
        "avatarIndex" : 0 ,
        "level" : 0,
        "totalSquarcuits" : 0,
        "totalWon" : 0,
        "totalLost" : 0
    } );

 If you mind hitting the DB each time, i'll tell you how but it's less elegant :)


I have some problems understanding your code.


The point is that with a new Facebook authentication the system will provide a different 'playerId' than the previous device registered user. So this will always fall into the 'else' code for a new player and it will insert the user normally.


It will fall in the 'if' code only when the player is not new, but in that case there would be nothing to update.

Am I wrong?


PS: Thanks for the Javascript syntax lesson.

That's were you are wrong, if the user is already authenticated (in your case by device id) and your game code calls FacebookConnectRequest GS will simply link the currently authenticated player to facebook then your cloud code will be called and you will be able to update the facebook info into playersList.


As for the JS code your welcome :)

but I made a small mistake:

var isFB = fbID != undefined; 

should have been 

var isFB = fbID !== undefined;



doc:

If the current player has previously created an account using either DeviceAuthenticationRequest or RegistrationRequest AND the Facebook user is not already registered with the game, the Facebook user will be linked to the current player.

But in the system collection the ID is different from the device registered user.


This is what I tried:

1- Registered with DeviceAuthenticationRequest a new player.

2- Connected to Facebook using FacebookConnectRequest from the device registered player.


This is what I have in the database:

- DEVICE ACCOUNT ID:   $oid: "595398e92d91abaf5d1644ef"

- FACEBOOK ACCOUNT ID: $oid: "59567e2038c31604f5e2b2b5"


They're different and there are two separate entries, only the field list is different...

Why shouldn't be one entry for both if they are linked? Or a field showing the link?

maybe related to the problem reported here

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



maybe doNotLinkToCurrentPlayer default is not false as specified in the doc, set it explicitly to false


I don't know


1 person likes this

I did set it explicitly to false and it still doesn't work. I think I'm going to submit a ticket for this.

What should be the correct behaviour? There should be two entries in the system collection, one for the device and one for Facebook, but they both should have the same external ID?

Answer

I sent a ticket to the support and we found out the problem was that I was deleting the players manually from the noSQL database when I should have used deletePlayer from the Cloud Code. The remedy was to delete all the entries in the externalAuthentication collection so that now when I connect Facebook, the account is merged and linked.


Now I can use your code, Christian. Thanks.

I did use your code but I think this code is correct *, because otherwise you would look only for those players who are already connected to Facebook.  And most of the times the users are trying to connect for the first time to Facebook from their Device Account.  

//Only fetching the customPlayer.facebookId to make it as ligthweight as possible
var customPlayer = Spark.runtimeCollection("playersList").findOne({"playerId":playerId}, {"isFacebookConnected": true);       // WRONG.

// CORRECT.
var customPlayer = Spark.runtimeCollection("playersList").findOne({"playerId":playerId});

   



Hi Andrea,


Happy to see that's its working fine now. 

As for the wrong code you misinterpreted the parameters, The second parameter of the findOne function is to specify the projected fields not the query.


so this code is correct:

var customPlayer = Spark.runtimeCollection("playersList").findOne({"playerId":playerId}, {"facebookId":true});


like I said in my comment, by specifying the projected field, mongodb will return an object with only two fields (oid and facebookId) instead of the full object. This is what we want because we only use customPlayer .facebookId in the code. But don't worry about that, it's an optimization that will maybe be usefull once you have 100000 users :)



Login to post a comment