|  | # Intrafoundation Software ### Home Software Forums News FAQ Galleries Web Design About Us Contact Us #### > > > |
# Getting Live Half-Life Game Stats From ColdFusion - Forums You may post here on any subjects related to this site or the software therein. (Most everything on this site is tied into the forums so that you may leave or post comments about it.) List all New Post
## Getting Live Half-Life Game Stats From ColdFusion `From: Lewis A. Sellers` `Date: May 28 2003 02:10 PM` ## Getting Live Half-Life Game Stats From ColdFusion `by Lewis Sellers` So, you want to proudly post the stats of your Half-Life or Counter-Strike game servers on your web site. Live. No problem. No, really. With a few lines of CFM and a general purpose COM object for sending and receiving UDP packets that I wrote there's not much to it. First off though, let's get into a little beginner-level background info, then we'll talk about the COM and how to make the scripts. The internet, as you may or may not know, runs off of the TCP/IP network protocol suite. TCP/IP consists of three protocols called: ICMP, UDP and TCP. ICMP is used only to PING for the distance between computers and TCP is used to do most of the heavy-lifting on the internet, powering such familiar things as HTTP, FTP and all your email through POP3/IMAP4 and SMTP. UDP is the network protocol that almost every game since the late ?90s has used to send information back and forth from game severs to a player?s game client. This is the important part. If you have the ability to send and receive data through the UDP protocol, you can TALK TO ANY GAME on the internet. ?Hi, how ya doing? So, who?s online tonight and how many frags do they have?? Now, sadly, ColdFusion doesn?t ship with any way to inherently use UDP in a general purpose manner. (Or at least it didn?t until CFMX exposed some JAVA functions that can be used for UDP. Using those functions however can be rather intimidating to most folks.) For this reason, sometime back I wrote a simple-to-use, general purpose little COM object specifically so that I could talk to game servers with ColdFusion scripts. Before we go further, and show you the actual scripts we should go into a little bit more detail on just exactly what this thing ?UDP? actually is. Otherwise you might be scratching your head trying to understand what?s going on later. UDP stands for ?User Datagram Protocol?. In simple terms, UDP allows you to send a ?packet? of data from one computer to another. By a ?packet? we mean a block of BYTEs (or string of characters such as ?A?, ?B?, etc if you prefer) in a chunk that can range in size anywhere from 0 (that is no bytes at all) up to a little less than 64 kilobytes (or that is technically up to a maximum of 65,507 bytes). You definitely couldn?t send say an entire MP3 or an ebook version of the Bible (or Koran) as a single packet, but that is plenty of space for sending around say lists of people who are currently playing on a game server or things like updated x,y,z positions of a couple dozen people and flying rockets 60 times a second or so. [NOTE: 65,507 is the absolute maximum. Depending on the hardware used it may be much less. Across ethernet cards typically data is broken up into packets of 1564 bytes -- only 1,500 bytes of which is usable. Because of the nature of UDP, if you sent 20kb across in a packet, you could expect the last 5kb of data to be truncated and simply lost. FYI, the guarenteed minimum for all hardware is 576 bytes. This is *the* reason that ICQ text messages are limited to about 400+ characters at a time.] You?re probably starting to get the idea of what UDP is and what it?s used for (and if you?re starting to relate it to a sort of binary XML feed that's not a bad way for a CFer to start relating to it), but one last important thing before we get to the scripts themselves. UDP is an ?unreliable? protocol. What this means is that if you tell your computer to send a UDP packet to someone else?s computer, the protocol does NOT guarantee that it will be received. This is important. Unlike the heavier protocol TCP (which we mentioned before) you could send out say 10 packets to someone, and they might report back that they only got 3. What happened to the others? *SHRUG*. Now this might seem like a BAD THING, a reason NOT to use UDP, but in truth the technical reasons behind this are actually what make it the prime choice among game programmers as far as protocols to use. In short, this unreliableness makes it FAST. Unlike the heavier TCP, it?s a fire-and-forget protocol. The attitude is: ?Send it off, and if it arrives, fine, if not, we don?t really care.? The heavier TCP protocol corrects for any lost packets but takes up more bandwidth and creates high(er) ping response times doing so. (As an aside, UNREAL I originally used TCP when it shipped, but in later patches dropped it in favor of UDP when trying to tweak out better responsiveness for its internet multiplay.) Ok. That?s it for the background lecture. We?re not going to get into any more of the technical aspects of UDP else this article will threaten to become a chapter in a book. You should know enough now to more or less follow what we?re going to do in the scripts. ## PART TWO: The Scripts Let?s start with the most basic thing: Getting a list of everyone currently playing on a Half-Life/Counter-Strike game server. All that you really have to do is send a UDP packet to the game server you?re interested in. This packet will contain a request for a list of players. Assuming that the server got the packet (UDP is unreliable remember ? a flakey Ethernet controller in Iraq could have ate the packet), it will send you BACK a packet containing the information you requested. Then it?s simply your job to use the string handling function of ColdFusion to parse through the data you got back and CFOUTPUT it to your web page. That?s all there is to it. Well, except for the details. The devil is in the details they say, and it?s true. Some games send data back and forth in pure, lovely, easy to handle, plain text. Half-life . . . well, now Half-Life is not one of those, unfortunately. It sends its data around in ugly (but compact, and thus fast) chunks of binary data. Not to worry though, the COM object I mentioned, and which you need to make the scripts work (see the APPENDIX for the download URL) has a couple little functions that you can use to pull out the binary formatted data into CFM variables. Ok, the details. The command string (or request) you need to send to the game server to list players is:
    	chr(255) & chr(255) & chr(255) & chr(255) & "players" & chr(10)
Yes, like I said, Half-Life uses some unprintable binary data in its request/responses but you don?t have to understand what it means. All you have to do is just send it, as is, to the game server. Now, what you get back is a packet that contains:
    	(255, 255, 255, 255)  : four chr(255)?s. (An OOB). Ignore this.
    	?D?                   : A response code that means ?player data follows?.
    	                      : You see, UDP can send packets back in a
    	                      : completely different order than you
    	                      : sent them out. Without such codes...
    	                      : you could have a problem.
    	BYTE                  : An 8-bit BYTE that is the ?active player count?.
    	                      : Can technically be 0 to 255.
Then there follows a series of recordsets that you can CFLOOP through containing specific information for each of the players on the server. If ?active player count? is 0 then there is no further data following. Each player record consists if the following data:
    	BYTE                  : The game server?s index number (ie, Primary Key)
    	                      : for the player. Can be 0 to 255.
    	STRING                : A NULL (ie, CHR(0)) terminated ASCII string
    	                      : containing the player?s name.
    	INT32                 : A signed 32-bit integer number (4 BYTES)
    	                      : which is the players FRAG total.
    	FLOAT32               : And finally, a 32-bit floating-point number
    	                      : which represents the time the player has been in
    	                      : the game.
That?s it. Aside from a short lecture on the actual functions the COM object has to send and receive the data and parse through the binary data, you now know how to list the players on a Half-Life server. Smile. ;-) Ok, drum-roll please. Actual code follows. First, we create an instance of the COM object and call it ?obj?.

#

    UDPClient
    >
    	PLAYERS
Simple enough. Now we tell the COM the internet address and port number of the game server we?re interested in by ?open?ing a connect to it. `gaming.twcny.rr.com` always seems to be up, so we?ll use them as an example. (BTW, by default Half-Life is always on port 27015).
?Open? returns a ?1? if it could establish a connection to the server and a ?0? if it couldn?t. We save this in the variable ?c?. We then check if it?s ?1? and print a message saying we couldn?t connect if not.
We set ?s? to the ?players? request string.
Before we do anything else we tell the COM object to wait around up 2 full seconds before giving up on anything it tries to send or receive. You can change this to anything you feel comfortable with. If the game server is sitting on a rack right next to your web server you could change it to 0.050 (or 50 milliseconds) if you want. (Because of a thing called the ?Nagle? algorithm TCP connections generally can't be sent faster than 20ms, but this doesn't apply to UDP.)
Now we send the packet with the ?send? command. That wasn?t hard was it? Again, if the command fails for some reason it?ll return a ?0?, otherwise it?ll return a count of the BYTEs it actually sent off. UDP should NEVER fail unless there is a serious problem with the Windows operating system itself.
    UDP Packet send failure (players).

    UDP Packet sent... (players)  (#c# bytes).
The above codes tests if the ?send? actually worked. I?ve never seen it fail.
And this invokes the command to receive the packet that we're waiting for the game server to send back in response. If we were expecting only pure text we could use the ?Recv? command and immediately print it to the web page. Since we know it's binary data though we use the special ?RecvPacket? command which buffers the data into a binary data cache. We can now issue a few of the special functions I mentioned which can parse through the pesky binary data packets for you. (NOTE: The COM object does have complete documentation of all these functions. Don't worry about that now though. For clarity, the important thing to understand here is that "recvpacket" stores the entire last packet received in a buffer in the COM object itself. The special binary packet handling functions will pull data from this buffer for you in a sequential manner, handling all of what would be a rather ugly business if you tried to handle it yourself in say ColdFusion version 3.x. Support for binary strings is better in latter versions of CF though, if you want to do it by hand. Feel free.)
    UDP packet recvpacket failure...
First though, we check ?packetlength? to see just how many bytes of data we got back. If the game server sends back a packet with 0 bytes, well, something very odd is up with that server. But we check anyway.
    UDP packet recv... (#obj.packetlength# bytes)
Print the count of bytes received.
    oob = #oob#
Ok. Here we go. We use the ?packetnumber? function to grab ?numbers? from the ?packet? buffer. The four chr(255) we mentioned above should be here. Actually, if you really want to know, the four chr(255) are what the number ?-1? looks like as a binary 32-bit integer. Oh, you didn?t want to know? Sorry. Pretend I didn?t tell you. It?s not important. All you need to know is that?s it?s a 32-bit integer so we tell ?packetnumber? to please grab an int32 for us. Which we promptly ignore. (It?s a special UDP header control code called an OOB ? Out Of Bounds. Didn?t want to know that either, eh?)
    ch = #ch#
Guess what? We use ?packetchar? to grab a character (a single BYTE expressed as an ASCII character) from the packet stream and pray to whatever deities will listen that it?s a ?D?, cause ?D? (as mentioned far above) means player listing data follows.
    **PACKET "PLAYERS" DETECTED**
Yippie. It is the packet with player data in it.
    active client count = #acc#
We use ?packetnumber? again to grab the next BYTE in the packet buffer and save it as a number to the CF variable ?acc?. This number should tell us exactly how many players are, right at this very moment, in the game trying to kill each other.

    #Player NameFragsin-game Time

    	#id##playername##frags##ingame#
The table above should be somewhat obvious by now as we?ve used the ?packetnumber? function a couple times and we went into detail on the breakdown of the contents of the packet as well. The ?packetstring? function is new, but also obvious we should think. What we?ve done is just CFLOOP through the remaining player data and print up a table based on the info we extract from the binary packet buffer.
    **PACKET WRONG-TYPE or NOT DETECTED**
The remains of a few of our conditional CFIF tests.
And finally, now that we?re done, we close the connection we opened with the ?Open? command.
    Couldn?t establish connection.
Hey. That?s it. We?re done man (or woman, as the case may be). You now know more about this subject than probably every one else on the planet excepting perhaps a few thousand other people. Now go on and build yourself a stats page. fini --min Lewis Sellers April 2003 http://www.intrafoundation.com ## APPENDIX A: The COM Compoment This article made use of a COM component called ?UDPClient?. It?s free, completely open-sourced and available for immediate download at http://www.intrafoundation.com/UDPClient.asp. It?s written in C++, not that it matters as the compiled .DLL is included in the .ZIP. All you have to do is unzip the .DLL into your web folder somewhere and register it. I.e. at a console prompt in that folder type:
    	regsvr32 UDPClientcom.dll
There's also an `install.bat` in the .ZIP's folder you can click on. But now it?s exposed for anything on your computer to use it, including your CFM scripts. ## APPENDIX B: Other Half-Life Commands ### PING Send:
    	chr(255) & chr(255) & chr(255) & chr(255) & "ping" & chr(10)
Receive:
    	INT32       : -1
    	?j?         :
### PLAYERS Send:
    	chr(255) & chr(255) & chr(255) & chr(255) & "players" & chr(10)
Receive:
    	INT32       : -1
    	?D?         :
    	BYTE        : active client count
Followed by a record-set of active client count
    	BYTE        : client index
    	STRING      : player name
    	INT32       : frags
    	FLOAT32     : total time in game
### RULES Send:
    	chr(255) & chr(255) & chr(255) & chr(255) & "rules" & chr(10)
Receive:
    	INT32       : -1
    	?E?         :
    	INT16       : count of rules
Followed by a record-set of rules
    	STRING      : rule name
    	STRING      : rule value
### INFO Send:
    	chr(255) & chr(255) & chr(255) & chr(255) & "info" & chr(10)
Receive:
    	INT32       : -1
    	?C?         :
    	STRING      : server network address
    	STRING      : host name
    	STRING      : map name
    	STRING      : game name
    	STRING      : game description
    	BYTE        : active client count
    	BYTE        : maximum number of clients (players) allowed
    	BYTE        : network protocol version
### DETAILS Send:
    	chr(255) & chr(255) & chr(255) & chr(255) & "details" & chr(10)
Receive:
    	INT32       : -1
    	?m?         :
    	STRING      : server network address
    	STRING      : host name
    	STRING      : map name
    	STRING      : game directory
    	STRING      : game description
    	BYTE        : active client count
    	BYTE        : maximum number of clients (players) allowed
    	BYTE        : protocol version
    	BYTE        : ?l? = listen server, ?d? = dedicated server
    	BYTE        : 'w' = windows, 'l' = linux
    	BYTE        : password? 1 = yes, 0 = no
    	BYTE        : mod? 1 = yes, 0 = no
If mod? is ?1? then extra data follows:
    	STRING      : url for mod website
    	STRING      : url for mod download
    	INT32       : mod version
    	INT32       : mod byte size
    	BYTE        : mod only to server?  1 = yes, 0 = no
    	BYTE        : custom mod client required?  1 = yes, 0 = no
SDK Extension:
    	BYTE        : secure server?  1 = yes, 0 = no
### GETCHALLENGE Send:
    	chr(255) & chr(255) & chr(255) & chr(255) & "getchallenge" & chr(10)
Um... Ok. Wait a minute. Maybe you don't need to know this. This command initiates an actual remote player connection. Yes... I know what's in your head now. You're thinking "Hey! If you just tell me the rest of the command codes I can make my web page play a game of Half-Life all by itself, dude!" Yes, that's technically true, but.... Maybe in another article. ;-) - v1.3 May 2003 - `You may post this article on relevant websites after emailing a notice. This article was originally prepared as a tutorial for UDPClient but first posted to easycfm.com.` #### http://tutorial117.easycfm.com Delete Edit Reply