Once the server side code was in place, I needed methods to download the current high score list and upload new entries in-game.
The basic code for connecting to the server and retrieving scores was provided by the unify community ‘Server Side Highscores’ article.
I added the method Md5Sum (also provided by the unify community) to encode the data before sending to the server.
Expanding on this code using the YouTube tutorial ‘[Unity Tutorial] Online Highscores 01 (dreamlo)‘ – Using IEnumerator when adding a new highscore or downloading the current highscore list provides a smoother in game experience for the player, since it allows the primary thread to manage the game, while the secondary threads manage the highscore table status.
The modified code was placed in a c# script called HighScoreController – Which I attached to an empty component also called HighScoreController.
Functionality within the HighScoreController script can be split into two fairly clear sections;
- Add New High Score.
- Download (format and store) current highscores list.
1. Add New High Score;
Adapting the method to add new highscores – Using IEnumerator to allow the code to run on a separate thread to the main game;
public static void AddNewHighScore(string userName, int score) { instance.StartCoroutine(instance.UploadNewHighscore(userName, score)); } // remember to use StartCoroutine when calling this function! IEnumerator UploadNewHighscore(string name, int score) { //This connects to a server side php script that will add the name and score to a MySQL DB. // Supply it with a string representing the players name and the players score. string hash = Md5Sum(name + score + secretKey); string post_url = addScoreURL + "name=" + WWW.EscapeURL(name) + "&score=" + score + "&hash=" + hash; // Post the URL to the site and create a download object to get the result. WWW hs_post = new WWW(post_url); yield return hs_post; // Wait until the download is done if (hs_post.error != null) { print("There was an error posting the high score: " + hs_post.error); } else { DownloadHighscores(); } }
With an associated method which encrypts highscores for sending (also provided by the Unify Community site);
public string Md5Sum(string strToEncrypt) { System.Text.UTF8Encoding ue = new System.Text.UTF8Encoding(); byte[] bytes = ue.GetBytes(strToEncrypt); // encrypt bytes System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] hashBytes = md5.ComputeHash(bytes); // Convert the encrypted bytes back to a string (base 16) string hashString = ""; for (int i = 0; i < hashBytes.Length; i++) { hashString += System.Convert.ToString(hashBytes[i], 16).PadLeft(2, '0'); } return hashString.PadLeft(32, '0'); }
2. Download (format and store) current highscores list;
Expanding on the Unify Community method to download highscores as a string from the server. As with the AddNewHighScore method, DownloadHighScores is also modified from the Unify Community code using IEnuerator to allow threaded functionality;
public void DownloadHighscores() { StartCoroutine("DownloadHighscoresFromDatabase"); } // Get the scores from the MySQL DB to display in a Text. // remember to use StartCoroutine when calling this function! IEnumerator DownloadHighscoresFromDatabase() { WWW hs_get = new WWW(highscoreURL); yield return hs_get; int counter = 0; for (; counter < hs_get.text.Length; counter++) if (hs_get.text[counter] == '#') break; string hs_got = hs_get.text.Substring(0, counter); //Substring(0, counter); if (hs_get.error != null) { print("There was an error getting the high score: " + hs_get.error); } else { FormatHighScores(hs_got); highScoreDisplay.OnHighScoresDownloaded(highScoresList); } }
Note: The highscore data is returned by 000webhost as a text string – When returning the data, 000webhost appends a little extra/unwanted info
http://stats.hosting24.com/count.php
This code is used by 000webhost to check site usage – Which is fair enough, since they provide the hosting for free – But is unneeded and unwanted by the game – I definitely dont want it getting mixed up with the highscore table.
My quick and dirty fix to this;
int counter = 0; for (; counter < hs_get.text.Length; counter++) if (hs_get.text[counter] == '#') break; string hs_got = hs_get.text.Substring(0, counter); //Substring(0, counter);
On the server, after creating the highscore list, I append a ‘#’ to the end of the string. A character I know isn’t used either in the highscores (it cant be entered when adding a highscore) or in 000webhost’s appended text. I loop through the highscore text, searching for the position of the hash character – Once found, the code removes it and any text which follows.
After DownloadHighscoresFromDatabase has retrieved the highscore text; it calls FormatHighScores which parses the names and scores from the text and stores them for use in game;
void FormatHighScores(string TextStream) { string[] entries = TextStream.Split(new char[] { '\n' }, System.StringSplitOptions.RemoveEmptyEntries); highScoresList = new HighScore[entries.Length]; for (int counter = 0; counter < entries.Length; counter++) { string[] entryInfo = entries[counter].Split(new char[] { '|' }); if (entryInfo.Length == 2) { //--- string userName = entryInfo[0]; int score = int.Parse(entryInfo[1]); highScoresList[counter] = new HighScore(userName, score); //--- } } //--- }
FormatHighScores populates a list of HighScore struct. This is used by the HighscoreDisplay script to populate the highscore table – And by the HighScoreAdd script to check if the new score should be counted as a new entry;
public struct HighScore { public string userName; public int score; public HighScore(string inUserName, int inScore) { userName = inUserName; score = inScore; } }
This provides a backbone in-game to manage highscores – But I still need methods to display current high score & add new highscores.
Grab a copy of the project here
Next post: 1.7d Highscores (Display)
Last post: 1.7b Highscores (In-Game Overview)
5 Replies to “Adventures in Unity – 1.7c Highscores (In-Game Backend)”