Generating Codes for Joining Challenges

Like Kahoot sometimes you want your friends to join your game through an easy to remember code. Players enter a code and the system finds the game their friend has created and adds them to it.

This tutorial shows you how to meet this sort of use case in GameSparks:

Here's the steps we'll follow:

  1. Create a runtime collection to save references to the generated codes, which Challenges they are linked to, and the time we created them (in miliseconds).
  2. Customize the CreateChallengeResponse Cloud code script.
  3. Create an Event that uses the generated code to search for games and join them if a game exists.
  4. Set up a way to remove used codes so future games can use them.

Important! If you're working on a new game that was created after the Game Data Service was launched in January 2018, you won't be able to create new Mongo Runtime collections and the Cloud Code used in the tutorial will not work. For the alternative tutorial for new games using the Game Data Service, see Generating Codes for Joining Challenges Using Game Data Service.

Creating a Runtime Collection.

This step is easy - simply create a runtime collection. We've called it challengeCodeCollection and you'll see that we make references to it in Cloud Code.

How to Create Runtime Collections? See this tutorial for details on how to create a runtime collection.

Customizing the CreateChallengeResponse Script

Our first task is to attach a customized Cloud Code script for the CreateChallengeResponse.

The reason we attach this code to the challenge creation response is because when the player has successfully submitted a CreateChallengeRequest, they receive a valid challengeInstanceId in the response. This is therefore a good place to verify that the player has a valid Challenge. We can then save the id, the generated code for the Challenge, and the timestamp in our Challenge and code runtime collection.

1. In the portal, go to the Configurator>Cloud Code page.

2. In the Scripts panel, select Responses>CreateChallengeResponse. The Cloud Code editor opens.

3. Add the following code:

//We check if the response has a valid challengeInstanceId to carry on the sequence
if(Spark.getData().challengeInstanceId !== null){

    //Load runtime collection where we save the code and reference to challenges
    var challengeCollection = Spark.runtimeCollection("challengeCodeCollection");

    //Get the challenge instance id generated
    var challengeID = Spark.getData().challengeInstanceId;

    //Generate random code of 000-000 format
    var code = randomCode();

    //If we did not get a valid code after 1000 attempts then force an error
    if(code === null){
        Spark.setScriptError("error", "NO VALID CODE CAN BE GENERATED")
    } else{
        var date = new Date();
        //Create new entry in collection for players to search and join
        challengeCollection.insert({"_id":{"$oid":challengeID},"code": code,"creationTime":date.getTime()})
        //Return the code to the player
        Spark.setScriptData("code", code);
    }

}

//Function to create number
function randomCode(){
    //Create a code, if this code is not valid (used already) keep trying for 1000 times, if none are valid, return null to be used to create an error message back
    for(var i = 0; i < 1000; i++){
        //Generate two 3 character long ints
        var firstThree = ("00" + Math.floor(Math.random() * 1000).toString()).slice(-3);
        var secondThree = ("00" + Math.floor(Math.random() * 1000).toString()).slice(-3);

        //Combine ints to form game search code
        var codeGen = firstThree + "-" + secondThree;

        //Is there any other game using this code right now?
        var potentialMatch = challengeCollection.findOne({"code": codeGen});

        //If not, break while loop by returning code
        if(potentialMatch === null){
            return codeGen;
        }
        if(i >= 999){
            return null;
        }
    }
}

Join Event

Because our players don't know the challengeInstanceId, the JoinChallengeRequest is not an immediate and viable way for players to join the Challenge. Instead, we need to create a custom Event that uses the generated code to:

1. Create an Event and add a single string Attribute and call it code.

2. Go to Configurator>Cloud Code and in the Scripts select the new Event under Events. The Cloud Code editor opens.

3. Add the following Cloud Code to the Event:

//Get code from input
var code = Spark.getData().code

//Find game
var challengeOBJ = Spark.runtimeCollection("challengeCodeCollection").findOne({"code": code},{_id : 1});
var challengeID = challengeOBJ._id.$oid;

//If game does not exist, return error
if(challengeID === null){
    Spark.setScriptError("error", "NO GAME CAN BE FOUND")
}
//If game exists, join it and return response as scriptData
else{
    //Create a join challenge request via code
    var joinRequest = new SparkRequests.JoinChallengeRequest();

    //Set the id``  ` of the challenge we wish to join
    joinRequest.challengeInstanceId = challengeID;

    //The sending happen here at .send()
    var joinResponse = joinRequest.Send()

    //If error is null or unidentified return the result of the request otherwise return the error
    if(joinResponse.error == null){
        Spark.setScriptData("joined", joinResponse.joined);    
    } else{
        Spark.setScriptError("error", joinResponse.error)
    }

}

Removing Old Entries for Re-Use

We want to remove old Challenge codes and make them available for re-use in new games. This can be done in a few ways:

You can combine both methods if you wish.

Method A

In this example of this method, we remove Challenge codes every day.

1. Go to Configurator>Cloud Code.

2. On the Scripts panel, select System>Every Day.

3. Add the following Cloud Code to the GS_DAILY script:

//Load our challenge and code collection
var challengeCollection = Spark.runtimeCollection("challengeCodeCollection");
//Create a date stamp
var date = new Date();
//Time stamp 24 hours ago by substracting the miliseconds equal to 24 hours
var timestamp = date.getTime() - 86400000;

//Remove any entry that has a creation timestamp of less than the timestamp we set above
//$lt is the 'less than' operator
challengeCollection.remove({"creationTime": { $lt: timeStamp }})

Method B

1. Go to Configurator>Cloud Code.

2. On the Scripts panel, select Global Messages>ChallengeWonMessage or GlobalMessage>ChallengeLostMessage:

3. Open a second tab and select GlobalMessage>ChallengeDrawnMessage:

4. Add the following Cloud Code to both the Won/Lost and Drawn messages:

//Get challenge instance id
var challengeID = Spark.getData().challenge.challengeId;
//Load collection
var challengeCollection = Spark.runtimeCollection("challengeCodeCollection");

//Remove code entry for this challenge to be re-used
challengeCollection.remove({"_id":{"$oid":challengeID}})

Removing Code for Expired or Withdrawn Challenges

If our Challenge is terminated for any reason before starting, we want to remove any reference of it and recycle the code generated for it:

This will ensure that if the Challenge is expired or withdrawn, we make the code available for re-use. It's important to leave the code in the Global version of the message because we only want to run it once. The Global version is the server version of the call that only executes once.

Did this page help you? Please enter your feedback below. For questions about using this part of the platform, please contact support here