Game server list
BlitzMax Forums/BlitzMax Programming/Game server list
| ||
Does anyone have any example code that sets up a central server list, where you can add and remove servers like in the old Blitz3D gnet? |
| ||
import brl.gnet or a simple php based meta server to which you send http 1.1 requests, code for this should be available more than enough I think :) |
| ||
The BlitzMax gnet module has nothing to do with what I am asking. If code for this is so plentiful, why bother posting a response telling me you think it is 'available'? |
| ||
Well the method I use is to have a simple php script on a web server which each server can simply make requests to, to add and remove themselfs from the list (they also need to send requests every 50 seconds or so (this can be changed) otherwise they get removed from the list. This is almost exactly the same method that GNet uses, the only real difference is the following script is somewhat more expanded .<? // Master Server // Copyright 2008 Binary Phoenix // This script is pretty simple, it allows you to pass an argument to this file that // specifies what statistic you want. Normally this will be a request to get all // servers running for a given game. // MySql DB Structure; // // - servers (table) // - ID, int, auto_increment, primary key // - IP, tinytext // - Name, text // - TimeoutTimer, int // - GameName, text // Arguments; // // - action : This specifies the action to preform, it can be any of the following; // - listservers : This will cause the script to emit a list of currently // running servers. This must be used with the gameid argument // to specify what game the servers must be running. // - addserver : This will add the current ip to the server list. This must be // used with the gameid argument to specify what game the server is be running. // - removeserver : This will remove the current ip from the server list. // - refreshserver: Resets the servers timeout timer so that its not removed from // the server list. // // - gamename : This is used by several actions to decide what game the servers it // is dealing with should be running. // - servername : This is used when adding a server to the list. It just contains // a name based description of the server. // - ip : Returns the current ip address. // // Errors; // // The server can return certain error strings depending on the situation, what follows // is a list of them; // // - "error 1" : This is a mysql error. Its usually temporary. // - "error 2" : Argument missing. This occurs when the request url dosen't // contain an required argument. // This variable stores how long it takes for a server to timeout. $timeoutDelay = 60; // 1 minutes. // Connect to the database. $connection = mysql_connect("localhost", "InsertDataBaseUsername", "InsertDataBasePassword") or die("error 1"); mysql_select_db("InsertDataBaseName") or die("error 1"); // Make sure we have been given an action. if (isset($_GET['action'])) { // Process the action. switch ($_GET['action']) { case 'ip': die($_SERVER['REMOTE_ADDR']); break; case 'listservers': // Check correct arguments have been passed. if (!isset($_GET['gamename'])) die("error 2"); // Get required arguemnts and clean them up. $gamename = $_GET['gamename']; // Kill off any servers that haven't refreshed themselfs in a long time. mysql_query("DELETE FROM servers WHERE TimeoutTimer <= " . time()); // Grab server list. $result = mysql_query("SELECT * FROM servers WHERE GameName='" . mysql_escape_string($gamename) . "'"); if ($result) { // Emit all the servers. while ($row = mysql_fetch_assoc($result)) { echo $row['IP'] . '|' . $row['Name'] . "\n"; } } break; case 'addserver': // Check correct arguments have been passed. if (!isset($_GET['gamename'])) die("error 2"); if (!isset($_GET['servername'])) die("error 2"); // Get required arguemnts and clean them up. $gamename = $_GET['gamename']; $serverName = $_GET['servername']; // Remove any old servers with the same ip and name. mysql_query("DELETE FROM servers WHERE IP='" . mysql_escape_string($_SERVER['REMOTE_ADDR']) . "' and Name='" . mysql_escape_string($serverName) ."' and GameName='" . mysql_escape_string($gamename) . "'"); // Insert it into the database. mysql_query("INSERT INTO servers(IP, Name, TimeoutTimer, GameName) VALUES('" . mysql_escape_string($_SERVER['REMOTE_ADDR']) . "','" . mysql_escape_string($serverName) . "'," . (time() + $timeoutDelay) . ",'" . mysql_escape_string($gamename) . "')"); break; case 'removeserver': // Remove this server based on its ip. mysql_query("DELETE FROM servers WHERE IP='" . mysql_escape_string($_SERVER['REMOTE_ADDR']) . "'"); break; case 'refreshserver': // Refersh the servers timeout timer. mysql_query("UPDATE servers SET TimeoutTimer='" . (time() + $timeoutDelay) . "' WHERE IP='" . mysql_escape_string($_SERVER['REMOTE_ADDR']) . "'"); break; } } else { die("error 2"); } // Close database connection. mysql_close($connection); ?> Within blitzmax all you need to do to make requests to this script, is to include the brl.httpstream module and open a stream to the script using the correct parameters and read in the first line (which will be an error number if something has gone wrong). For example to add a server you would open a stream to; local stream:TStream = OpenStream("http::www.YourDomain.com/script.php?action=addserver&gamename=YourGameName&servername=YourServerName") local result:string = ReadLine(stream) CloseStream(stream) And so forth. Hope that helps. Not sure if the code will work I haven't tested it with blitz yet. |
| ||
Well, for my game I just coded a simple server, that game servers connect to and update information. If there is no more information in n seconds, the server is deleted from the list. Clients also connect to this server to request the list. If you know how networking works you can figure out the rest.. |
| ||
Well you asked for something simple, so why not use GNet. And the sources are really available like sand at a beach. Its one of the most common questions on BM and Blitz3D on how to do the communication between Blitz and PHP and a metaserver list shouldn't be a problem. the quakenet php - mysql tutorial already covers far more than you would need for that. |
| ||
Thank you we are looking at the code above. |
| ||
I was able to connect and add a server, but was unable to retrieve a list of servers. It just prints blank lines:Local stream:TStream stream=OpenStream("http::www.leadwerks.com/gameservers/game1.php?action=addserver&gamename=my_game&servername=my_server") If Not stream RuntimeError "ERROR" While Not stream.Eof() Print ReadLine(stream) Wend stream.close() stream=OpenStream("http::www.leadwerks.com/gameservers/game1.php?action=listservers&gamename=my_game") If Not stream RuntimeError "ERROR" While Not stream.Eof() Print ReadLine(stream) Wend stream.close() |
| ||
Try this http://www.blitzbasic.com/codearcs/codearcs.php?code=2208 to manage GET/POST on http streams.If http.Open("www.leadwerks.com") 'POST Example result$=http.Post("gameservers/game1.php",["action","gamename","servername"], ["addserver","my_game","my_server"] ) End If The 'logic' is (for POST method) http.Open (your MAIN domain = www.leadwerks.com) result = http.Post (path_of_your_page,[array_of_variables],[array_of_values]) I've tested and got the following result HTTP/1.1 200 OK Date: Sat, 13 Sep 2008 19:10:35 GMT Server: Apache Connection: close Content-Type: text/html error 2 This one for the GET method If http.Open("www.leadwerks.com") result$=http.Get("gameservers/game1.php?action=addserver&gamename=my_game&servername=my_server") end if HTTP/1.1 200 OK Date: Sat, 13 Sep 2008 19:20:15 GMT Server: Apache Connection: close Content-Type: text/html Process complete I dont' know if it is the result I should expect, but there is no error 404. |
| ||
I did not set up the table. OMG it werks! |
| ||
Ultimately all this does is retrieve a list of server IPs. Therefore it can be completely separate from whatever networking code you might use. My goal is to make a module that only adds, removes, refreshes, and retrieves a list of servers. Then it can be used with whatever networking system you want. This all works, but it opens a new stream each time an action is performed. This can take hundreds of milliseconds. Does anyone know how I can write to and from the stream to send new messages? I looked at BlitzHTTPGet but if I use more than one Get command it crashes: If http.Open("www.google.com") 'POST Example Print http.Post("/search", ["hl", "q", "btnG"] , ["en", "fantasaar", "Google Search"] ) Print http.Post("/search", ["hl", "q", "btnG"] , ["en", "fantasaar", "Google Search"] ) End If http.Close() If it takes 300 millisecs to refresh the server every minute, that is not usable. SuperStrict '========================================= 'test Local s$ Local servers$[] Local server:TPubServer server=TPubServer.Create("http::www.leadwerks.com/gameservers/game1.php","My_Server","My_Game") servers=TPubServer.list("http::www.leadwerks.com/gameservers/game1.php","My_Game") If servers For s=EachIn servers Print s Next EndIf '========================================= Type TPubServer Field url$ Field stream:TStream Method Delete() Remove() EndMethod Function Create:TPubServer(url$,servername$,gamename$="") Local stream:TStream Local server:TPubServer server=New TPubServer server.url=url server.stream=OpenStream(url+"?action=addserver&gamename="+gamename+"&servername="+servername) If Not server.stream Return Null While Not server.stream.Eof() If ReadLine(server.stream).Trim() server.stream.close() Return Null EndIf Wend Return server EndFunction Method Refresh:Int() stream=OpenStream(url+"?action=refreshserver") If Not stream Return False stream.close() Return True EndMethod Method Remove:Int() stream=OpenStream(url+"?action=removeserver") stream.close() stream=Null Return True EndMethod Function List:String[](url$,gamename$="") Local descarray:String[] Local list:TList Local stream:TStream Local s$,sarr$[],n:Int stream=OpenStream(url+"?action=listservers&gamename="+gamename) If Not stream Return Null list=New TList While Not stream.Eof() s=ReadLine(stream) If s.contains("|") list.addfirst(s) EndIf Wend stream.close() If list.IsEmpty() Return Null descarray=New String[list.count()] For s=EachIn list descarray[n]=s n:+1 Next Return descarray EndFunction EndType |
| ||
Sadly thats one of the problems with the method I suggested. Its never been much of a problem for me as small delays aren't really noticable in the games I've been using it for. However there are a few things I can think of off the top of my head that might help; - Remove Refresh Code Simplest and crudest method. Remove the refresh code, or reduce the timeout interval. Might cause problems with dead servers though. - Cron-Job Setup a cron-job on the computer hosting the master server script. Make the cron-job ping all game servers every few minutes and remove the servers that don't respond. This transfers all the connection delays onto the master server instead of the game. - Seperate Thread Most obvious one really. Put all the refrehs code on a seperate thread. Not sure how well BMax would handle this though with its lack of threading support. - Connection: Keep-Alive When requesting data from the server, send a keep-alive connection header with the HTTP request. Then send all requests down the same socket. This removes all the connection junk that slows everything down. |
| ||
Not sure how well BMax would handle this though with its lack of threading support. Hmmm... |
| ||
Yes I noticed the thread bmax topic just after posting this :). I'm rather out of date I'm afraid. |
| ||
Okay, here is my code: And an example of usage: The purpose of this code is to retrieve a list of available server IP addresses. So I see this as something that can be completely separate from networking commands, and this could be used with any networking lib. It would be more useful if the Refresh() method could be run on a separate thread, but I don't know enough about threading yet to do that. |