diff --git a/protocols/hexenworld.js b/protocols/hexenworld.js new file mode 100644 index 0000000..1524e28 --- /dev/null +++ b/protocols/hexenworld.js @@ -0,0 +1,6 @@ +module.exports = require('./quake2').extend({ + init: function() { + this._super(); + this.sendHeader = '\xFFstatus\x0a'; + } +}); diff --git a/reference/cryengine/gameq.txt b/reference/cryengine/gameq.txt new file mode 100644 index 0000000..cd4f003 --- /dev/null +++ b/reference/cryengine/gameq.txt @@ -0,0 +1,104 @@ +I was under the impression all the farcry games used ASE? +If anyone notices a problem, this is reference for some old cryengine protocol: + + +. + * + * $Id: cry.php,v 1.2 2008/04/22 18:52:27 tombuskens Exp $ + */ + + +[cry] +rules = "\x7f\xff\xff\xffrules" +status = "\x7f\xff\xff\xffstatus" +players = "\x7f\xff\xff\xffplayers" + +[farcry2] +status = "\x06\x01\x00\x00\x2b\xbf\x53\x51\xdc\x80\x19\xb8\xb0\x57\xa3\x75" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * CryEngine protocol + * + * @author Tom Buskens + * @version $Revision: 1.2 $ + */ +class GameQ_Protocol_cry extends GameQ_Protocol +{ + public function rules() + { + // Header + $this->header(); + + // Rules + while ($this->p->getLength()) { + $this->r->add($this->p->readString(), $this->p->readString()); + } + } + + public function status() + { + // Header + $this->header(); + + // Unknown + $this->p->read(15); + + $this->r->add('hostname', $this->p->readString()); + $this->r->add('mod', $this->p->readString()); + $this->r->add('gametype', $this->p->readString()); + $this->r->add('map', $this->p->readString()); + + $this->r->add('num_players', $this->p->readInt8()); + $this->r->add('max_players', $this->p->readInt8()); + $this->r->add('password', $this->p->readInt8()); + $this->p->read(2); + $this->r->add('punkbuster', $this->p->readInt8()); + } + + + public function players() + { + $this->header(); + $this->p->skip(2); + + while ($this->p->getLength()) { + $this->r->addPlayer('name', $this->p->readString()); + $this->r->addPlayer('team', $this->p->readString()); + $this->p->skip(1); + $this->r->addPlayer('score', $this->p->readInt8()); + $this->p->skip(3); + $this->r->addPlayer('ping', $this->p->readInt8()); + $this->p->skip(7); + } + } + + + private function header() + { + if ($this->p->read(4) !== "\x7f\xff\xff\xff") { + throw new GameQ_ParsingException($this->p); + } + $this->p->skip(2); + } +} +?> + diff --git a/reference/cs2d/gameq.txt b/reference/cs2d/gameq.txt new file mode 100644 index 0000000..fe73696 --- /dev/null +++ b/reference/cs2d/gameq.txt @@ -0,0 +1,56 @@ +. + * + * $Id: cs2d.php,v 1.1 2008/04/14 18:04:50 tombuskens Exp $ + */ + +[cs2d] +status = "\xfa\x00" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Counterstrike 2d Protocol + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_cs2d extends GameQ_Protocol +{ + public function status() + { + $this->p->skip(2); + $this->r->add('hostname', $this->readString()); + $this->r->add('password', $this->p->readInt8()); + $this->r->add('mapname', $this->readString()); + $this->r->add('num_players', $this->p->readInt8()); + $this->r->add('max_players', $this->p->readInt8()); + $this->r->add('fog_of_war', $this->p->readInt8()); + $this->r->add('war_mode', $this->p->readInt8()); + $this->r->add('version', $this->readString()); + } + + private function readString() + { + $str = $this->p->readString("\x0D"); + $this->p->skip(1); + return $str; + } +} +?> diff --git a/reference/cs2d.txt b/reference/cs2d/lgsl.txt similarity index 100% rename from reference/cs2d.txt rename to reference/cs2d/lgsl.txt diff --git a/reference/cube/gameq_cube.txt b/reference/cube/gameq_cube.txt new file mode 100644 index 0000000..5320a80 --- /dev/null +++ b/reference/cube/gameq_cube.txt @@ -0,0 +1,58 @@ +. + * + * $Id: cube.php,v 1.1 2007/07/04 09:08:36 tombuskens Exp $ + */ + +[cube] +status = "\x00" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Cube Engine protocol + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_cube extends GameQ_Protocol +{ + /* + * status packet + */ + public function status() + { + // Header + if (!$this->p->read() == "\x00") { + throw new GameQ_ParsingException($this->p); + } + $this->p->skip(2); + + // Vars + $this->r->add('protocol', $this->p->readInt8()); + $this->r->add('mode', $this->p->readInt8()); + $this->r->add('num_players', $this->p->readInt8()); + $this->r->add('time_remaining', $this->p->readInt8()); + $this->r->add('map', $this->p->readString()); + $this->r->add('servername', $this->p->readString()); + $this->r->add('max_players', $this->p->readInt8()); + } + +} +?> diff --git a/reference/cube/gameq_sauerbraten.txt b/reference/cube/gameq_sauerbraten.txt new file mode 100644 index 0000000..d313202 --- /dev/null +++ b/reference/cube/gameq_sauerbraten.txt @@ -0,0 +1,79 @@ +. + * + * $Id: sauerbraten.php,v 1.2 2008/06/25 13:50:47 tombuskens Exp $ + */ + +[sauerbraten] +status = "\xFF" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Sauerbraten / Cube 2 Engine protocol + * + * @author Tom Buskens + * @version $Revision: 1.2 $ + */ +class GameQ_Protocol_sauerbraten extends GameQ_Protocol +{ + private function getint() + { + $i = $this->p->readInt8(); + if ($i == 0x80) + { + $i = $this->p->readInt8(); + $i |= $this->p->readInt8() << 8; + } + else if ($i == 0x81) + { + $i = $this->p->readInt8(); + $i |= $this->p->readInt8() << 8; + $i |= $this->p->readInt8() << 16; + $i |= $this->p->readInt8() << 24; + } + + return $i; + } + + /* + * status packet + */ + public function status() + { + // Header + if (!$this->p->read() == "\x00") { + throw new GameQ_ParsingException($this->p); + } + + // Vars + $this->r->add('num_players', $this->getint()); + $this->r->add('num_attributes', $this->getint()); + $this->r->add('protocol', $this->getint()); + $this->r->add('servermode', $this->getint()); + $this->r->add('time_remaining', $this->getint()); + $this->r->add('max_players', $this->getint()); + $this->r->add('locked', $this->getint()); + $this->r->add('map', $this->p->readString()); + $this->r->add('servername', $this->p->readString()); + } +} + + +?> diff --git a/reference/cube.txt b/reference/cube/lgsl.txt similarity index 100% rename from reference/cube.txt rename to reference/cube/lgsl.txt diff --git a/reference/freelancer/gameq.txt b/reference/freelancer/gameq.txt new file mode 100644 index 0000000..1c72cb6 --- /dev/null +++ b/reference/freelancer/gameq.txt @@ -0,0 +1,57 @@ +. + * + * $Id: freelancer.php,v 1.2 2008/02/22 13:33:40 tombuskens Exp $ + */ + +[freelancer] +status = "\x00\x02\xf1\x26\x01\x26\xf0\x90\xa6\xf0\x26\x57\x4e\xac\xa0\xec\xf8\x68\xe4\x8d\x21" + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Freelancer protocol + * UNTESTED + * + * @author Tom Buskens + * @version $Revision: 1.2 $ + */ +class GameQ_Protocol_freelancer extends GameQ_Protocol +{ + /* + * status packet + */ + public function status() + { + // Server name length @ 3 + $this->p->skip(3); + $name_length = $this->p->readInt8() - 90; + + // Max players @ 20 + $this->p->skip(17); + $this->r->add('max_players', $this->p->readInt8() - 1); + // Num players @ 24 + $this->p->skip(3); + $this->r->add('num_players', $this->p->readInt8() - 1); + + // Servername @ 91 + $this->p->skip(66); + $this->r->add('servername', $this->p->read($name_length)); + } +} +?> diff --git a/reference/freelancer.txt b/reference/freelancer/lgsl.txt similarity index 100% rename from reference/freelancer.txt rename to reference/freelancer/lgsl.txt diff --git a/reference/ghostrecon/gameq.txt b/reference/ghostrecon/gameq.txt new file mode 100644 index 0000000..4be0de1 --- /dev/null +++ b/reference/ghostrecon/gameq.txt @@ -0,0 +1,64 @@ +. + * + * $Id: ghostrecon.php,v 1.1 2007/07/02 10:14:32 tombuskens Exp $ + */ + +[ghostrecon] +status = "\xc0\xde\xf1\x11\x42\x06\x00\xf5\x03\x00\x78\x30\x63" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Ghost Recon protocol + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_ghostrecon extends GameQ_Protocol +{ + /* + * Status + */ + public function status() + { + // Unknown + $this->p->skip(25); + + $this->r->add('servername', $this->readGhostString()); + $this->r->add('map', $this->readGhostString()); + $this->r->add('mission', $this->readGhostString()); + $this->r->add('gametype', $this->readGhostString()); + } + + /** + * Read a Ghost Recon string + * + * @return string The string + */ + private function readGhostString() + { + if ($this->p->getLength() < 4) return ''; + $this->p->skip(4); + + return $this->p->readString(); + + } +} +?> diff --git a/reference/ghostrecon.txt b/reference/ghostrecon/lgsl.txt similarity index 100% rename from reference/ghostrecon.txt rename to reference/ghostrecon/lgsl.txt diff --git a/reference/ghostrecon/qstat_info.txt b/reference/ghostrecon/qstat_info.txt new file mode 100644 index 0000000..54a3566 --- /dev/null +++ b/reference/ghostrecon/qstat_info.txt @@ -0,0 +1,229 @@ +/********* +QStat - Real-time game server stats +http://sourceforge.net/p/qstat/ +License: The Artistic License 2.0 +*********/ + +Ghost Recon - QStat notes +------------------------- + +The following Server Stats are pulled from the Ghost Recon Server - NOTE +many other stats continue to work as normal due to the base qstat program. + +$SERVERNAME + + The name of the GR Server. + +$PLAYERS + + The number of Players that are playing, oberving or in the Lobby + (note the ignoreserverplayer Argument above) + +$MAXPLAYERS + + The maximum players that the server will allow playing, oberving + or in the Lobby (note the ignoreserverplayer Argument above) + +$MAP + + The Name of the MAP that is being used (NOTE not the Mission) + +$GAME + + The Mods that the server is running. Ex: mp1; is the Desert + Seige Mod + +$(RULE:error) + + If an error occured there may be some detail here. IF the problm + occurred very early in the interpretation then $SERVERNAME will + hold the details. + +$(RULE:mission) + + The name of the Mission that the server is running. + +$(RULE:gamemode) + + What is the Game Mode that the server is in. Known values are + COOP, TEAM and SOLO + +$(RULE:missiontype) + + What is the Mission Type. Known Values are: Mission, Firefight, + Recon, Hamburger Hill, Last Man Standing, Sharpshooter, Search + And Rescue, Domination, and Seige. + +$(RULE:dedicated) + + Is this server Dedicated; Yes or No. + +$(RULE:status) + + What is the Playing Status of the Server, values are Playing, + Joining or Debrief. + +$(RULE:gametime) + + What is the Time limit for the Game. Values are 00:00, 05:00, + 10:00, 15:00 20:00, 25:00, 30:00, 45:00 and 60:00. The 00:00 + is for an unlimited game. The format of this uses the -ts, + -tc and -tsw command line options. + +$(RULE:timeplayed) + + How long has this game been playing. The format of this uses + the -ts, -tc and -tsw command line options. + +$(RULE:remainingtime) + + How much time is left in this game. The format of this uses + the -ts, -tc and -tsw command line options. + +$(RULE:version) + + What is the Version number reported by the server. Patch 1.2 = + 10.1010A, Patch 1.3 = 11.101A + +$(RULE:spawntype) + + What type of spawn is in use. Known Values are None, Infinite, + Individual and Team. + +$(RULE:spawncount) + + How many spawns are allowed. Enhancment possibility to add + $(IF:SPAWN) to filter out when spawntype is none. + +$(RULE:restrict) + + What Weapon restrictions are in force for the server. + +$(RULE:password) + + Does the Server have a join password defined Yes or No. + +$(RULE:ti) + + Is the server using the Threat Indicator. + +$(RULE:motd) + + What is the Message Of The Day - Note these can be quite big. + +$(RULE:patch) + + What is the patch level of the GR Server. + +$(RULE:usestarttime) + + Is the server configured to start a game after "starttimeset" + (Yes) OR does everyone need to click on ready (no). + +$(RULE:starttimeset) + + What time is configured to automatically start the next round. + +$(RULE:debrieftime) + + How long does the server wait at the Debrief screen after + a mission. + +$(RULE:respawnmin) + + How long must a dead player wait before he can repawn. + +$(RULE:respawnmax) + + What is the longest time that a user has to respawn. + +$(RULE:respawnsafe) + + How long after respawn is a player invulnerable/cannot damage + others. + +$(RULE:allowobservers) + + Does the server allow observers? Yes or No + +$(RULE:startwait) + + How long untill the automatic start timer forces the next game + to start. + +$(RULE:iff) + + What Identification - Friend or Foe is configured. None, + Reticule or Names + +$PLAYERNAME + + What is the Players Name. + +$TEAMNUM + + What Team Number is the Player On. Known Values are 1,2,3,4,5. + 1 is Team BLUE, 2 is Team Read, 3 is Team Yellow, 4 is + Team Green, 5 is Unassigned (observer or in lobby) + +$TEAMNAME + + What is the Name of the Team, see above. + +$DEATHS + + What is the health of this player. 0 Alive, 1 Dead. Note if the + player has spawns remaining this can change from 1 back to 0. + Enhancement possibility to add $HEALTH or $(RULE:health). + Hopefully RSE/UBI will add the Deaths, Frags, and Ping to the + availible information. If this happens then it would be better + to have a $HEALTH + +$(IF:DEATHS) and $(IFNOT:DEATHS) + + A Test to see if the player is dead. Usefull in this constuct: + $(IF:DEATHS)Dead$(ENDIF)$(IFNOT:DEATHS)Alive$(ENDIF) + +Ghost Recon communicates on two UDP ports and one TCP stream. Normally TCP +is on port 2346 and carries the game dialog. This is the port number +that is mentioned in the game so we use it and apply an offset to get the +port number for status queries. Port 2347 gives some high level server stats +and 2348 gives fairly low level server stats. QStat is designed around +a single port per server so the 2348 port is used. One down side to this +is the lack of many meaningful detail player stats (Deaths, frags, hit +percentage, ping etc.). I imagines that some of these are availible in +the TCP stream but that would be difficult to add to a program like QStat. + +The Ghost Recon packets are variable structures with a lot of string +lengths. This requires fairly defensive programming as Red Storm +Entertainment is not forthcoming with any details. + +This release adds support for the GhostRecon game. Number one note +is that Red Storm and UBI do not provide the information that many +Quake based users expect. Specifically they do not make Frags, Deaths +Connect Time or Pings availible - at least not as far as I can tell. +That said there are quite a few things that are availible and allow a +server administrator to make the status of his or her server available +to the public via the web. + +This change uses all undocumented interfaces to the Ghost Recon server +so will most likely break when you install a patch. It has been tested +against the Desert Seige update and several public servers. It should +work against the 1.2, 1.3, and 1.4 patches and Island Thunder add-on to +Ghost Recon. + +The Ghost Recon game type is GRS. For command-line queries, use -grs + +There is one query argument to this server, ignoreserverplayer. +This option controls whether the first player is ignored. Ghost Recon +requires that the dedicated server program take up one of the player slots +(always the first slot). The ignoreserverplayer option defaults to 'yes', +so the "server player" will normally not be seen. If you are running +a non-dedicated server, then set ignoreserverplayer to 'no' like this: + + -grs,ignoreserverplayer=no + +Otherwise you would not be able to display your own stats. + + +Ghost Recon support provided by Bob Marriott. \ No newline at end of file diff --git a/reference/gtr2.txt b/reference/gtr2/lgsl.txt similarity index 100% rename from reference/gtr2.txt rename to reference/gtr2/lgsl.txt diff --git a/reference/hexen2/gameq.txt b/reference/hexen2/gameq.txt new file mode 100644 index 0000000..3f38792 --- /dev/null +++ b/reference/hexen2/gameq.txt @@ -0,0 +1,52 @@ +. + * + * $Id: hexen2.php,v 1.1 2007/07/11 09:12:31 tombuskens Exp $ + */ + +[hexen2] +status = "\x80\x00\x00\x0e\x02HEXENII\x00\x05" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Hexen 2 protocol + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_hexen2 extends GameQ_Protocol +{ + /* + * status packet + */ + public function status() + { + // Header? + $this->p->skip(5); + + $this->r->add('address', $this->p->readString()); + $this->r->add('servername', $this->p->readString()); + $this->r->add('map', $this->p->readString()); + $this->r->add('num_players', $this->p->readInt8()); + $this->r->add('max_players', $this->p->readInt8()); + $this->p->skip(); // unknown + } +} +?> diff --git a/reference/openttd/gameq.txt b/reference/openttd/gameq.txt new file mode 100644 index 0000000..3d60f8d --- /dev/null +++ b/reference/openttd/gameq.txt @@ -0,0 +1,77 @@ +. + * + * $Id: openttd.php,v 1.1 2009/10/24 18:45:16 evilpie Exp $ + */ + +[openttd] +status = "\x03\x00\x00" + + +require_once GAMEQ_BASE . 'Protocol.php'; + +/** + * OpenTTD Protocol, direct port from udp.cpp source from the game + * + * @author Tom Schuster + * @version $Revision: 1.1 $ + */ + + class GameQ_Protocol_openttd extends GameQ_Protocol + { + public function status () + { + $this->p->readInt16(); # packet size + $this->p->readInt8(); # packet type + + $protocol_version = $this->p->readInt8(); + $this->r->add('protocol_version', $protocol_version); + switch ($protocol_version) + { + case 4: + $num_grfs = $this->p->readInt8(); #number of grfs + $this->r->add('num_grfs', $num_grfs); + $this->p->skip ($num_grfs * 20); #skip id and md5 hash + case 3: + $this->r->add('game_date', $this->p->readInt32()); + $this->r->add('start_date', $this->p->readInt32()); + case 2: + $this->r->add('companies_max', $this->p->readInt8()); + $this->r->add('companies_on', $this->p->readInt8()); + $this->r->add('spectators_max', $this->p->readInt8()); + case 1: + $this->r->add('hostname', $this->p->readString()); + $this->r->add('version', $this->p->readString()); + $this->r->add('language', $this->p->readInt8()); + $this->r->add('password', $this->p->readInt8()); + $this->r->add('max_clients', $this->p->readInt8()); + $this->r->add('clients', $this->p->readInt8()); + $this->r->add('spectators', $this->p->readInt8()); + if ($protocol_version < 3) + { + $days = ( 365 * 1920 + 1920 / 4 - 1920 / 100 + 1920 / 400 ); + $this->r->add('game_date', $this->p->readInt16() + $days); + $this->r->add('start_date', $this->p->readInt16() + $days); + } + $this->r->add('map', $this->p->readString()); + $this->r->add('map_width', $this->p->readInt16()); + $this->r->add('map_height', $this->p->readInt16()); + $this->r->add('map_type', $this->p->readInt8()); + $this->r->add('dedicated', $this->p->readInt8()); + } + } + } \ No newline at end of file diff --git a/reference/openttd.txt b/reference/openttd/lgsl.txt similarity index 100% rename from reference/openttd.txt rename to reference/openttd/lgsl.txt diff --git a/reference/plainsight.txt b/reference/plainsight/lgsl.txt similarity index 100% rename from reference/plainsight.txt rename to reference/plainsight/lgsl.txt diff --git a/reference/redfaction/gameq.txt b/reference/redfaction/gameq.txt new file mode 100644 index 0000000..82b696e --- /dev/null +++ b/reference/redfaction/gameq.txt @@ -0,0 +1,59 @@ +. + * + * $Id: redfaction.php,v 1.1 2007/06/30 12:43:43 tombuskens Exp $ + */ + +[redfaction] +status = "\x00\x00\x00\x00" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Red Faction Protocol + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_redfaction extends GameQ_Protocol +{ + /* + * getstatus packet + */ + public function status() + { + // Header, we're being carefull here + if ($this->p->read() !== "\x00") { + throw new GameQ_ParsingException($this->p); + } + + // Dunno + while ($this->p->read() !== "\x00") {} + $this->p->read(); + + // Data + $this->r->add('servername', $this->p->readString()); + $this->r->add('gametype', $this->p->readInt8()); + $this->r->add('num_players', $this->p->readInt8()); + $this->r->add('max_players', $this->p->readInt8()); + $this->r->add('map', $this->p->readString()); + $this->p->read(); + $this->r->add('dedicated', $this->p->readInt8()); + } +} diff --git a/reference/rfactor/gameq.txt b/reference/rfactor/gameq.txt new file mode 100644 index 0000000..202c65d --- /dev/null +++ b/reference/rfactor/gameq.txt @@ -0,0 +1,62 @@ +. + * + * $Id: rfactor.php,v 1.2 2009/08/13 20:46:40 evilpie Exp $ + */ + +[rfactor] +status = "rF_S" + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * rFactor Protocol + * + * @author Tom Buskens + * @version $Revision: 1.2 $ + */ +class GameQ_Protocol_rfactor extends GameQ_Protocol +{ + + public function status() + { + // Header + $this->p->jumpto(17); + $this->r->add('version', $this->p->readInt16()); + $this->p->jumpto(25); + $this->r->add('series', $this->p->readString()); + $this->p->jumpto(45); + $this->r->add('servername', $this->p->readString()); + + $this->p->jumpto(73); + $this->r->add('map', $this->p->readString()); + $this->p->jumpto(105); + $this->r->add('motd', $this->p->readString()); + $this->p->jumpto(206); + $this->r->add('rate', $this->p->readInt8()); + $this->r->add('numplayers', $this->p->readInt8()); + $this->r->add('maxplayers', $this->p->readInt8()); + $this->r->add('numbots', $this->p->readInt8()); + $this->r->add('session', $this->p->readInt8() >> 5); + $this->r->add('damage', $this->p->readInt8()); + $this->p->jumpto(217); + $this->r->add('time', $this->p->readInt16()); + $this->r->add('laps', $this->p->readInt16() / 16); + } +} +?> diff --git a/reference/rfactor.txt b/reference/rfactor/lgsl.txt similarity index 100% rename from reference/rfactor.txt rename to reference/rfactor/lgsl.txt diff --git a/reference/samp.txt b/reference/samp/lgsl.txt similarity index 100% rename from reference/samp.txt rename to reference/samp/lgsl.txt diff --git a/reference/savage/gameq.txt b/reference/savage/gameq.txt new file mode 100644 index 0000000..5ac3a06 --- /dev/null +++ b/reference/savage/gameq.txt @@ -0,0 +1,92 @@ +. + * + * $Id: silverback.php,v 1.1 2007/07/11 09:12:31 tombuskens Exp $ + */ + +[silverback] +status = "\x9e\x4c\x23\x00\x00\xcePiNG" + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Silverback Engine Protocol + * (Savage) + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_silverback extends GameQ_Protocol +{ + /* + * status packet + */ + public function status() + { + while ($this->p->getLength()) { + $var = $this->p->readString("\xFE"); + + if ($var == 'players') break; + + $this->r->add($var, $this->p->readString("\xFF")); + } + + $this->players(); + } + + /* + * player / team data + */ + public function players() + { + $team = ''; + $players = 0; + + while ($this->p->getLength()) { + if ($this->p->lookAhead() == "\x20") { + $this->p->skip(); + $this->r->addPlayer('name', $this->p->readString("\x0a")); + $this->r->addPlayer('team', $team); + ++$players; + } + else { + $team = $this->p->readString("\x0a"); + if ($team != '--empty--') { + $this->r->addTeam('name', $team); + } + } + } + } + + + /* + * Merge packets + */ + public function preprocess($packets) + { + // Cut off headers and join packets + $return = ''; + + foreach ($packets as $packet) { + $return .= substr($packet, 12, strlen($packet) - 13); + } + + return $return; + } +} +?> diff --git a/reference/savage.txt b/reference/savage/lgsl.txt similarity index 100% rename from reference/savage.txt rename to reference/savage/lgsl.txt diff --git a/reference/savage2/gameq.txt b/reference/savage2/gameq.txt new file mode 100644 index 0000000..866fb6c --- /dev/null +++ b/reference/savage2/gameq.txt @@ -0,0 +1,55 @@ +. + * + * $Id: savage2.php,v 1.1 2008/05/22 14:16:11 tombuskens Exp $ + */ + +[savage2] +status = "\x01" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Savage 2 Protocol + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_savage2 extends GameQ_Protocol +{ + /* + * status packet + */ + public function status() + { + $this->p->skip(12); + $this->r->add('hostname', $this->p->readString()); + $this->r->add('num_players', $this->p->readInt8()); + $this->r->add('max_players', $this->p->readInt8()); + $this->r->add('time', $this->p->readString()); + $this->r->add('map', $this->p->readString()); + $this->r->add('nextmap', $this->p->readString()); + $this->r->add('location', $this->p->readString()); + $this->r->add('min_players', $this->p->readInt8()); + $this->r->add('gametype', $this->p->readString()); + $this->r->add('version', $this->p->readString()); + $this->r->add('min_level', $this->p->readInt8()); + } +} +?> diff --git a/reference/savage2.txt b/reference/savage2/lgsl.txt similarity index 100% rename from reference/savage2.txt rename to reference/savage2/lgsl.txt diff --git a/reference/teeworlds/gameq.txt b/reference/teeworlds/gameq.txt new file mode 100644 index 0000000..7355adc --- /dev/null +++ b/reference/teeworlds/gameq.txt @@ -0,0 +1,65 @@ +. + * + * $Id: teeworlds.php,v 1.2 2009/03/09 13:36:32 tombuskens Exp $ + */ + +[teeworlds] +status = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFgief" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Teeworlds protocol + * + * @author Tom Buskens + * @version $Revision: 1.2 $ + */ +class GameQ_Protocol_teeworlds extends GameQ_Protocol +{ + /* + * status packet + */ + public function status() + { + $this->p->skip(14); + + $this->r->add('version', $this->p->readString()); + $this->r->add('hostname', $this->p->readString()); + $this->r->add('map', $this->p->readString()); + $this->r->add('gametype', $this->p->readString()); + + + $this->r->add('password', $this->p->readString()); + $this->r->add('ping', $this->p->readString()); + $this->r->add('num_players', $this->p->readString()); + $this->r->add('max_players', $this->p->readString()); + + $this->players(); + } + + private function players() + { + while ($name = $this->p->readString()) { + $this->r->addPlayer('name', $name); + $this->r->addPlayer('score', $this->p->readString()); + } + } +} +?> diff --git a/reference/teeworlds.txt b/reference/teeworlds/lgsl.txt similarity index 100% rename from reference/teeworlds.txt rename to reference/teeworlds/lgsl.txt diff --git a/reference/tribes/gameq.txt b/reference/tribes/gameq.txt new file mode 100644 index 0000000..2c7d897 --- /dev/null +++ b/reference/tribes/gameq.txt @@ -0,0 +1,63 @@ +. + * + * $Id: tribes.php,v 1.1 2007/07/07 14:20:21 tombuskens Exp $ + */ + +[tribes] +status = "b++" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Tribes protocol + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_tribes extends GameQ_Protocol +{ + public function status() + { + // Header + if ($this->p->read(4) != 'c++b') { + throw new GameQ_ParsingException($this->p); + } + + // Variables + $this->r->add('game', $this->p->readPascalString()); + $this->r->add('version', $this->p->readPascalString()); + $this->r->add('hostname', $this->p->readPascalString()); + $this->r->add('dedicated', $this->p->readInt8()); + $this->r->add('password', $this->p->readInt8()); + $this->r->add('num_players', $this->p->readInt8()); + $this->r->add('max_players', $this->p->readInt8()); + $this->r->add('cpu_lsb', $this->p->readInt8()); + $this->r->add('cpu_msb', $this->p->readInt8()); + $this->r->add('mod', $this->p->readPascalString()); + $this->r->add('gametype', $this->p->readPascalString()); + $this->r->add('map', $this->p->readPascalString()); + $this->r->add('motd', $this->p->readPascalString()); + $this->r->add('teamcount', $this->p->readInt8()); // Not sure + + // TODO: player listing + } +} +?> + diff --git a/reference/tribes.txt b/reference/tribes/lgsl.txt similarity index 100% rename from reference/tribes.txt rename to reference/tribes/lgsl.txt diff --git a/reference/tribes2/gameq.txt b/reference/tribes2/gameq.txt new file mode 100644 index 0000000..2f51873 --- /dev/null +++ b/reference/tribes2/gameq.txt @@ -0,0 +1,104 @@ +. + * + * $Id: tribes2.php,v 1.1 2007/07/07 14:52:01 tombuskens Exp $ + */ + +[tribes2] +info = "\x0E\x02\x01\x02\x03\x04" +status = "\x12\x02\x01\x02\x03\x04" + + +require_once GAMEQ_BASE . 'Protocol.php'; + + +/** + * Tribes 2 protocol + * + * @author Tom Buskens + * @version $Revision: 1.1 $ + */ +class GameQ_Protocol_tribes2 extends GameQ_Protocol +{ + public function info() + { + // Header + $this->p->skip(6); + + $this->r->add('version', $this->p->readPascalString()); + + // TODO: Protocol and build numbers + $this->p->skip(12); + + $this->r->add('hostname', $this->p->readPascalString()); + } + + public function status() + { + // Header + $this->p->skip(6); + + // Vars + $this->r->add('mod', $this->p->readPascalString()); + $this->r->add('gametype', $this->p->readPascalString()); + $this->r->add('map', $this->p->readPascalString()); + $this->readBitflag($this->p->read()); + $this->r->add('num_players', $this->p->readInt8()); + $this->r->add('max_players', $this->p->readInt8()); + $this->r->add('num_bots', $this->p->readInt8()); + $this->r->add('cpu', $this->p->readInt16()); + $this->r->add('info', $this->p->readPascalString()); + + $this->p->skip(2); + + $this->teams(); + $this->players(); + } + + private function teams() + { + $num_teams = $this->p->read(); + $this->r->add('num_teams', $num_teams); + $this->p->skip(); + + for ($i = 0; $i < $num_teams; $i++) { + $this->r->addTeam('name', $this->p->readString("\x09")); + $this->r->addTeam('score', $this->p->readString("\x0a")); + } + } + + private function players() + { + // TODO + } + + + private function readBitflag($flag) + { + $vars = array('dedicated', 'password', 'linux', + 'tournament', 'no_alias'); + + $bit = 1; + foreach ($vars as $var) { + $value = ($flag & $bit) ? 1 : 0; + $this->r->add($var, $value); + $bit *= 2; + } + } +} +?> + diff --git a/reference/tribes2.txt b/reference/tribes2/lgsl.txt similarity index 100% rename from reference/tribes2.txt rename to reference/tribes2/lgsl.txt diff --git a/reference/vcmp.txt b/reference/vcmp/lgsl.txt similarity index 100% rename from reference/vcmp.txt rename to reference/vcmp/lgsl.txt