Online High Score Table

Blitz3D Forums/Blitz3D Beginners Area/Online High Score Table

alloidgames(Posted 2006) [#1]
In a simple game of mine, I created a high score table that included both one's personal high scores and high scores posted up on a website. On the website, the scores are kept in a simple text file. I used the following code to bring the scores down from the site and put them in arrays:


tcp = OpenTCPStream("www.alloidgames.com",80)
If tcp Then
WriteLine tcp,"GET http://www.alloidgames.com/raingamehs.txt"
WriteLine tcp,Chr$(10)
If Not Eof(tcp) Then
While Not Eof(tcp)
For i = 1 To 10
olscore(i) = ReadLine(tcp)
olname$(i) = ReadLine$(tcp)
ollevel(i) = ReadLine(tcp)
Next
Wend
End If
CloseTCPStream tcp
End If


So far, I've only been able to figure out how to get high scores going one way. Is there any way, after comparing the recent score to the lowest high score from online (olscore(10)), to have the game send the score up to the text file or to the site? The goal would be for players to post their own scores on the site automatically, without allowing them to alter their scores. If this is not directly possible, what are some other ways to possible communicate the score information? Could I have the game send an e-mail automatically with the score in it, without allowing the player to edit the e-mail?


jfk EO-11110(Posted 2006) [#2]
You could use GET to send the users score as a part of the URL, eg:
GET www.alloidgames.com/raingamehs.php?user=joe&score=12345"

But useing GET allows the user to edit this and send it manually over the Adresslin ef a browser.

You can use POST instead of GET (see code archives), but basicly the best protection against cheating is to encrypt the data and/or add some kind of checksum, so invalid data will be rejected. If you do this, you may use GET without any risk.

I would strongly suggest to use a php script that will read the users score and name, compare it to the list and add his score to the list if required, then return the updated list to the user in text format. This is really very simple when you know the basics of PHP and MySql, assuming your server supports PHP and MySql. You may use a simple textfile instead of the Database MySql to store the list, but MySql offers very simple sorting functions, so all you have to do is reading the database sorted by the size of the score field.

However, using a checksum to validate the score must be done in a way that is not known by the public. Example:

a=12345 ; the score!

b$=a
checksum=0
for i=1 to len(b$)
checksum=(checksum+floor(mid$(b$,i,1))*1234) and $FFFF
next

c$=user$+"."+b$+"."+checksum

c$ will then be sent to the server, as GET parameter.

now the php script will extract username, the score and the checksum. It will then create its own checksum from the received score (using the same code, but in php). If the received checksum and the instantly created checksum are the same, the score is valid and legal. If they differ, it's a cheater and you may send a string like "you lousy cheater! your harddrive will be formated in 3 seconds, byebye!"


alloidgames(Posted 2006) [#3]
Thanks for the reply!

I think I understand your concept for the checksum and what the pages need to do, but I have no clue how to implement it. So I would send the URL containing the info (name,score,level,checksum), and they are basically variables and values included in the URL, which the PHP script can than read and interpret? How does the PHP script read the variables in the URL?

My server does support PHP and MySql, but I have absolutely no experience in either. I'd rather use a textfile to store the info as I've already got a sorting algorithm within the program so the order doesn't really matter in the textfile (in fact, every score could be posted and the sorter only shows the top ten, so I don't have to worry about comparing a posted score to the high scores list and deleting the lowest high score, etc. It could just add every new score to the bottom of the text file, and I'd occaisionally just clean it out).


Yan(Posted 2006) [#4]
Have a look in the code archives, I'm pretty sure there's a solution for B3D in there somewhere and I believe it includes the PHP script too.

[edit]
Hmm...I just had a look but couldn't find it. Perhaps it was just posted on the forum then, which is a bummer as it'd be long gone by now (this was a couple of years ago). :o(

You could have a go at converting this to B3d.
[/edit]


t3K|Mac(Posted 2006) [#5]
What about using ETNA - Lib?


alloidgames(Posted 2006) [#6]
Ok, so I got all the PHP stuff going. It's really simple, and it works like a charm. The only problem I've got left (and I have a feeling it has a really simple answer) is that I need the Blitz program to access the webpage "www.alloidgames.com/raingame.php?" + senddata$

(within senddata$ is all the info).

The PHP program just takes senddata$ and puts it in a textfile.

I've tried WriteLine stream,"GET www.alloidgames.com/raingame.php?" + senddata$, but all that ends up in my textfile is that little annoying unreadable square. If I access the page directly on my browser, substituting something in for senddata$, it appears correctly in the textfile. How can I get the program itself to access that?


jfk EO-11110(Posted 2006) [#7]
are you sure senddata$ is set correctly? did you print it to the screen to monitor it?
you may also try to use brackets:
WriteLine stream,("GET www.alloidgames.com/raingame.php?" + senddata$)

But in theory this should work also without the brackets.


alloidgames(Posted 2006) [#8]
Yes, senddata$ is correct all the way through (I think, at least everywhere I've checked it). Here's a snippit, with senddata$ changed just to send$:

Text width / 2, height / 2 + 150, "You got an online high score!!!!", True,True
Locate width / 2 - 40, height / 2 + 180
sendingname$ = Input("What is your name?")
send$ = "|" + Str(Int(score#)) + "|" + sendingname$ + "|" + Str(level)
Print send$
tcp = OpenTCPStream("www.alloidgames.com",80)
If tcp Then
WriteLine tcp,"GET http://www.alloidgames.com/raingamehs.php?" + send$
WriteLine tcp,Chr$(10)
EndIf
CloseTCPStream tcp



My PHP code looks like this:


<?php
$newString = $_GET['info'];
$fp = fopen( "raingamehs.txt" , "a+" );
fwrite( $fp, $newString );
fclose($fp)
?>


t3K|Mac(Posted 2006) [#9]
ETNA is IDEAL for this - and it's free! Why bother with own code when you have a great solution at your fingertips?


GfK(Posted 2006) [#10]
ETNA is IDEAL for this - and it's free! Why bother with own code when you have a great solution at your fingertips?
Because believe it or not, some people write code for personal enjoyment and a sense of achievement - which you simply do not get by using other people's code.


t3K|Mac(Posted 2006) [#11]
thats just like re-inventing the wheel...


Yan(Posted 2006) [#12]
Try something like this...
name$ = Input("Enter name : ")

send$ = "|" + Rand(1000) + "|" + name$ + "|" + Rand(10)
send$ = Replace(send$, " ", "_")
Print send$

tcp = OpenTCPStream("alloidgames.com", 80)

If tcp Then
	WriteLine tcp, "GET /raingamehs.php?info=" + send$ + " HTTP/1.0"
	WriteLine tcp, "HOST: alloidgames.com"
	WriteLine tcp, ""
EndIf

CloseTCPStream tcp
Bear in mind that this is extremely insecure.


RepeatUntil(Posted 2006) [#13]
Alloidgames, of course it's nice to do things by yourself, but you might consider using the ETNA library as t3K|Mac mentionned.
Advantage of ETNA:
- uses thread, so it's not slowing down your program (you can even use it in your main loop if you wish)
- uses encryption (coming soon!), so that nobody can cheat and add a very high score

ETNA comes with an example for a high score on a web site (with php). See my sig if you are interested...


alloidgames(Posted 2006) [#14]
Hey, thanks guys for the replies.

Hamish, your code works great! (You've got an extra little apostraphe after the send$ = Replace(... line, but otherwise its perfect.) You're right, it is really insecure, so I'll add a checksum as jfk suggested.

I checked out ETNA and it seems extremely useful; I'll definetely check into it on later games, but I'll leave this one as it is for now.

Thanks!


Yan(Posted 2006) [#15]
Hmm...I've no idea how that apostrophe got there. 8o/


jfk EO-11110(Posted 2006) [#16]
BTW, apropos checksums: when you use "AND $FFFF" for the checksum, like in my example, you have to realize that the checksum will never be higher than 65535. This means, a hacker could brute force the right checksum with a max of 65535 attempts. If your server has no automatic recognition of brute force attacks or dos attacks, this will take only a while for the hacker.

Using a 32 Bit checksum (and $FFFFFFFF) will make it much harder for the cheater, since it allows 4 billion possible checksums. But in that case you should also use a higher multiplier than 1234 for the digits, eg. 12345678.

That said, since the checksum code is not pubic, the hacker won't know if it's 16 bit or 32 bit. You may also use an uncommon checksum, like a 25 bit checksum:

checksum = checksum AND %1111111111111111111111111