GameMaker Online Highscores

Appsurd

Member
Online Highscores in GameMaker Studio


GM version: GMStudio 2023.11
Target platform: ALL
Download: https://marketplace.gamemaker.io/assets/4205/online-highscores-example
Links: N/A
Latest change: 2024-02-09
Level: Advanced



Summary

This tutorial will explain how to create a highscore system for your game. You can send the scores to the server and you can show a top-10 highscore list in your game. If the player’s name is not ranked in the top 10, but the player is ranked somewhere lower, then the player’s rank and score will be displayed in the eleventh position. The player’s name can be given a different colour. Don't forget to check the directory and the secret key very carefully, because this is the most common source of errors!



Table of contents

Introduction
Chapter 1: Creating an account on Altervista
Chapter 2: Coding and setting up the database
Chapter 3: Setting up GameMaker Studio
Conclusion
Frequently Asked Questions
Changelog



Introduction

An online highscore system is a cool feature for almost every arcade game. Highscores make people competitive and keeps them closer to your game, since everyone wants to be ranked first. Since GameMaker Studio has no built-in functionality for online highscores, you have to program them yourself. This tutorial will try to explain carefully and with many intermediate steps how this could be done. The tutorial includes two important scripts and a sample project, which can be downloaded from the YoyoGames Marketplace for free. After finishing the tutorial, you can make your own highscore table, where the player's name is coloured differently so he/she can find its position easily. Also, if the player is not ranked in the top 10, the position of the player will be displayed below the top 10.

If you are looking for a tutorial with more features, please have a look at https://marketplace.gamemaker.io/assets/8926/online-highscores-premium.

This tutorial and all its assets are completely free; you are not required to give any credits to Appsurd. If you want to give credits, please refer to us as Appsurd. We appreciate it if you rate the sample project in the Marketplace and tell us if something can be improved. Thanks in advance and enjoy the tutorial!



Chapter 1: Creating an account on Altervista

In order to make the online highscores, you need to have a server with a database. Since I understand that not everyone has one, you may choose to create a free account on the website https://en.altervista.org/registration.php?action=create-hosting. Please note that creating this account is for free, and you do not need to buy a premium account. Also, please do not use a VPN while creating an account, as it might cause errors.

Sometimes, while creating an account, Altervista will notify you that "The plain Hosting service is not yet available in your country." This means that you were unable to create the database. Luckily, there is a solution for this. Instead, you can create a blog first, and then convert the blog into a website + database. Go to https://en.altervista.org/registration.php and register your account. You may need to wait several hours (up to 48 hours) before your account is validated. After your account has been activated, you need to login and you will see the Dashboard of your blog. In the left column, find “Settings” and look for “Convert to hosting”. See Figure 1 for more details.


Figure 1: The Dashboard of the blog. The settings menu is somewhere at the bottom of the list and the button “Convert to Altersite” or "Convert to hosting" is indicated by the orange frame.​


Then press “Convert to AlterSite” and click the “Go on” in the middle of the page. Then follow the instructions to convert your blog to a website with a database, since we need a website and a database (actually only the last one but they come together) and not a blog. Now we have succesfully created an account, so we can go to chapter 2 which will inform you what codes and settings you need!

It is not obligatory to use Altervista, but I strongly suggest you do. If you cannot use Altervista or you have your own domain, you need to apply a few changes, which are mentioned throughout the tutorial.

If you still encounter any technical problems while creating an account, try to Google your problem first. When you still haven’t been able to create one, you may always contact me directly via email or just leave a comment in this topic.



Chapter 2: Coding and setting up the database

After you’ve finished creating an account, it’s time to start coding. First go to the Dashboard. You should then see something like this:


Figure 2: The Dashboard of Altervista.


First we want to set up the PHP code. You do not need to know anything about PHP but it’s an advantage if you do. Click the “File Management” in the top orange frame. You should now see something like Figure 3. If you converted your Altervista account from a blog to a website + database, you need to delete all files first.


Figure 3: The “File management” screen. If this is not empty, delete all files first!​


Here create a new folder using the buttons in the orange frame, and give it the name of your game. Therefore I will use “OnlineHighscores” (it is recommend to use only letters and no spaces!) Now open the folder. You should now see something like Figure 4.


Figure 4: Inside the “OnlineHighscores” folder. Here you must create two PHP files: addscore.php and display.php.​


In the upper orange frame you see the map I’ve just created. It should of course display the name you just have chosen. Now select in the lower orange frame the PHP tag from the middle button. Give the PHP file an useful name, I will use addscore. I strongly suggest that you do the same, otherwise you might get weird errors in case you forget later on to change the file name to whatever name you had chosen.

For non-Altervista users, please remark that we are using php files, so please add the extension [/B].php[/B] manually.

Now the file opens. Copy and paste the following PHP code into it. You may try to understand what’s happening, but it’s not necessary.

Code:
<?
    // Connect to database
    $db = new PDO('mysql:host=localhost;dbname=my_tutorialappsurd', 'tutorialappsurd');

    // Check secret key, if correct, then insert name and score
    $secret_key = "1234";
    if($secret_key == $_POST['secret_key'])
    {
        // Prepare statement
        $sql = "INSERT INTO OnlineHighscores VALUES (NULL, :name, :score)"; // Change OnlineHighscores to your game name
        $stmt = $db->prepare($sql);
        $stmt->bindParam(':name', $name, PDO::PARAM_STR);
        $stmt->bindParam(':score', $score, PDO::PARAM_INT);

        // Get name and score from URL string
        $name = $_POST['name'];
        $score = $_POST['score'];

        // Execute statement
        $stmt->execute();
        echo '1';
    }
    else
    {
        echo '0';
    }
?>

In this script, at first a connection is ensured with the database. This is done using a PDO prepared statement, and not using the regular mysql_* functions as in older versions of this tutorial. This is done because to prevent parameter injection as discussed in the first comments below the tutorial (see https://forum.yoyogames.com/index.php?threads/online-highscores.4291/#post-34322). Please do not forget to change your “db_name” to “my_” and thereafter your login name. And the last argument should also be your login name, which in my case is tutorial_appsurd.

For non-Altervista users, you have to insert an additional parameter after ‘tutorialappsurd’, namely your password. You should have something like this:
Code:
$db = new PDO('mysql:host=localhost;dbname=my_tutorialappsurd', 'tutorialappsurd','mypassword');
To improve the security of your game a little, I added a secret key. Please create a completely random key (throughout the tutorial I will call this the secret key) consisting of letters and numbers only and change it with the one I use (which is 1234). Save this key somewhere, you will need it a couple of times throughout the tutorial.

Then the secret key is compared to the secret key on the server. Do not forget to change this value into the string/value you just chose! If this is correct, then the statement of inserting a new score into the database is prepared. Thereafter both the name and the score are connected to the prepared statement, such that the values are actually put into the database. At last the whole process is executed, and a value of “1” is returned to GameMaker: Studio if the process was successful.

I almost forgot to say that you need to change the table name in line 10 (which in my case is OnlineHighscores) to whatever you have chosen as a table name (I recommended you to choose your game’s name). Now we are done! Save the file, so it returns to the screen you saw earlier in Figure 4. You should now see the file you just created.

The previous script was created for submitting a new score, and we’ll also need one for displaying the top 10 scores. This is slightly more difficult, and again, you may try to understand the script but it’s quite difficult, so it's no problem if you don't completely understand it. Create a new PHP script as before and call it display.php. Then copy the following code into it.

Code:
<?
    // Connect to database
    $db = new PDO('mysql:host=localhost;dbname=my_tutorialappsurd', 'tutorialappsurd');

    // Check secret key, if correct, then get names and scores
    $has_found = 0;
    $secret_key = "1234";
    if($secret_key == $_POST['secret_key'])
    {
        // Get all data from the table, ordering from best to worst
        $sql = "SELECT * FROM OnlineHighscores ORDER BY score DESC";
        $stmt = $db->prepare($sql);
        $stmt->execute();

        // Fetch the result into a nice format EXAMPLE: 1. Guest2837 100
        // no_lines is the length of the list, generally you will want a top 10
        $line = 1;
        $no_lines = $_POST['no_lines'];
        while($row = $stmt->fetch(PDO::FETCH_ASSOC))
        {
            // We only want a top no_lines
            if($line <= $no_lines)
            {
                  // Check if you are in the top no_lines
                  if($row['name'] == $_POST['name'])
                  {
                        $has_found = 1;
                  }
                  // Echo the top no_lines list
                  echo $line . ".-" . $row['name'] . "-" . $row['score'] . "|";
                  $line += 1;
            }
            else
            {
                // When you are not in the top no_lines list, search for your record
                if($has_found == 0)
                {
                    if($row['name'] == $_POST['name'])
                    {
                        $has_found = 1;
                        echo $line . ".-" . $row['name'] . "-" . $row['score'] . "|";
                        break;
                    }
                    $line += 1;
                }
                else
                {
                    break;
                }
            }
        }
        // Send some empty lines if there are not enough scores
        if($line <= $no_lines)
        {
            for($i = $line; $i<=$no_lines; $i++)
            {
                echo $i . ".--|";
            }
        }
    }
?>

Just as in the previous script, at first a connection is made with the database. If you do not use Altervista, please add your password in the second line. After that, the secret key from the POST request is compared with the secret key on the server. If the two keys are the same, the statement for retrieving all scores is prepared. Now the tricky part starts.

Using a while loop, we are looping through all available scores, starting with the highest score. We always want to return a top-10, so the first if statement inside the loop guarantees that we at least get back 10 lines. However, when the player’s name is somewhere in the top 10, we don't have to search beyond the top 10, so the variable $has_found will be set to 1.

After the first ten loops, we want to check whether the player’s name has appeared in the top 10. If this was not the case, the program continues the loop to hopefully find a score of the player. After a score was found, the script also returns an eleventh row which contains the player’s highest rank and score.

Of course it’s possible that the database doesn’t contain 10 lines yet. The last if-statement ensures that the script always sends back 10 lines (such that it actually fills it up the highscore list with empty lines).

However, you still have to change the variables into the ones you use! First of all, change your secret key! Also change the database name and account name (which are both in one of the first lines) to the ones you have chosen! Finally change your table name in line 11 to the table name you have chosen, which is preferably the name of your game! Now save the script. You should now see the same as in Figure 4 before but now your two scripts are visible too.

Now it’s time to create a database. Go back to your Dashboard (see Figure 2) and click this time on the lower orange frame on “Access to PHPMyAdmin”. Now a new tab opens. In the left column, click “Add database”. Please make a distinction between a database (which Altervista allows you to have only one) and a table (which is inside a database, and you can have multiple of them).

It’s possible that the database my_tutorialappsurd is already there (or at least with your account name). If so, click my_tutorialappsurd. This database should be empty, so delete all tables (“drop”) if there are any. Finally your database should look like Figure 5.

In case you do not already have a database, create one in the left menu and call it my_tutorialappsurd in which the second part after “my_” should preferably be the name of your loginname. After that, open the database by clicking in the left menu on my_tutorialappsurd. There you find something like is shown in Figure 5.


Figure 5: The PHPMyAdmin environment. I have created a new table inside my database, which is called my_tutorialappsurd.​


Now enter a suitable name for your table, such as OnlineHighscores (preferably the name of your game). We will need three columns, so set the number of columns to 3. Then press “Go”. You should now see the following screen, see Figure 6.


Figure 6: Adding a new table to your database. For the creation of online highscores, only three rows are required: id, name and score.​


Go to the first row under “Name” and enter the word id. Leave the Type to INT. Fill at Length/Values the value 10 and check the checkmark in the one but last column called “A_I”. This ensures that each player in the list gets its own id and that scores will not be overwritten accidently.

Now continue on the second row and enter name under “Name” and choose VARCHAR as “Type” and fill in the value 100 in “Length/values”. This means that name is a string with a maximal length of 100 characters.

Lastly, enter in the third row under “Name” the word score. Again leave the “Type” to INT and enter the value 10 under “Length/values”. This means that score is a integer with a maximum value of 9,999,999,999. If you’ve done everything correctly, the scheme should look like the scheme in Figure 7.


Figure 7: After completing all steps, your table settings should look like this.​


In the down right corner, press Save to save your table. We are done now in Altervista! In the next chapter, we will get back to GameMaker Studio where we will setup the code.



Chapter 3: Setting up GameMaker Studio

After we have finished with Altervista, the difficult part is already behind us. I have already put everything together in a sample project, which can be downloaded from the Marketplace. Anyway, I will just continue setting up GameMaker Studio in case you want to code everything yourself.

Now open up GameMaker Studio and go to the object where you want to send in the player’s score. Preferably do this in a Mouse Pressed/Released Event, this prevents you from sending the score multiple times! Now create a script called server_send_score and put in the following code.

GML:
/// @function server_send_score(name, score)
/// @param {str}	name		The name of the player
/// @param {real}	score		The achieved score
///
/// @description	Sends the player’s score to the database in Altervista
/// @date			2024-02-09
/// @copyright		Appsurd

function server_send_score(_name, _score)
{
	// We need to encode the name so that it does not contain any forbidden characters
	var name = url_encode(base64_encode(string(_name)));
	
	// Perform the request to the server
	var address = "http://ftp.tutorialappsurd.altervista.org/OnlineHighscores/addscore.php";
	var args = "name="+name+"&score="+string(_score)+"&secret_key=1234";
	return http_post_string(address, args);
}
Please check very carefully if all variables are equal to the ones you entered in Altervista. If you followed all steps precisely, simply change tutorialappsurd to your account name and OnlineHighscores to your game name. Also check your chosen secret key, because if it’s different, then nothing will work! The only thing this script does, is sending the player’s score to the database in Altervista.

This script uses GameGeisha’s url_encode, which you can find here. It simply makes sure that “weird” characters are still send to the server without giving errors.

GML:
/// @function url_encode(str)
/// @param {str}	str		The string to encode
///
/// @description	Encode the string <str> in x-www-form-urlencoded format.
/// @date			2020-01-18
/// @copyright		GameGeisha (original), Appsurd (GMS 2 edit)

function url_encode(_str)
{
	var s, hex_digits, special_chars;
	s = "";
	hex_digits = "0123456789ABCDEF";
	special_chars = "$&+,/:;=?@ " + "\"" + "'<>#%{}|\\^~[]`!";
	
	//Main loop
	var i, l, c, o, escapes, escape_bytes;
	l = string_length(_str);
	for (i=1; i<=l; i+=1) {
		c = string_char_at(_str, i);
		o = ord(c);
		escapes = 0;
		//Single-byte characters
		if (o <= $7F) {
			if (string_pos(c, special_chars) != 0) || (o < 32) {
				escapes = 1;
				escape_bytes[0] = o;
			}
		}
		//2-byte characters
		else if (o <= $7FF) {
			escapes = 2;
			escape_bytes[0] = (o>>6)+192;
			escape_bytes[1] = (o&63)+128;
		}
		//3-byte characters
		else if (o <= $FFFF) {
			escapes = 3;
			escape_bytes[0] = (o>>12)+224;
			escape_bytes[1] = ((o>>6)&63)+128;
			escape_bytes[2] = (o&63)+128;
		}
		//Too long
		else {
			show_error("Invalid character.", true);
		}
		//Dump in escape characters, if any
		if (escapes == 0) {
			s += c;
		}
		else {
			var j;
			for (j=0; j<escapes; j+=1) {
				s += "%" + string_char_at(hex_digits, (escape_bytes[j]>>4)+1) + string_char_at(hex_digits, (escape_bytes[j]&15)+1);
			}
		}
	}

	//Done
	return s;

}

Perhaps you are wondering why I’m using base64_encode and url_encode. Normally, the username could consist of letters, numbers but also other strange characters. Since the server doesn’t like all types of input (and actually considers some characters to be ‘built-in functions’ such as the “&” sign) so therefore the script url_encode is used. Furthermore I’m using base64_encode. Since I want to show the highscores and eventually split up the highscores into different parts, I do need a variable to split to (perhaps you may recall from the PHP scripts that I’m using “|” and “–“ to split to). However, to prevent strange errors from happening, I want to ensure that the string doesn’t contain any other “|” or “-“ than the ones I want to split onto. Using base64_encode ensures this. If you are planning to use Altervista/PHP/Mysql for future projects, base64_encode might not be necessary in your case since you probably don’t need to split the string from the server. However, for this tutorial to work properly, it is vital to use it!

If you are a more experienced programmer, you might want to extend this script such that it checks using os_is_network_connected if the player’s connected to the internet. If not, you would have to call the script again after a few seconds. Normally, this almost never happens so I therefore chose not to implement it.

After creating the send script, we will also need a get script. Create a new script called server_get_scoresand put the following code into it.

GML:
/// @function server_get_scores(name, no_lines)
/// @param {str}	name		The name of the player
/// @param {real}	no_lines	The number of scores you want to display (generally 10 is fine)
///
/// @description	Get the highscore list from the database in Altervista
/// @date			2024-02-09
/// @copyright		Appsurd

function server_get_scores(_name, _no_lines)
{
	// We need to encode the name so that it does not contain any forbidden characters
	var name = url_encode(base64_encode(string(_name)));
	
	// Perform the request to the server
	var address = "http://ftp.tutorialappsurd.altervista.org/OnlineHighscores/display.php"
	var args = "name="+name+"&no_lines="+string(_no_lines)+"&secret_key=1234";
	return http_post_string(address, args);
}
Again, don’t forget to change the account name, folder name and secret key to the one you have chosen! Just to clarify, the value no_linesmeans nothing more than just showing that number of lines. Normally you want a top 10, so choosing 10 as input for no_lines is just fine. If you want, you can choose another number of course!

Now it’s time to create the highscores! For showing the actual highscores, it’s the easiest to create an object named obj_highscore. Enter the following codes into the right events in this object.

obj_highscore Create Event
GML:
/// @description  Initialise loading the online highscores
player_name = "Guest4033";
get_highscores = server_get_scores(player_name, 10);
text1 = "Please wait for the highscores to load...";
text2 = "";
alarm[1] = room_speed;
The variables text1, text2 and the alarm are used to check if the internet connection of the player is working properly. I could have used os_is_network_connected(), however, after testing this script in various occasions I felt that this was safer in use and actually handled the “not-having-internet” process better.

Of course the player_name I chose isn’t something you want to use in your game. You probably stored the player’s name as global.name so just remove the “Guest4033” and replace it with global.name, then you’ll be fine.

obj_highscore Alarm 1 Event
GML:
/// @description  When the scores haven’t loaded, try again once per second
if (text2 == "")
{
    get_highscores = server_get_scores(player_name, 10);
    text1 = "Please check your internet connection...";
    alarm[1] = room_speed;
}
obj_highscore HTTP Async Event
GML:
/// @description  Receiving the result from Altervista
if (ds_map_find_value(async_load, "id") == get_highscores)
{
    if (ds_map_find_value(async_load, "status") == 0)
    {
        text2 = string(ds_map_find_value(async_load, "result"));
        show_debug_message(text2);
        if (text2 == "IOException" or text2 == "")
        {
            text1 = "Please check your internet connection...";
            text2 = "";
        }
        else
        {
            text1 = "Ready";
            alarm[1] = -1;
        }
    }
}
obj_highscore Draw event
GML:
/// @description  Draw the highscores if available
draw_set_colour(c_black);
if (text1 == "Ready")
{
    draw_text_highscore(room_width/2-110, 50, "", "Name", "Score", string(text2), player_name, c_green);
}
else
{
    draw_text(room_width/2-110, 50, text1);
}
In these events, lots of if-statements are used to guarantee that the user actually has a working connection with the Internet. If not, the message “Please check your internet connection…” will be displayed.

In the last Draw code, you may of course change the x,y coordinates or choose different header names above the highscores. If you prefer not to give the player’s score a different colour, simply replace the c_green (which implies that in my example the player’s name and score will be displayed in green) to c_black, or whatever colour you prefer.

In order to display the table with the online highscores correctly, we will use a script called draw_text_highscore. Just create a script and call it draw_text_highscore and put the following text into the text field.

GML:
/// @function draw_text_highscore(x, y, text1, text2, text3, highscores, name, colour)
/// @param {real}	 x			draw x position
/// @param {real}	 y			draw y position
/// @param {str} text1			the text to display above the index
/// @param {str} text2			the text to display above the name
/// @param {str} text3			the text to display above the score
/// @param {str} highscores		the highscores
/// @param {str} name			the name to colour
/// @param {colour} colour		the colour to give to the name
///
/// @description	Draws a highscore with the player’s name coloured in a special colour
/// @date			2021-08-26
/// @copyright		Appsurd

function draw_text_highscore(_xx, _yy, _header_index, _header_name, _header_score, _highscores, _name, _colour)
{
	// Adjustable Parameters, if you need, you can change these values
	var max_la = 20;	// minimum width of the number column (1. 2. etc.)
	var max_lb = 100;	// minimum width of the name column
	var max_lc = 20;	// minimum width of the score column

	// Initialise the drawing by splitting up the text
	var default_colour = draw_get_colour();
	var no_lines = string_count("|", _highscores);
	var str2 = string_split(_highscores, "|", true);
	var str3,str3a,str3b,str3c;
	str3[0] = string(_header_index)+".-"+string(_header_name)+"-"+string(_header_score);
	for(var i=0; i<no_lines; i+=1)
	{
		str3[i+1] = str2[i];
	}

	// Splitting up the text into a part with the number (str3a), the name (str3b) and the score (str3c)
	// The output from the database is given by (Nr.-Name-Score)
	for(var i=0; i<no_lines+1; i+=1)
	{
		var str4 = string_split(str3[i], "-", false);
		str3a[i] = str4[0];
		str3b[i] = str4[1];
		str3c[i] = str4[2];
	
		// Decode the name so we can use it (but do not decode the header containing "name" since it's not encoded!)
		if (i != 0)
		{
			str3b[i] = base64_decode(str3b[i]);
		}
	
		// Assure that if a player has a \n in his name, then escape
		str3b[i] = string_replace_all(str3b[i], "\n", "\\n");
	
		// Adjust the width such that the text doesn't overlap
		max_la = max(string_width(str3a[i]), max_la);
		max_lb = max(string_width(str3b[i]), max_lb);
		max_lc = max(string_width(str3c[i]), max_lc);
	}
	str3a[0] = "";

	// The actual drawing of the highscores
	var height = 0;
	for(var i=0; i<no_lines+1; i+=1)
	{
		// Colour the player's data
		if (_name == str3b[i])
		{
			draw_set_colour(_colour);
		}
		else
		{
			draw_set_colour(default_colour);
		}
		
		// Draw the numbers (1. 2. etc)
		draw_set_halign(fa_right);
		draw_text(_xx+max_la+5, _yy+height, str3a[i]);
		
		// Draw the name + score
		draw_set_halign(fa_left);
		draw_text(_xx+max_la+10, _yy+height, str3b[i]);
		draw_text(_xx+max_la+10+max_lb+10, _yy+height, str3c[i]);
		
		// Increment height
		height += string_height(str3[i]);
	}
}

To see the scripts in action, I created a project which contains all the scripts as well as a nice example with the OnlineHighscores database I used in the tutorial. You can import the final project into GameMaker Studio, by downloading the example in the Marketplace: https://marketplace.gamemaker.io/assets/4205/online-highscores-example Unfortunately, due to some users abusing the example in old versions of the tutorial, the example does not work; you have to insert your own Altervista name and password.

Of course this asset is completely free and it’s advisable to download it and import the scripts server_send_score, server_get_scores, draw_text_highscore, url_encode each time you create a new project! Perhaps you also want to import the complete obj_highscore, at least I consider that convenient since all code is already in there.

If you want a more elaborate highscore system, for example where every player gets a unique ID to assign a highscore to one player only, you can visit the Marketplace to find the Online Highscore Premium Version tutorial: https://marketplace.gamemaker.io/assets/8926/online-highscores-premium

Just in case you forgot, you can do with it whatever you want, it’s completely free! Please do not sell the scripts or the tutorials, but you may edit it for your own purposes! If you want to give credits, please give credits to Appsurd.



Conclusion

The tutorial is finished by now, I hope you have learned how you can create your own online highscore system using the free online database Altervista and how you can implement this in GameMaker Studio. If there are any questions or if you find anything unclear, please post your response in the comments below. Thanks for reading the tutorial and have fun with your online highscores!



Frequently Asked Questions

I want more features
  • This tutorial is completely free and allows you to create a simple highscore system. For users who want to do more, you can go to the Marketplace to buy the Premium Version: https://marketplace.gamemaker.io/assets/8926/online-highscores-premium. With the premium version, I explain how to create a unique ID for each player and also how one can add more columns to the database. Please visit this link for more information.

HTML5 problems
  • All scripts and code should work on all platforms, except HTML5. I am not completely aware what the real problem is, but it’s due to connection problems between the server where your game is hosted and the Altervista server. You might solve your problems by placing the following line in ALL your PHP files at line 2 (just after the <?php ):
    Code:
    header('Access-Control-Allow-Origin: *');
    If this doesn’t solve your problem, I’m absolutely sorry but then I can’t help you out. If somebody has a solution for this, please post it in the comments so I can improve the tutorial!

Android problems
  • Sometimes, the communication on Android does not work whereas the communication on other platforms works fine. This was pointed out to me by Bastosz. A possible solution is to replace all connections to http by https, which is specifically a problem on Android P and above.

Altervista problems
  • Sometimes Altervista starts on the Italian version. If you simply login, the environment automatically switches back to English. If this doesn’t happen, Google probably has more good ideas on how to switch it back to English.
  • While creating your Altervista account, do not use a VPN, otherwise the receiving and sending of data might not work as expected. This was pointed out to me by Andrei.

Script shortcomings
  • The script is vulnerable for a replay attack, which is described in this commentary on the tutorial and I found the Wikipedia page about replay attacks also very helpful. FrostyCat, thanks for mentioning this. It appears to me that these kind of attacks are not really a problem for such simple highscore systems, and there is no simple method to prevent this. In the future, I might be improving this in the tutorial.

The GDPR
  • Some users have asked me about the GDPR (General Data Protection Regulation), a European law protecting the privacy of all European people. The law mainly exists for the protection of personal, online data. Although I’m not an expert on the topic, I would like to give you some advice. Never save any personal data, like real names, email addresses, home addresses, bank accounts, etc. If you bind to that rule, the GDPR is probably not a problem for you and this highscore system can be used without any problems. Again, I'm not an expert on the topic so please consult official sources for further information.


Changelog
V1.0.0 (2016-08-10)

First English version of the tutorial was written.

V1.1.0 (2016-09-24)

- Improved server communication (POST instead of GET, PDO Prepared statements instead of normal mysql_* functions and added url_encode)
- Improved support for other characters (by using url_encode and base64_encode the support of symbols like # was added)
- Improved explanation about creating Altervista databases & tables
- Improved explanation about draw_text_highscore
- Fix: text improvements
- Fix: HTTP Event: changed the status >=0 to status == 0
- Fix: display.php didn’t always return the right string when the number of available scores was lower than the number of requested ones

FrostyCat, thanks for helping out on the server communication!
GameGeisha, thanks for the wonderful script url_encode!

V1.1.1 (2016-10-01)

- Fix: Figure 7 showed the wrong numbers

V1.1.2 (2017-02-08)

- Fix: multiple spelling errors
- Small adjustments to example project

V1.1.3 (2018-07-21)
- PHP send script: removed ‘’ around score
- Changes some variable names into more ‘clear’ ones
- Fixed typo’s

V1.1.4 (2018-09-17)
- Thanks to BTS, added remark about adding password for non-Altervista users upon login

V1.1.5 (2018-10-21)
- Thanks to johnny-o, fixed a variable name in the tutorial

V1.1.6 (2019-07-31)
- Thanks to Bastosz, added a known issue

V1.1.7 (2019-09-17)
- Thanks to HayManMarc, a clearification was added for non-Altervista users

V1.1.8 (2020-01-08)
- Thanks to a user, added a clearification about using a VPN while creating your Altervista account

V1.2.0 (2020-01-18)
- Updated to GMS 2
- Various text improvements
- Various changes to the sample project

V1.2.3 (2020-01-28)
- Renamed hash to secret key
- Fixed minor spelling issues
- Added a new paid tutorial: Online Highscores Premium Version

V1.2.4 (2020-03-04)
- Clarified the Android http issue

V1.2.5 (2021-08-28)
- Update to GMS 2.3+

V1.2.6 (2022-08-06)
- Minor change in description Altervista setup (thanks to Dune Veteran)

V1.2.7 (2023-07-26)
- Removed string_split as it is implemented native in GameMaker now

V1.2.8 (2024-02-09)
- Fixed string_split issues
- Rename scr_send_score to server_send_score
- Rename scr_get_scores to server_get_scores
- Miscellaneous improvements
 
Last edited:

FrostyCat

Redemption Seeker
As a web developer, I have some serious questions to ask you about this tutorial.
  • Why are you using GET parameters to submit new entries? This opens the flood gates for XSS attacks using simple embedded URLs.
  • Why are you reusing the same access token? I can just sniff an outgoing request with F12 or Wireshark, then conduct a replay attack against you.
  • Why are you building query strings out of filthy user input? This is a classic vector for SQL injection, and mysql_real_escape_string() won't save you.
  • Why are you building request parameters out of unescaped user input? Not only would people entering fancy characters as names have issues with this, it can also allow clients to inject other parameters into the request.
  • Why are you checking ds_map_find_value(async_load, "status")>=0 without handling 0 and 1 separately? When the status is 1 for an in-progress request (can happen intermittently), there is no content to check.
I've had enough unteaching bad habits that Destron's students picked up from the old GMC, I hope I don't have to clean up after yours.
 

Appsurd

Member
FrostyCat, first of all, thanks for the extensive read through my tutorial. I really appreciate that you are pointing out improvements in the tutorial! I must admit that I'm not an expert in web developing, so I could have forgotten / not thought of several things, and therefore I'm happy you took the time to read it. I will now answer point by point.

  • Why are you using GET parameters to submit new entries? This opens the flood gates for XSS attacks using simple embedded URLs.
Interesting point, I must admit that using GET is not too handy. What would you suggest to change it into?
  • Why are you reusing the same access token? I can just sniff an outgoing request with F12 or Wireshark, then conduct a replay attack against you.
I agree, although I wouldn't know any safe and easy to implement method to use a different token every time which is known by both client and server. Perhaps you got an idea?
Oops, I really didn't know this. I'll look into it, thanks!
  • Why are you building request parameters out of unescaped user input? Not only would people entering fancy characters as names have issues with this, it can also allow clients to inject other parameters into the request.
Isn't this the same point as you are mentioning above? If not, please elaborate more on what you're trying to say.
  • Why are you checking ds_map_find_value(async_load, "status")>=0 without handling 0 and 1 separately? When the status is 1 for an in-progress request (can happen intermittently), there is no content to check.
That's a typing error, it should be == 0, thanks!
I've had enough unteaching bad habits that Destron's students picked up from the old GMC, I hope I don't have to clean up after yours.
I understand, and therefore I'm happy you expressed your concern with the online functionality. I'll be looking into ways for improvements in the near future, thanks in advance for answering this post!

----------------------------------------------------------------------------------------------------

Please note that I'm currently looking into the matter and I might be changing the content of this post.
 

FrostyCat

Redemption Seeker
Interesting point, I must admit that using GET is not too handy. What would you suggest to change it into?
Change it to POST, and put the parameters in URL encoded form as the second parameter in http_post_string(). That way embedded URLs alone can't inject parameters into the resulting request.
I agree, although I wouldn't know any safe and easy to implement method to use a different token every time which is known by both client and server. Perhaps you got an idea?
Use a web token generator. Here is one example.
Oops, I really didn't know this. I'll look into it, thanks!
Look no further than PDO prepared statements.
Isn't this the same point as you are mentioning above? If not, please elaborate more on what you're trying to say.
No, it's not. I'm talking about this line:
Code:
http_post_string("http://ftp.tutorialpelistar.altervista.org/OnlineHighscores/addscore.php?name="+string(argument0)+":&score="+string(argument1)+"&hash=1234","");
Let's say a player entered a name containing + symbols. + is syntactic sugar for spaces in URL encoding, so they would come out as spaces on the PHP side. This isn't wanted behaviour.

Let's say someone built off your tutorial and added one more parameter named message at the end, which also contains user input. A user can submit a message ending with &score=9999 to overwrite the score with 9999. This is what I mean by parameter injection.

You can use a script like this one to escape the individual inputs.
 
T

Tirous

Guest
Could you explain what the limits are for AlterVista?

Its just that i've never found a 'free' service that offers things like free web-host with php/sql support, without said service being littered in restrictions.

Neat tutorial, and while your code needs work(as FrostyCat has already explained), i must say i did learn something. :D
 
Last edited:

Appsurd

Member
Change it to POST, and put the parameters in URL encoded form as the second parameter in http_post_string(). That way embedded URLs alone can't inject parameters into the resulting request.
Sounds like a good idea. I'll look into it.
Use a web token generator. Here is one example.
I don't really get what the advantage is. Both the client and the server need to know the 'secret_server_key' right?
Look no further than PDO prepared statements.
Again a good idea. Never seen it actually, but I'll look into it.
No, it's not. I'm talking about this line:
Code:
http_post_string("http://ftp.tutorialpelistar.altervista.org/OnlineHighscores/addscore.php?name="+string(argument0)+":&score="+string(argument1)+"&hash=1234","");
Let's say a player entered a name containing + symbols. + is syntactic sugar for spaces in URL encoding, so they would come out as spaces on the PHP side. This isn't wanted behaviour.

Let's say someone built off your tutorial and added one more parameter named message at the end, which also contains user input. A user can submit a message ending with &score=9999 to overwrite the score with 9999. This is what I mean by parameter injection.

You can use a script like this one to escape the individual inputs.
Never thought about that actually. Thanks very much for mentioning all these things and I'll be updating the tutorial somewhere in the near future.

Could you explain what the limits are for AlterVista?

Its just that i've never found a 'free' service that offers things like free web-host with php/sql support, without said service being littered in restrictions.

Neat tutorial, and while your code needs work(as FrostyCat has already explained), i must say i did learn something. :D
The main advance for me is that Altervista is completely free, except when you try to use large files, database or much traffic. I appears from the Dashbaord that you have 1,000 MB space for files & database, which is (when you only use it for things like online highscores) more than enough. Furthermore, you can only have 30 GB Traffic, however, I'm not completely sure over which time span this holds. You can also build a website with it for free, as well as a blog and several other things which I never use :p So I hope you informed you well and I'm glad the tutorial actually learned you something ;)
 

Appsurd

Member
Use a web token generator. Here is one example.
FrostyCat, I do understand how it works but I don't understand why this is an advantage. Overall, the usuage of such a 'secret_key' isn't very safe I suppose. Or am I missing out on something?

You can use a script like this one to escape the individual inputs.
This script is working out fine, however, I would need a decoder in Game Maker to get the symbols back. Is there such a decoder and where can I find it?
 

FrostyCat

Redemption Seeker
FrostyCat, I do understand how it works but I don't understand why this is an advantage. Overall, the usuage of such a 'secret_key' isn't very safe I suppose. Or am I missing out on something?
Using tokens protects your server from replay attacks and similar forgeries based on editing past requests. As long as the actual secret key is known only to the server, it'll protect what the article claims to protect.

This script is working out fine, however, I would need a decoder in Game Maker to get the symbols back. Is there such a decoder and where can I find it?
The server shouldn't send information back in URL-encoded form, you won't need one if it's done properly.
 
C

ConsolCWBY

Guest
I liked the tutorial very much! Very informative, even if I never use it!
And FrostyCat has great points! I'd like to see them integrated into the tute!
Good job, guys! :)
 

Appsurd

Member
Using tokens protects your server from replay attacks and similar forgeries based on editing past requests. As long as the actual secret key is known only to the server, it'll protect what the article claims to protect.
Thanks for answering, I do understand the concept but for me it's hard to put it in practise. The article you attached doesn't really give me an extensive explanation how one should setup this. For example, the article isn't clear whether you may use the same user token more than once. Furthermore, basing the user token on the secret server key and the player id implies that the user token is always the same. This makes sure that replay attacks cannot be executed with another ID, but that it's perfectly possible with your own...

The server shouldn't send information back in URL-encoded form, you won't need one if it's done properly.
Ah, I thought the PHP script would simply submit the encoded string into the database, but it automagically puts it back in its original form. Thanks for answering :D

I liked the tutorial very much! Very informative, even if I never use it!
And FrostyCat has great points! I'd like to see them integrated into the tute!
Good job, guys! :)
Great to hear! As you might notice, I'm trying to fathom what exactly is going on and thereafter, I'll put it into this tutorial, so it could probably take another week or so before everything is completely arranged!
 

Appsurd

Member
Please note that we are working on the tutorial, so the example might be producing various strange bugs! This will be fixed asap!
 

FrostyCat

Redemption Seeker
Thanks for answering, I do understand the concept but for me it's hard to put it in practise. The article you attached doesn't really give me an extensive explanation how one should setup this. For example, the article isn't clear whether you may use the same user token more than once. Furthermore, basing the user token on the secret server key and the player id implies that the user token is always the same. This makes sure that replay attacks cannot be executed with another ID, but that it's perfectly possible with your own...
Sorry for not getting back to you sooner, I should have evaluated the solution better before suggesting it.

My take on this would be adding a URL that can be POSTed to to create session entries in the database, sort of like one-time temporary users. This can be just a table with single UUID column in it, for example. The response would be a token generated by the library based on the created session.

After the client requests a token and gets it, it holds onto the token until the time comes to submit a score. During submission, the token is provided with the request. Upon receiving a request, the server decodes the token and looks it up in the table for sessions. If it exists, it processes the submission request as usual, and the corresponding session entry would be deleted. If the client wants to submit another score, it would need to request a new token because the server has trashed the old one.

To stop your database from being populated with abandoned tokens, you can add a timestamp column to your sessions and use the MySQL scheduler or cron to regularly delete entries older than some specific threshold.

For the server to be accessible at all, something has to be replayable (i.e. known to the client before even starting the first request). It's a matter of making the replayable parts as useless on its own as possible.
 

Appsurd

Member
For the server to be accessible at all, something has to be replayable (i.e. known to the client before even starting the first request). It's a matter of making the replayable parts as useless on its own as possible.
So we are actually making it harder to execute a replay attack, but not impossible?

I was thinking, couldn't you something similar to this but just slightly different? Sort of, at the very first login, the user receives a token (the UUID for example). He then provides the token during the next request he does. After it has been verified that this token is correct, the task he send a request for is executed. And at the very end, the server returns a new token for an upcoming use. This ensures that nobody can interact as that player with the server. The downside is that if the player loses his token, he will never be able to login anymore.

And just a final question, this system feels like it's working only partially whereas is it quite some work and I am only creating a "simple" online highscores system with this, not a bank transfer communication channel :p So isn't this overkill ?
 
T

Tirashi

Guest
hello, sorry for my bad english but i will do my best :)
it does not work for me, i don't knom the problem. When i want to see the highscore it just show me name and score and that all. In OnlineHighscores I put two name and score but the game allways show me just name and score. Do you have any idea of where come from the problem?

Thank you :)

Edit: I did some mistake, now the only problem is that the game does not show the real score in the table, it shows 0 and we don't see the new name and the new score in the highscore when we send it

Edit 2: Sorry it was me who made lot of mistake xD everything is ok
 
Last edited by a moderator:

Appsurd

Member
Great. Thank you for sharing this
Thanks :) You're welcome!

hello, sorry for my bad english but i will do my best :)
it does not work for me, i don't knom the problem. When i want to see the highscore it just show me name and score and that all. In OnlineHighscores I put two name and score but the game allways show me just name and score. Do you have any idea of where come from the problem?

Thank you :)

Edit: I did some mistake, now the only problem is that the game does not show the real score in the table, it shows 0 and we don't see the new name and the new score in the highscore when we send it

Edit 2: Sorry it was me who made lot of mistake xD everything is ok
Alright, that's no problem. In case you have any more questions, just ask! Please note that I'm still updating the online-server-script (PHP part) so stay tuned for the update :)
 

danibus

Member
Hi there! First thanks for your post +PeliStart, it's for dummies :)
I will try this tutorial "as this", but later like to use my own machine to use it as server. How to do? I'm using W10 Pro and can't switch to linux... install apache server or something less professional?
Maybe phpmyadmin?
Someone tried?
 

Appsurd

Member
Thanks :) I aimed the tutorial at the target group of "dummies" so I hope it's clear to you :)
Unfortunately, I'm not an expert in running your own server, so perhaps you can ask this question in another section of this forum or perhaps even somewhere else as it's not really related to GM.
 

Appsurd

Member
Small bug: In "display.php" change this

Code:
echo $i . ". " . $row['name'] . " " . $row['score'] . "|" ;
with this

Code:
echo $i . ". " . $row['Name'] . " " . $row['score'] . "|" ;
To see players names when checking php from browser (not in GM)
This is not true. The columnname "name" is referring to the column you created in the database. Just look at Figure 7, it's definitely called "name" and not "Name"
 

Appsurd

Member
Changelog

V1.1.0 (2016-09-24)

- Improved server communication (POST instead of GET, PDO Prepared statements instead of normal mysql_* functions and added url_encode)
- Improved support for other characters (by using url_encode and base64_encode the support of symbols like # was added)
- Improved explanation about creating Altervista databases & tables
- Improved explanation about draw_text_highscore
- Fix: text improvements
- Fix: HTTP Event: changed the status >=0 to status == 0
- Fix: display.php didn’t always return the right string when the number of available scores was lower than the number of requested ones

FrostyCat, thanks for helping out on the server communication!
GameGeisha, thanks for the wonderful script url_encode!
 
Thank for your tutorial and work!

I have no problem to config this with "OVH" (other service type like Altervista).
I have a question, when i send a score it does not erase the previous one.. it's possible to attribute one ID (id corresponding to the same in database) per "save game file" ?

My english is very bad sorry, i have also a bad screenshot for example...lol
 

Attachments

Appsurd

Member
Thank for your tutorial and work!

I have no problem to config this with "OVH" (other service type like Altervista).
I have a question, when i send a score it does not erase the previous one.. it's possible to attribute one ID (id corresponding to the same in database) per "save game file" ?

My english is very bad sorry, i have also a bad screenshot for example...lol
Thank you very much for the compliment! Awesome that you got this working on another service! ;)

I completely understand your question, however, it will be a little harder to implement your idea compared to the scenario I explain in the tutorial. Let me try to give you some tips on how you could set this up.
  1. Since you would want an ID per "save game file" , the first time a user starts up the game, the game should ADD the player to the database with a score of 0. In the PHP script, simply add the user to the database. Then return the new player ID so you can save the player ID in-game.
  2. Whenever the player gets a new highscore, use the addscore.php as discussed in the tutorial. However, you should change it a little. You should of course send the player ID with the script to the server. Then in the PHP file, you need to change the INSERT statement into an UPDATE statement and use the old player ID with it to update the player's score.
  3. The display.php will almost remain the same, you only need to change the name for the player ID such that the script can check whether the player is ranked in the top-10 based on his ID.
  4. You would need to tweak the draw_text_highscore a little too, since the colouring of the text shouldn't be based on the player's name but on the player's ID.
Please notice that the downside of using this method is that you cannot get back your score after your savefile was deleted or the player bought a new device.

After following these steps you should be able to do this. I admit that these guidelines are really poor and without some true knowledge of PHP, this is going to be quite hard to implement. My latest tutorial on https://marketplace.yoyogames.com/assets/8926/online-highscores-premium explains this in detail, so you could consider buying my asset ;)
 
Last edited:
B

buda1234

Guest
Thank for your tutorial and work! Was very useful.
 
Last edited by a moderator:

Appsurd

Member
Thank for your tutorial and work!
I only had a problem sending the name and score, the database dint received the info. But if I write the info manually in the database and I can see the info in game studio.
I check multiples times the script in addscore.php specifically (dbname, login ,hash, table ) but i cant see anything wrong. Any idea maybe I had to give permission to write in somewhere or something like that?. Thanks
First of all, thanks for trying out the tutorial. :) It appears to me that your problem is not in the download part (since manually added scores are shown correctly by your game) so we should look at the uploading part. Just got a quick question for you to check where it might be going wrong.

Did you check the db name, account name and hash in send_score?

If those are correct, I wouldn't know where the problem is without looking at your code. You certainly do not need to enable anything (otherwise the showing the scores wouldn't be possible as well). In case you still experience problems, you may send your PHP files and GMS scripts to me using a PM (not in this topic please). In case you send a PM, please add your altervista account name, db name, table name and PHP file names with it too!
 
F

freshlycrackedgames

Guest
I had a bunch of errors here they are:
In Object obj_highscore, in Event DrawEvent action number 1 at line 3 : Cannot compare arguments
In Object obj_highscore, in Event CreateEvent action number 1 at line 4 : Cannot set a constant ("text") to a value
In Object obj_highscore, in Event ObjAlarm1 action number 1 at line 5 : Cannot set a constant ("text") to a value
In Object obj_highscore, in Event WebAsyncEvent action number 1 at line 10 : Cannot set a constant ("text") to a value
In Object obj_highscore, in Event WebAsyncEvent action number 1 at line 15 : Cannot set a constant ("text") to a value
Compile Failed - Please check the Compile window for any additional information

 
F

freshlycrackedgames

Guest
I had a bunch of errors here they are:
In Object obj_highscore, in Event DrawEvent action number 1 at line 3 : Cannot compare arguments
In Object obj_highscore, in Event CreateEvent action number 1 at line 4 : Cannot set a constant ("text") to a value
In Object obj_highscore, in Event ObjAlarm1 action number 1 at line 5 : Cannot set a constant ("text") to a value
In Object obj_highscore, in Event WebAsyncEvent action number 1 at line 10 : Cannot set a constant ("text") to a value
In Object obj_highscore, in Event WebAsyncEvent action number 1 at line 15 : Cannot set a constant ("text") to a value
Compile Failed - Please check the Compile window for any additional information

i have no idea how to use this comment system
 

Appsurd

Member
i have no idea how to use this comment system
First of all, thanks for trying out the tutorial! I do not quite understand what you mean with the above sentence, but from your other comment, it's clear to me that you have inside your project a constant named text. When using a constant, you cannot change it's content, simply because it is constant and therefore unchangeable. Actually, you are having a conflict error (since my example and your code use the same variable). In case you did not add that constant yourself to your project, do you have any other Marketplace assets / examples inside the same project? If so, those assets/examples could be having the constant text declared.

There are two possible solutions:
(1) remove the constant text from your code / downloaded assets or examples and replace it by another variable
(2) edit my example, so simply change all occurences of the variable text to something else, e.g. text1

Hope this helps, and if it doesn't, please come back to me so we'll try to fix it!
 
H

Harest

Guest
Seems like there were some interesting discussions to try to secure the leaderboard. The one-time token generated by the server would have indeed been quite useless in the actual situation. As long as it's obtained by the client in plain text, it's pretty easy to ask a token and simulate a new request to send any score you want.

There's two relatively easy things that can be done :
  • First one would be to use HTTPS. That way it would be slightly harder than just capturing the traffic with Wireshark like mentioned to get the datas exchanged between the client and the server.
  • Second : Using some symmetric encryption with the key & method in the game code and on the server, so it wouldn't be exchanged and would require to either decompile the game or read the RAM.
Then, the next level would be to be able to reproduce every input the player did on the server and see if the score sent is the same / probable. But there's no miracle anyway and it'll never be 100% secure. The goal is just to make it harder to cheat. It also depends on how far you want to make it hard
A nice QA related from StackExchange.

On a side note, all your images included are http images. It could be nice to upload them on a https images hoster to prevent mixed-content errors. I think you can simply upload them on the forum directly ? I guess Imgur is blocking GM since it's commercial.
 
Last edited by a moderator:

Appsurd

Member
Seems like there were some interesting discussions to try to secure the leaderboard. The one-time token generated by the server would have indeed been quite useless in the actual situation. As long as it's obtained by the client in plain text, it's pretty easy to ask a token and simulate a new request to send any score you want.
Exactly. That's why I decided not to include them in this (simple) tutorial.

  • First one would be to use HTTPS. That way it would be slightly harder than just capturing the traffic with Wireshark like mentioned to get the datas exchanged between the client and the server.
Good idea, unfortunately HTTPS isn't the standard right now (and especially if you want to try this out for free, this isn't possible because HTTPS simple costs money). So altough I agree, for now I'm just using the normal HTTP connections in this tutorial. I might however mention this explicitely in my tutorial, so I'll have a look where to put it in.

  • Second : Using some symetric encryption with the key & method in the game code and on the server, so it wouldn't be exchanged and would require to either decompile the game or read the RAM.
This is (quite) comparable to the hash system I'm using right now with the difference that I am sending the hash with the request and your method doesn't. So I agree it's safer, but other clients still have access to the exact same hash, so it would make it a little safer, but I think it's not a big step forward (unless you can convince me of course ;))

Then, the next level would be to be able to reproduce every input the player did on the server and see if the score sent is the same / probable. But there's no miracle anyway and it'll never be 100% secure. The goal is just to make it harder to cheat. It also depends on how far you want to make it hard
A nice QA related from StackExchange.
That's indeed a pain in the ass, since validating a player's score is tremendously difficult, especially if the cheating player knows what he's doing. The discussion on StackOverflow is a really interesting one, thanks for sending the link. After all, this is an intermediate tutorial about making your own highscores, so I assume most people who actually know (/are experienced) how to handle online data already know this so it doesn't feel necessary for me to include this in the tut.

On a side note, all your images included are http images. It could be nice to upload them on a https images hoster to prevent mixed-content errors. I think you can simply upload them on the forum directly ? I guess Imgur is blocking GM since it's commercial.
Oh really, I wasn't aware of the fact that uploading directly to the post was possible too. Thanks for pointing this out! :D

EDIT: Unfortunately Yoyo has a limit of only 5 pictures, so uploading isn't an option. Could you perhaps explain what the actual problem is right now? In all browsers I checked (desktop, laptop, mobile) the pictures are shown correctly....
 
Last edited:
H

Harest

Guest
Good idea, unfortunately HTTPS isn't the standard right now (and especially if you want to try this out for free, this isn't possible because HTTPS simple costs money). So altough I agree, for now I'm just using the normal HTTP connections in this tutorial. I might however mention this explicitely in my tutorial, so I'll have a look where to put it in.
In fact it's more and more the standard, recent article related. More than 50% of web traffic is now encrypted. About the cost of HTTPS, StartSSL was one of the free ssl certificates provider (and still is but there's some issues since WoSign acquiring). Thankfully now there's Let's Encrypt. But i don't know if there's some free hosting providers with PHP/SQL and HTTPS (TLS).

This is (quite) comparable to the hash system I'm using right now with the difference that I am sending the hash with the request and your method doesn't. So I agree it's safer, but other clients still have access to the exact same hash, so it would make it a little safer, but I think it's not a big step forward (unless you can convince me of course ;))
Not really comparable since you're encrypting all the datas and not just passing a key as an additional parameter. Depending on the implementation of your symmetric encryption, you could add some variation. Not an expert on that matter though, i wish i knew more. But like i said, both this and https are just "relatively easy" ways to make it safer. It's definitely not a big step forward as it'd require quite a lot more. It'll just push the skills required a little further as you'll need if you put both of these to be able to decrypt the HTTPS traffic and decompile the game or read the RAM to find how the symmetric encryption is working and the key (the key being only a part of the encryption).

EDIT: Unfortunately Yoyo has a limit of only 5 pictures, so uploading isn't an option. Could you perhaps explain what the actual problem is right now? In all browsers I checked (desktop, laptop, mobile) the pictures are shown correctly....
It was just a note. In fact for an unknown reason at first the images weren't loading at all before, they're since. Too bad there's this classic 5 images / forum post limit ^^.
 
Last edited by a moderator:

Appsurd

Member
In fact it's more and more the standard, recent article related. More than 50% of web traffic is now encrypted. About the cost of HTTPS, StartSSL was one of the free ssl certificates provider (and still is but there's some issues since WoSign acquiring). Thankfully now there's Let's Encrypt. But i don't know if there's some free hosting providers with PHP/SQL and HTTPS (TLS).
And I'm glad it is. Most websites use login systems etc. so HTTPS is vital to use. I prefer to keep this tutorial simple, so I'm not going to add anything on using HTTPS but when you're trying to make a more advanced program, it's definitely a good idea to look into.

Not really comparable since you're encrypting all the datas and not just passing a key as an additional parameter. Depending on the implementation of your symetric encryption, you could add some variation. Not an expert on that matter though, i wish i knew more.
Agreed. I might change this in the tutorial, but I'm unsure how to encrypt text using a hash/key in GameMaker. Any ideas?

It was just a note. In fact for an unknown reason at first the images weren't loading at all before, they're since. Too bad there's this classic 5 images / forum post limit ^^.
Yea, Yoyo, please fix :D
 
H

Harest

Guest
I'm still quite new to GM, and i never really dig symmetric encryption so i can't tell you which algorithm would be optimal here in term of implementation ease / efficiency. When i looked at ds_map_secure_save/load to find the "encryption" (spoiler : it's simple base64 encoding), i found this post with an implementation of the XOR cypher (in the update part) which is one of the easiest to implement i guess. Otherwise cf. the Wikipedia page on symmetric encryption, there're plenty algorithms to use (non exhaustive list and some may be deprecated) :
Examples of popular symmetric algorithms include Twofish, Serpent, AES (Rijndael), Blowfish, CAST5, Kuznyechik, RC4, 3DES, Skipjack, Safer+/++ (Bluetooth), and IDEA
But like you said, maybe you should keep this tutorial simple while maybe noting the options anyone could use to improve it a little further. For instance, if someone can have their hosting with HTTPS, there's only one letter to change in the code i think, by adding a s after http when you post your datas :p.
 
Last edited by a moderator:

gnysek

Member
To solve HTML5 issue, you need to create PHP file on same server as game is, and send score there. However, this file may just "forward" data with CURL or file_get_contents, so database and entry script may be still on another server.
You can also try to open link in new window instead of AJAX, and then display "thanks for submitting score" text (after redirect, so you don't see URL and don't resubmit score).
 
N

N8Games

Guest
Hi, PeliStar.

First I wanted to say thank you for posting this tutorial and the extension on the marketplace. Helps a noob like myself when more experienced GM:S programmers share their knowledge in this way.

I have a question: Is this supposed to work in the Game Maker player as well as in an exicutable file? I've been trying to implement this into my own project and even created a project from scratch using your extension and for some reason it's not writing to the database. Wasn't sure if this is a known issue. I've double & tripple checked my server & database settings for AlterVista both in the GM:S scripts and the pho files on server.

Thank you in advanced for any insight anyone might provide.

Edit: Figured it out. In the example URL it has "http://ftp.tutorialpelistar.altervista.org/OnlineHighscores/addscore.php"

Once I removed the ftp. At the beginning it worked.
 
Last edited by a moderator:

Appsurd

Member
To solve HTML5 issue, you need to create PHP file on same server as game is, and send score there. However, this file may just "forward" data with CURL or file_get_contents, so database and entry script may be still on another server.
You can also try to open link in new window instead of AJAX, and then display "thanks for submitting score" text (after redirect, so you don't see URL and don't resubmit score).
Creating the PHP file on the same server as you host the game is certainly a solution, however, I think most users starting with online functionality do not know how to use the internal database on their website, so I therefore did not include this in the tutorial. Moreover, I personally think that HTML5 is more difficult than most other platforms due to its limitations. So I assume most HTML5 devs know how to do this themselves. But it's nevertheless a very useful comment for devs reading this topic!

About the second solution you proposed, I don't quite understand you... Could you please explain it in more detail? :)

Hi, PeliStar.

First I wanted to say thank you for posting this tutorial and the extension on the marketplace. Helps a noob like myself when more experienced GM:S programmers share their knowledge in this way.

I have a question: Is this supposed to work in the Game Maker player as well as in an exicutable file? I've been trying to implement this into my own project and even created a project from scratch using your extension and for some reason it's not writing to the database. Wasn't sure if this is a known issue. I've double & tripple checked my server & database settings for AlterVista both in the GM:S scripts and the pho files on server.

Thank you in advanced for any insight anyone might provide.

Edit: Figured it out. In the example URL it has "http://ftp.tutorialpelistar.altervista.org/OnlineHighscores/addscore.php"

Once I removed the ftp. At the beginning it worked.
You're welcome, it's great people are learning from the tutorial, because that's what it was created for :)

Of course this tutorial/codes should be working on any platform or so, so it's not possible you should be experiencing any troubles. Not having access to ftp means your firewall is trying to block it. Altough I must admit I do not know myself what the precise advantage is of using FTP instead of leaving it out (just as you did) but I can remember Altervista advising me some day to start using it, and therefore I am. So is there anyone around knowing more about FTP and the follow up question: should you be using it for this application (online highscores) or not? Thanks in advance!
 
P

PatrikPé

Guest
Thanks for this tutorial, works very well :)

I have a question - is it possible to highlight only the current line with score player just sent?
I mean, right after the game my highscore table will appear and I want only the most recent score to be drawn with different color.
 

Appsurd

Member
Thanks for this tutorial, works very well :)

I have a question - is it possible to highlight only the current line with score player just sent?
I mean, right after the game my highscore table will appear and I want only the most recent score to be drawn with different color.
Thank you very much!

Your question is slightly difficult, since it requires to make a distinction between the last score of the player and all other scores.

1. A possible solution could be to create an extra column in the database and put down something which indicates the date / time when the score was sent in.
2. Then in display.php you can change the search algorithm to find the latest score by the given player name (since you need to put this score in the eleventh position, but if you don't then skip this step).
3. Also change the display script to return the time of each value in the highscores
4. Go to GameMaker: Studio and open the draw_text_highscore to change the colouring mechanism and colour the player's latest score.

I understand this step-by-step procedure is very vague and I'm myself not sure how you could handle this precisely. In case you have any further questions don't hesistate to ask them here, but I can't promise to give you cut-and-clear code since your problem is rather difficult.
 

FrostyCat

Redemption Seeker
Your question is slightly difficult, since it requires to make a distinction between the last score of the player and all other scores.
How is this even remotely difficult? Getting back the last inserted row is one of the most routine and basic tasks in SQL.

You could have used $db->lastInsertId() in the submission PHP script to get the ID of the inserted score entry, then responded with that to the client upon success. Then in the high score listing PHP script, include the ID on each entry at the top. Then the client can look through the listing for self-initiated submissions (i.e. IDs received from past responses for submissions) and draw them differently if they appear.

I really suggest that you put off teaching this subject until you have a more reasonable grasp of basic procedures.
 
Top