diff --git a/README.md b/README.md index 7f4e880..cc0b222 100644 --- a/README.md +++ b/README.md @@ -71,120 +71,219 @@ Supported Games --- * Age of Chivalry (ageofchivalry) +* Age of Empires 2 (aoe2) [[Separate Query Port](#separate-query-port)] +* Alien Arena (alienarena) * Alien Swarm (alienswarm) * Aliens vs Predator 2 (avp2) -* Aliens vs Predator 3 (avp3) -* America's Army 1 (americasarmy) [[Separate Query Port - Usually port+1](#separate-query-port)] -* America's Army 2 (americasarmy2) [[Separate Query Port - Usually port+1](#separate-query-port)] -* America's Army 3 (americasarmy3) [[Separate Query Port - Usually 27020](#separate-query-port)] -* America's Army: Proving Grounds (americasarmypg) [[Separate Query Port - Usually 27020](#separate-query-port)] +* Aliens vs Predator 2010 (avp2010) +* America's Army (americasarmy) [[Separate Query Port](#separate-query-port)] +* America's Army 2 (americasarmy2) [[Separate Query Port](#separate-query-port)] +* America's Army 3 (americasarmy3) [[Separate Query Port](#separate-query-port)] +* America's Army: Proving Grounds (americasarmypg) [[Separate Query Port](#separate-query-port)] * ArmA Armed Assault 1 (arma) * ArmA Armed Assault 2 (arma2) * ArmA Armed Assault 3 (arma3) * Armagetron (armagetron) -* Battlefield 1942 (bf1942) [[Separate Query Port - Usually 23000](#separate-query-port)] -* Battlefield 2142 (bf2142) [[Separate Query Port - Usually 29900](#separate-query-port)] -* Battlefield 2 (bf2) [[Separate Query Port - Usually 29900](#separate-query-port)] -* Battlefield 3 (bf3) [[Separate Query Port - Usually port+22000](#separate-query-port)] -* Battlefield 4 (bf4) [[Separate Query Port - Usually port+22000](#separate-query-port)] -* Battlefield: Bad Company 2 (bfbc2) [[Separate Query Port - Usually 48888](#separate-query-port)] -* Battlefield: Vietnam (bfv) [[Separate Query Port - Usually 48888](#separate-query-port)] +* Baldur's Gate (baldursgate) [[Separate Query Port](#separate-query-port)] +* Battlefield 1942 (bf1942) [[Separate Query Port](#separate-query-port)] +* Battlefield Vietnam (bfv) [[Separate Query Port](#separate-query-port)] +* Battlefield 2 (bf2) [[Separate Query Port](#separate-query-port)] +* Battlefield 2142 (bf2142) [[Separate Query Port](#separate-query-port)] +* Battlefield: Bad Company 2 (bfbc2) [[Separate Query Port](#separate-query-port)] +* Battlefield 3 (bf3) [[Separate Query Port](#separate-query-port)] +* Battlefield 4 (bf4) [[Separate Query Port](#separate-query-port)] * Breach (breach) -* Brink (brink) [[Separate Query Port - Usually port+1](#separate-query-port)] -* Build and Shoot (buildandshoot) +* Breed (breed) +* Brink (brink) [[Separate Query Port](#separate-query-port)] +* Build and Shoot (buildandshoot) [[Separate Query Port](#separate-query-port)] * Call of Duty (cod) -* Call of Duty 2 (cod2) -* Call of Duty 4 (cod4) -* Call of Duty: Modern Warfare 3 (codmw3) [[Separate Query Port - Usually port+2](#separate-query-port)] * Call of Duty: United Offensive (coduo) +* Call of Duty 2 (cod2) +* Call of Duty 3 (cod3) +* Call of Duty 4: Modern Warfare (cod4) * Call of Duty: World at War (codwaw) +* Call of Duty: Modern Warfare 2 (codmw2) +* Call of Duty: Modern Warfare 3 (codmw3) [[Separate Query Port](#separate-query-port)] +* Call of Juarez (callofjuarez) [[Separate Query Port](#separate-query-port)] +* Chaser (chaser) [[Separate Query Port](#separate-query-port)] +* Chrome (chrome) [[Separate Query Port](#separate-query-port)] +* Codename Eagle (codenameeagle) +* Commandos 3: Destination Berlin (commandos3) +* Command and Conquer: Renegade (cacrenegade) [[Separate Query Port](#separate-query-port)] +* Contact J.A.C.K. (contactjack) * Counter-Strike 1.6 (cs16) * Counter-Strike: Condition Zero (cscz) * Counter-Strike: Source (css) * Counter-Strike: Global Offensive (csgo) +* Cross Racing Championship (crossracing) [[Separate Query Port](#separate-query-port)] * Crysis (crysis) -* Crysis 2 (crysis2) * Crysis Wars (crysiswars) -* Darkest Hour (darkesthour) [[Separate Query Port - Usually port+1](#separate-query-port)] +* Crysis 2 (crysis2) +* Daikatana (daikatana) [[Separate Query Port](#separate-query-port)] +* Dark Messiah of Might and Magic (dmomam) +* Darkest Hour (darkesthour) [[Separate Query Port](#separate-query-port)] +* DayZ (dayz) +* Deadly Dozen: Pacific Theater (deadlydozenpt) +* Deer Hunter 2005 (dh2005) [[Separate Query Port](#separate-query-port)] +* Descent 3 (descent3) [[Separate Query Port](#separate-query-port)] +* Deus Ex (deusex) [[Separate Query Port](#separate-query-port)] +* Devastation (devastation) [[Separate Query Port](#separate-query-port)] +* Dino D-Day (dinodday) +* Dirt Track Racing 2 (dirttrackracing2) [[Separate Query Port](#separate-query-port)] * Day of Defeat (dod) * Day of Defeat: Source (dods) -* DayZ (dayz) [[Separate Query Port - Usually 27016-27020](#separate-query-port)] -* Dino D-Day (dinodday) * Doom 3 (doom3) * DOTA 2 (dota2) -* Enemy Territory Quake Wars (etqw) +* Drakan (drakan) [[Separate Query Port](#separate-query-port)] +* Enemy Territory Quake Wars (etqw) [[Separate Query Port](#separate-query-port)] * F.E.A.R. (fear) -* Far Cry (farcry) [[Separate Query Port - Usually port+123](#separate-query-port)] -* Far Cry 2 (farcry2) [[Separate Query Port - Usually port+123](#separate-query-port)] +* F1 2002 (f12002) +* F1 Challenge 99-02 (f1c9902) +* Far Cry (farcry) [[Separate Query Port](#separate-query-port)] +* Far Cry (farcry2) * Fortress Forever (fortressforever) -* Frontlines: Fuel of War (ffow) +* Flashpoint (flashpoint) [[Separate Query Port](#separate-query-port)] +* Frontlines: Fuel of War (ffow) [[Separate Query Port](#separate-query-port)] * Garry's Mod (garrysmod) * Ghost Recon: Advanced Warfighter (graw) * Ghost Recon: Advanced Warfighter 2 (graw2) -* Gore (gore) +* Giants: Citizen Kabuto (giantscitizenkabuto) +* Global Operations (globaloperations) +* Gore (gore) [[Separate Query Port](#separate-query-port)] +* Gunman Chronicles (gunmanchronicles) * Half-Life 1 Deathmatch (hldm) * Half-Life 2 Deathmatch (hl2dm) * Halo (halo) +* Halo 2 (halo2) +* Heretic 2 (heretic2) * The Hidden: Source (hidden) +* Hidden and Dangerous 2 (had2) [[Separate Query Port](#separate-query-port)] * Homefront (homefront) +* Homeworld 2 (homeworld2) +* IGI-2: Covert Strike (igi2) +* IL-2 Sturmovik (il2) * Insurgency (insurgency) +* Iron Storm (ironstorm) +* James Bond: Nightfire (jamesbondnightfire) * Just Cause 2 Multiplayer (jc2mp) -* Killing Floor (killingfloor) +* Killing Floor (killingfloor) [[Separate Query Port](#separate-query-port)] +* Kingpin: Life of Crime (kingpin) [[Separate Query Port](#separate-query-port)] +* KISS Psycho Circus (kisspc) [[Separate Query Port](#separate-query-port)] * KzMod (kzmod) * Left 4 Dead (left4dead) * Left 4 Dead 2 (left4dead2) -* Mafia 2 Multiplayer (m2mp) [[Separate Query Port - Usually port+1](#separate-query-port)] -* Medal of Honor: Allied Assault (mohaa) [[Separate Query Port - Usually port+97](#separate-query-port)] -* Medal of Honor: Spearhead (mohsh) [[Separate Query Port - Usually port+97](#separate-query-port)] -* Medal of Honor: Breakthrough (mohbt) [[Separate Query Port - Usually port+97](#separate-query-port)] -* Medal of Honor 2010 (moh2010) [[Separate Query Port - Usually 48888](#separate-query-port)] -* Medal of Honor: Warfighter (mohwf) -* Minecraft (minecraft) [[Additional Notes](#minecraft)] -* Monday Night Combat (mnc) -* Multi Theft Auto [[Separate Query Port - Usually port+123](#separate-query-port)] -* Mumble [[Additional Notes](#mumble)] +* Mafia 2 Multiplayer (m2mp) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Allied Assault (mohaa) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Pacific Assault (mohpa) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Airborne (mohab) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Spearhead (mohsh) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Breakthrough (mohbt) [[Separate Query Port](#separate-query-port)] +* Medal of Honor 2010 (moh2010) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Warfighter (mohwf) [[Separate Query Port](#separate-query-port)] +* Minecraft (minecraft) +* Minecraft (minecraftping) +* Monday Night Combat (mnc) [[Separate Query Port](#separate-query-port)] +* Multi Theft Auto: Vice City (mtavc) [[Separate Query Port](#separate-query-port)] +* Multi Theft Auto: San Andreas (mtasa) [[Separate Query Port](#separate-query-port)] +* Mumble (mumble) [[Separate Query Port](#separate-query-port)] +* Mumble (mumbleping) * Mutant Factions (mutantfactions) -* Natural Selection (ns) -* Natural Selection 2 (ns2) [[Separate Query Port - Usually port+1](#separate-query-port)] +* Nascar Thunder 2004 (nascarthunder2004) +* netPanzer (netpanzer) * No More Room in Hell (nmrih) +* Natural Selection (ns) +* Natural Selection 2 (ns2) [[Separate Query Port](#separate-query-port)] +* Need for Speed: Hot Pursuit 2 (nfshp2) +* Nerf Arena Blast (nab) [[Separate Query Port](#separate-query-port)] +* Neverwinter Nights (nwn) +* Neverwinter Nights 2 (nwn2) [[Separate Query Port](#separate-query-port)] +* Nexuiz (nexuiz) +* Nitro Family (nitrofamily) +* No One Lives Forever (nolf) +* No One Lives Forever 2 (nolf2) * Nuclear Dawn (nucleardawn) +* OpenArena (openarena) +* Operation Flashpoint (operationflashpoint) [[Separate Query Port](#separate-query-port)] +* Painkiller (painkiller) [[Separate Query Port](#separate-query-port)] +* Postal 2 (postal2) [[Separate Query Port](#separate-query-port)] * Prey (prey) -* Quake 1 (quake1) +* Quake 1: QuakeWorld (quake1) * Quake 2 (quake2) -* Quake 3 (quake3) +* Quake 3: Arena (quake3) * Quake 4 (quake4) -* Red Orchestra: Ostfront 41-45 (redorchestraost) [[Separate Query Port - Usually port+10](#separate-query-port)] -* Red Orchestra 2 (redorchestra2) [[Separate Query Port - Usually 27015](#separate-query-port)] +* Rag Doll Kung Fu (ragdollkungfu) +* Rainbow Six (r6) +* Rainbow Six: Raven Shield (r6ravenshield) [[Separate Query Port](#separate-query-port)] +* Rainbow Six: Rogue Spear (r6roguespear) +* RalliSport Challenge (rallisportchallenge) +* Rally Masters (rallymasters) +* Red Orchestra (redorchestra) [[Separate Query Port](#separate-query-port)] +* Red Orchestra: Ostfront 41-45 (redorchestraost) [[Separate Query Port](#separate-query-port)] +* Red Orchestra 2 (redorchestra2) [[Separate Query Port](#separate-query-port)] +* Redline (redline) * Return to Castle Wolfenstein (rtcw) * Ricochet (ricochet) -* Rust (rust) +* Rise of Nations (riseofnations) +* Rune (rune) [[Separate Query Port](#separate-query-port)] +* Rust (rust) [[Separate Query Port](#separate-query-port)] +* Serious Sam (ss) [[Separate Query Port](#separate-query-port)] +* Serious Sam 2 (ss2) +* Shattered Horizon (shatteredhorizon) * The Ship (ship) -* ShootMania (shootmania) [[Additional Notes](#nadeo-shootmania--trackmania--etc)] +* Shogo (shogo) +* Shootmania (shootmania) +* SiN (sin) +* SiN Episodes (sinep) +* Soldat (soldat) [[Separate Query Port](#separate-query-port)] +* Soldier of Fortune (sof) * Soldier of Fortune 2 (sof2) +* S.T.A.L.K.E.R. (stalker) [[Separate Query Port](#separate-query-port)] +* Star Trek: Bridge Commander (stbc) +* Star Trek: Voyager - Elite Force (stvef) +* Star Trek: Voyager - Elite Force 2 (stvef2) +* Star Wars: Battlefront (swbf) * Star Wars: Battlefront 2 (swbf2) * Star Wars: Jedi Knight (swjk) * Star Wars: Jedi Knight 2 (swjk2) +* Star Wars: Republic Commando (swrc) [[Separate Query Port](#separate-query-port)] * Starbound (starbound) * Suicide Survival (suicidesurvival) -* SWAT 4 (swat4) [[Separate Query Port - Usually port+2](#separate-query-port)] +* SWAT 4 (swat4) [[Separate Query Port](#separate-query-port)] * Sven Coop (svencoop) * Synergy (synergy) -* Team Fortress 2 (tf2) +* Tactical Ops (tacticalops) [[Separate Query Port](#separate-query-port)] +* Team Factor (teamfactor) * Team Fortress Classic (tfc) -* Teamspeak 2 (teamspeak2) -* Teamspeak 3 (teamspeak3) -* Terraria (terraria) [[Additional Notes](#terraria)] -* TrackMania 2 (trackmania2) [[Additional Notes](#nadeo-shootmania--trackmania--etc)] -* TrackMania Forever (trackmaniaforever) [[Additional Notes](#nadeo-shootmania--trackmania--etc)] -* Unreal Tournament (ut) [[Separate Query Port - Usually port+1](#separate-query-port)] -* Unreal Tournament 2003 (ut2003) [[Separate Query Port - Usually port+1](#separate-query-port)] -* Unreal Tournament 2004 (ut2004) [[Separate Query Port - Usually port+1](#separate-query-port)] -* Unreal Tournament 3 (ut3) [[Separate Query Port - Usually 6500](#separate-query-port)] +* Team Fortress 2 (tf2) +* Teamspeak 2 (teamspeak2) [[Separate Query Port](#separate-query-port)] +* Teamspeak 3 (teamspeak3) [[Separate Query Port](#separate-query-port)] +* Terminus (terminus) +* Terraria (terraria) [[Separate Query Port](#separate-query-port)] +* Tony Hawk's Pro Skater 3 (thps3) +* Tony Hawk's Pro Skater 4 (thps4) +* Tony Hawk's Underground 2 (thu2) +* Trackmania 2 (trackmania2) +* Trackmania Forever (trackmaniaforever) +* Tremulous (tremulous) +* Tribes: Vengeance (tribesvengeance) [[Separate Query Port](#separate-query-port)] +* Tron 2.0 (tron20) +* Turok 2 (turok2) +* Universal Combat (universalcombat) [[Separate Query Port](#separate-query-port)] +* Unreal (unreal) [[Separate Query Port](#separate-query-port)] +* Unreal Tournament (ut) [[Separate Query Port](#separate-query-port)] +* Unreal Tournament 2003 (ut2003) [[Separate Query Port](#separate-query-port)] +* Unreal Tournament 2004 (ut2004) [[Separate Query Port](#separate-query-port)] +* Unreal Tournament 3 (ut3) [[Separate Query Port](#separate-query-port)] * Urban Terror (urbanterror) +* V8 Supercar Challenge (v8supercar) * Ventrilo (ventrilo) +* Vietcong (vietcong) [[Separate Query Port](#separate-query-port)] +* Vietcong 2 (vietcong2) [[Separate Query Port](#separate-query-port)] * Warsow (warsow) +* Wheel of Time (wheeloftime) [[Separate Query Port](#separate-query-port)] * Wolfenstein 2009 (wolfenstein2009) * Wolfenstein: Enemy Territory (wolfensteinet) +* Xpand Rally (xpandrally) [[Separate Query Port](#separate-query-port)] * Zombie Master (zombiemaster) * Zombie Panic: Source (zps) @@ -204,6 +303,48 @@ Don't see your game listed here? * protocol-unreal2 * protocol-valve * protocol-valvegold + +Games Not Supported (yet!) +--- +(Want support for one of these games? Please open an issue!) +* Arca Sim Racing +* Cube Engine: + * Assault Cube + * Cube 2: Sauerbraten + * Blood Frontier +* BFRIS +* Call of Duty: Black Ops +* Call of Duty: Black Ops 2 +* Counter-Strike 2D +* Delta Force: Land Warrior +* Enemy Territory: Quake Wars +* Flashpoint +* Freelancer +* Ghost Recon +* GTR2 +* Haze +* Hexen 2 +* Hexen World +* Hidden and Dangerous 2 +* Mohawk Voice Server +* OpenTTD +* Pariah +* Raven Shield +* Red Faction +* rFactor +* San Andreas: Multiplayer +* Savage: Battle for Newerth +* Savage 2: A Tortured Soul +* Shattered Horizons +* Starsiege +* Sum of All Fears +* Teeworlds +* Tribes 1 +* Tribes 2 +* World in Conflict + +> '''Know how to code?''' Many of the protocols for these games are documented +> in the /reference folder, ready for you to write code for! ### Games with Additional Notes @@ -228,7 +369,9 @@ additional option: token #### Separate Query Port Games with this note use a query port which is usually not the same as the game's connection port. -You must pass the query port to GameDig, not the connection port. +Usually, no action will be required from you. The 'port' option you pass GameDig should be the game's +connection port. GameDig will attempt to calculate the query port automatically. If the query still fails, +you may need to pass the 'port_query' option to GameDig as well, indicating the separate query port. Usage from Command Line --- diff --git a/bin/printreadme.js b/bin/printreadme.js new file mode 100644 index 0000000..fa1783f --- /dev/null +++ b/bin/printreadme.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +var TypeResolver = require('../lib/typeresolver'); +TypeResolver.printReadme(); + diff --git a/games.txt b/games.txt new file mode 100644 index 0000000..b43273d --- /dev/null +++ b/games.txt @@ -0,0 +1,257 @@ +# id | pretty | protocol | options | parameters + +ageofchivalry|Age of Chivalry|valve +aoe2|Age of Empires 2|ase|port_query=27224 +alienarena|Alien Arena|quake2|port=27910 +alienswarm|Alien Swarm|valve +avp2|Aliens vs Predator 2|gamespy1|port=27888 +# avp2010 doesn't really... have a default port or query port +# both port and port_query should be specified when used +avp2010|Aliens vs Predator 2010|valve + +americasarmy|America's Army|americasarmy|port=1716,port_query_offset=1 +americasarmy2|America's Army 2|americasarmy|port=1716,port_query_offset=1 +americasarmy3|America's Army 3|valve|port=8777,port_query=27020 +americasarmypg|America's Army: Proving Grounds|valve|port=8777,port_query=27020 + +#arcasimracing|Arca Sim Racing|rfactor|port=34397,port_query_offset=-100 + +arma|ArmA Armed Assault 1|gamespy2|port=2302 +arma2|ArmA Armed Assault 2|gamespy3|port=2302 +arma3|ArmA Armed Assault 3|gamespy3|port=2302 + +armagetron|Armagetron|armagetron|port=4534 +baldursgate|Baldur's Gate|gamespy1|port=6073,port_query=1470 + +bf1942|Battlefield 1942|gamespy1|port=14567,port_query=23000 +bfv|Battlefield Vietnam|gamespy2|port=15567,port_query=23000 +bf2|Battlefield 2|gamespy3|port=16567,port_query=29900|noChallenge +bf2142|Battlefield 2142|gamespy3|port=16567,port_query=29900 +bfbc2|Battlefield: Bad Company 2|battlefield|port=19567,port_query=48888|isBadCompany2 +bf3|Battlefield 3|battlefield|port=25200,port_query_offset=22000 +bf4|Battlefield 4|battlefield|port=25200,port_query_offset=22000 + +breach|Breach|valve|port=27016 +breed|Breed|gamespy2|port=7649 +brink|Brink|valve|port_query_offset=1 +buildandshoot|Build and Shoot|buildandshoot|port=32887,port_query=32886 + +cod|Call of Duty|quake3|port=28960 +coduo|Call of Duty: United Offensive|quake3|port=28960 +cod2|Call of Duty 2|quake3|port=28960 +cod3|Call of Duty 3|quake3|port=28960 +cod4|Call of Duty 4: Modern Warfare|quake3|port=28960 +codwaw|Call of Duty: World at War|quake3|port=28960 +codmw2|Call of Duty: Modern Warfare 2|quake3|port=28960 +codmw3|Call of Duty: Modern Warfare 3|valve|port=27015,port_query_offset=2 + +callofjuarez|Call of Juarez|ase|port_query=26000 +chaser|Chaser|ase|port=3000,port_query_offset=123 +chrome|Chrome|ase|port=27015,port_query_offset=123 +codenameeagle|Codename Eagle|gamespy1|port=4711 +commandos3|Commandos 3: Destination Berlin|gamespy1|port=6500 +cacrenegade|Command and Conquer: Renegade|gamespy1|port=4848,port_query=25300 +contactjack|Contact J.A.C.K.|gamespy1|port=27888 + +cs16|Counter-Strike 1.6|valve +cscz|Counter-Strike: Condition Zero|valve +css|Counter-Strike: Source|valve +csgo|Counter-Strike: Global Offensive|valve + +#cs2d|Counter-Strike: 2D|cs2d|port=? +crossracing|Cross Racing Championship|ase|port=12321,port_query_offset=123 + +crysis|Crysis|gamespy3|port=64087 +crysiswars|Crysis Wars|gamespy3|port=64100 +crysis2|Crysis 2|gamespy3|port=64000 + +# cube|Cube|cube|port=28786,port_query_offset=1 +daikatana|Daikatana|quake2|port=27982,port_query_offset=10 +dmomam|Dark Messiah of Might and Magic|valve +darkesthour|Darkest Hour|unreal2|port=7757,port_query_offset=1 +dayz|DayZ|valve|port=2302 +deadlydozenpt|Deadly Dozen: Pacific Theater|gamespy1|port=25300 +dh2005|Deer Hunter 2005|gamespy2|port=23459,port_query=34567 +descent3|Descent 3|gamespy1|port=2092,port_query=20142 +deusex|Deus Ex|gamespy2|port=7791,port_query_offset=1 +devastation|Devastation|unreal2|port=7777,port_query_offset=1 +dinodday|Dino D-Day|valve +dirttrackracing2|Dirt Track Racing 2|gamespy1|port=32240,port_query_offset=-100 +dod|Day of Defeat|valve +dods|Day of Defeat: Source|valve +doom3|Doom 3|doom3|port=27666 +dota2|DOTA 2|valve +drakan|Drakan|gamespy1|port=27045,port_query_offset=1 +etqw|Enemy Territory Quake Wars|doom3|port=3074,port_query=27733|isEtqw,hasSpaceBeforeClanTag,hasClanTag,hasTypeFlag +fear|F.E.A.R.|gamespy2|port=27888 +f12002|F1 2002|gamespy1|port=3297 +f1c9902|F1 Challenge 99-02|gamespy1|port=34397 +farcry|Far Cry|ase|port=49001,port_query_offset=123 +farcry2|Far Cry|ase|port=14001 +fortressforever|Fortress Forever|valve +flashpoint|Flashpoint|gamespy1|port=2302,port_query_offset=1 +#freelancer|Freelancer|freelancer|port=? +ffow|Frontlines: Fuel of War|ffow|port=5476,port_query_offset=2 +garrysmod|Garry's Mod|valve +#gr|Ghost Recon|ghostrecon|port=2346,port_query_offset=2 +graw|Ghost Recon: Advanced Warfighter|gamespy2|port=15250 +graw2|Ghost Recon: Advanced Warfighter 2|gamespy2|port=16250 +giantscitizenkabuto|Giants: Citizen Kabuto|gamespy1|port=8911 +globaloperations|Global Operations|gamespy1|port=28672 +gore|Gore|gamespy1|port=27777,port_query_offset=1 +#gtr2|GTR2|gtr2|port=34297,port_query_offset=1 +gunmanchronicles|Gunman Chronicles|valve +hldm|Half-Life 1 Deathmatch|valve +hl2dm|Half-Life 2 Deathmatch|valve +halo|Halo|gamespy2|port=2302 +halo2|Halo 2|gamespy2|port=2302 +heretic2|Heretic 2|gamespy1|port=28910 +hidden|The Hidden: Source|valve +had2|Hidden and Dangerous 2|gamespy1|port=11001,port_query_offset=3 +homefront|Homefront|valve +homeworld2|Homeworld 2|gamespy1|port=6500 +igi2|IGI-2: Covert Strike|gamespy1|port=26001 +il2|IL-2 Sturmovik|gamespy1|port=21000 +insurgency|Insurgency|valve +ironstorm|Iron Storm|gamespy1|port=3505 +jamesbondnightfire|James Bond: Nightfire|gamespy1|port=6550 +jc2mp|Just Cause 2 Multiplayer|jc2mp|port=7777 +killingfloor|Killing Floor|killingfloor|port=7707,port_query_offset=1 +kingpin|Kingpin: Life of Crime|gamespy1|port=31510,port_query_offset=-10 +kisspc|KISS Psycho Circus|gamespy1|port=7777,port_query_offset=1 +kzmod|KzMod|valve +left4dead|Left 4 Dead|valve +left4dead2|Left 4 Dead 2|valve +m2mp|Mafia 2 Multiplayer|m2mp|port=27016,port_query_offset=1 + +mohaa|Medal of Honor: Allied Assault|gamespy1|port=12203,port_query_offset=97 +mohpa|Medal of Honor: Pacific Assault|gamespy1|port=13203,port_query_offset=97 +mohab|Medal of Honor: Airborne|gamespy1|port=12203,port_query_offset=97 +mohsh|Medal of Honor: Spearhead|gamespy1|port=12203,port_query_offset=97 +mohbt|Medal of Honor: Breakthrough|gamespy1|port=12203,port_query_offset=97 +moh2010|Medal of Honor 2010|battlefield|port=7673,port_query=48888 +mohwf|Medal of Honor: Warfighter|battlefield|port=25200,port_query_offset=22000 + +minecraft|Minecraft|gamespy3|port=25565|maxAttempts=2,srvRecord=_minecraft._tcp +minecraftping|Minecraft|minecraftping|port=25565|srvRecord=_minecraft._tcp +mnc|Monday Night Combat|valve|port=7777,port_query=27016 +mtavc|Multi Theft Auto: Vice City|ase|port=22003,port_query_offset=123 +mtasa|Multi Theft Auto: San Andreas|ase|port=22003,port_query_offset=123 +mumble|Mumble|mumble|port=64738,port_query=27800 +mumbleping|Mumble|mumbleping|port=64738 +mutantfactions|Mutant Factions|mutantfactions|port=11235 +nascarthunder2004|Nascar Thunder 2004|gamespy2|port=13333 +netpanzer|netPanzer|gamespy1|3030 +nmrih|No More Room in Hell|valve +ns|Natural Selection|valve +ns2|Natural Selection 2|valve|port_query_offset=1 +nfshp2|Need for Speed: Hot Pursuit 2|gamespy1|port=61220 +nab|Nerf Arena Blast|gamespy1|port=4444,port_query_offset=1 +nwn|Neverwinter Nights|gamespy2|port=5121 +nwn2|Neverwinter Nights 2|gamespy2|port=5121,port_query=6500 +nexuiz|Nexuiz|quake3|port=26000 +nitrofamily|Nitro Family|gamespy1|port=25601 +nolf|No One Lives Forever|gamespy1|port=27888 +nolf2|No One Lives Forever 2|gamespy1|port=27890 +nucleardawn|Nuclear Dawn|valve +openarena|OpenArena|quake3|port=27960 +#openttd|OpenTTD|openttd|port=? +operationflashpoint|Operation Flashpoint|gamespy1|port=2234,port_query_offset=1 +painkiller|Painkiller|ase|port=3455,port_query_offset=123 +#plainsight|Plain Sight|plainsight|port=? +postal2|Postal 2|gamespy1|port=7777,port_query_offset=1 +prey|Prey|doom3|port=27719 + +quake1|Quake 1: QuakeWorld|quake1|port=27500 +quake2|Quake 2|quake2|port=27910 +quake3|Quake 3: Arena|quake3|port=27960 +quake4|Quake 4|doom3|port=28004|hasClanTag + +ragdollkungfu|Rag Doll Kung Fu|valve +r6|Rainbow Six|gamespy1|port=2348 +r6ravenshield|Rainbow Six: Raven Shield|gamespy1|port=7777,port_query_offset=1000 +r6roguespear|Rainbow Six: Rogue Spear|gamespy1|port=2346 +rallisportchallenge|RalliSport Challenge|gamespy1|port=17500 +rallymasters|Rally Masters|gamespy1|port=16666 +redorchestra|Red Orchestra|unreal2|port=7758,port_query_offset=1 +redorchestraost|Red Orchestra: Ostfront 41-45|gamespy1|port=7757,port_query_offset=10 +redorchestra2|Red Orchestra 2|valve|port=7777,port_query=27015 +#rfactor|rFactor|rfactor|port=34397,port_query_offset=-100 +redline|Redline|gamespy1|port=25252 +rtcw|Return to Castle Wolfenstein|quake3|port=27960 +ricochet|Ricochet|valve +riseofnations|Rise of Nations|gamespy1|port=6501 +rune|Rune|gamespy1|port=7777,port_query_offset=1 +rust|Rust|valve|port=28015,port_query_offset=1 +#samp|San Andreas Multiplayer|samp|port=? +#savage|Savage|savage|port=? +#savage2|Savage 2|savage2|port=? +ss|Serious Sam|gamespy1|port=25600,port_query_offset=1 +ss2|Serious Sam 2|gamespy2|port=25600 +shatteredhorizon|Shattered Horizon|valve +ship|The Ship|valve +shogo|Shogo|gamespy1|port=27888 +shootmania|Shootmania|nadeo +sin|SiN|gamespy1|port=22450 +sinep|SiN Episodes|valve +soldat|Soldat|ase|port=13073,port_query_offset=123 +sof|Soldier of Fortune|quake1|port=28910 +sof2|Soldier of Fortune 2|quake3|port=20100 +stalker|S.T.A.L.K.E.R.|gamespy3|port=5445,port_query_offset=2 + +stbc|Star Trek: Bridge Commander|gamespy1|port=22101 +stvef|Star Trek: Voyager - Elite Force|quake3|port=27960 +stvef2|Star Trek: Voyager - Elite Force 2|quake3|port=29253 + +swbf|Star Wars: Battlefront|gamespy2|port=3658 +swbf2|Star Wars: Battlefront 2|gamespy2|port=3658 +swjk|Star Wars: Jedi Knight|quake3|port=29070 +swjk2|Star Wars: Jedi Knight 2|quake3|port=28070 +swrc|Star Wars: Republic Commando|gamespy2|port=7777,port_query=11138 + +starbound|Starbound|valve|port=21025 +suicidesurvival|Suicide Survival|valve +swat4|SWAT 4|gamespy2|port=10480,port_query_offset=2 +svencoop|Sven Coop|valve +synergy|Synergy|valve +tacticalops|Tactical Ops|gamespy1|port=7777,port_query_offset=1 +teamfactor|Team Factor|gamespy1|port=57778 +tfc|Team Fortress Classic|valve +tf2|Team Fortress 2|valve +teamspeak2|Teamspeak 2|teamspeak2|port=8767,port_query=51234 +teamspeak3|Teamspeak 3|teamspeak3|port=9987,port_query=10011 +#teeworlds|Teeworlds|teeworlds|port=? +terminus|Terminus|gamespy1|port=12286 +terraria|Terraria|terraria|port=7777,port_query_offset=101 +thps3|Tony Hawk's Pro Skater 3|gamespy1|port=6500 +thps4|Tony Hawk's Pro Skater 4|gamespy1|port=6500 +thu2|Tony Hawk's Underground 2|gamespy1|port=5153 +trackmania2|Trackmania 2|nadeo +trackmaniaforever|Trackmania Forever|nadeo +tremulous|Tremulous|quake3|port=30720 +#tribes|Tribes|tribes|port=? +#tribes2|Tribes 2|tribes2|port=? +tribesvengeance|Tribes: Vengeance|gamespy2|port=7777,port_query_offset=1 +tron20|Tron 2.0|gamespy2|port=27888 +turok2|Turok 2|gamespy1|port=12880 +universalcombat|Universal Combat|ase|port=1135,port_query_offset=123 + +unreal|Unreal|gamespy1|port=7777,port_query_offset=1 +ut|Unreal Tournament|gamespy1|port=7777,port_query_offset=1 +ut2003|Unreal Tournament 2003|unreal2|port=7757,port_query_offset=1 +ut2004|Unreal Tournament 2004|ut2004|port=7777,port_query_offset=1 +ut3|Unreal Tournament 3|ut3|port=7777,port_query_offset=-1277 + +urbanterror|Urban Terror|quake3|port=27960 +v8supercar|V8 Supercar Challenge|gamespy1|port=16700 +ventrilo|Ventrilo|ventrilo|port=3784 +#vcmp|Vice City Multiplayer|vcmp|port=? +vietcong|Vietcong|gamespy1|port=5425,port_query=15425 +vietcong2|Vietcong 2|gamespy2|port=5001,port_query=19967 +warsow|Warsow|warsow|port=44400 +wheeloftime|Wheel of Time|gamespy1|port=7777,port_query_offset=1 +wolfenstein2009|Wolfenstein 2009|doom3|port=27666|hasSpaceBeforeClanTag,hasClanTag,hasTypeFlag +wolfensteinet|Wolfenstein: Enemy Territory|quake3|port=27960 +xpandrally|Xpand Rally|ase|port=28015,port_query_offset=123 +zombiemaster|Zombie Master|valve +zps|Zombie Panic: Source|valve diff --git a/games/aliases.txt b/games/aliases.txt deleted file mode 100644 index 0ed656f..0000000 --- a/games/aliases.txt +++ /dev/null @@ -1,96 +0,0 @@ -# id | pretty | protocol | port? - -ageofchivalry|Age of Chivalry|valve -alienswarm|Alien Swarm|valve -avp2|Aliens vs Predator 2|gamespy1|27888 -avp3|Aliens vs Predator 3|valve|27016 -americasarmy2|America's Army 2|americasarmy -americasarmy3|America's Army 3|valve|27020 -americasarmypg|America's Army: Proving Grounds|valve|27020 -arma|ArmA Armed Assault 1|gamespy2|2302 -arma2|ArmA Armed Assault 2|gamespy3|2302 -arma3|ArmA Armed Assault 3|gamespy3|2302 -bf1942|Battlefield 1942|gamespy1|23000 -bf2142|Battlefield 2142|gamespy3|29900 -bf3|Battlefield 3|battlefield -bf4|Battlefield 4|battlefield -bfv|Battlefield Vietnam|gamespy2|23000 -breach|Breach|valve|27016 -brink|Brink|valve|27016 -cod|Call of Duty|quake3|28960 -cod2|Call of Duty 2|quake3|28960 -cod4|Call of Duty 4|quake3|28960 -codmw3|Call of Duty: Modern Warfare 3|valve|27017 -coduo|Call of Duty: United Offensive|quake3|28960 -codwaw|Call of Duty: World at War|quake3|28960 -csgo|Counter-Strike: Global Offensive|valve -css|Counter-Strike: Source|valve -cs16|Counter-Strike 1.6|valve -cscz|Counter-Strike: Condition Zero|valve -crysis|Crysis|gamespy3|64087 -crysis2|Crysis 2|gamespy3|64000 -crysiswars|Crysis Wars|gamespy3|64100 -darkesthour|Darkest Hour|unreal2|7758 -dayz|DayZ|valve|2302 -dinodday|Dino D-Day|valve -dod|Day of Defeat|valve -dods|Day of Defeat: Source|valve -doom3|Doom 3|doom3 -dota2|DOTA 2|valve -farcry|Far Cry|ase|49124 -farcry2|Far Cry|ase -fear|F.E.A.R.|gamespy2|27888 -fortressforever|Fortress Forever|valve -garrysmod|Garry's Mod|valve -graw|Ghost Recon: Advanced Warfighter|gamespy2 -graw2|Ghost Recon: Advanced Warfighter 2|gamespy2 -gore|Gore|gamespy1 -hldm|Half-Life 1 Deathmatch|valve -hl2dm|Half-Life 2 Deathmatch|valve -halo|Halo|gamespy2|2302 -hidden|The Hidden: Source|valve -homefront|Homefront|valve -insurgency|Insurgency|valve -kzmod|KzMod|valve -left4dead|Left 4 Dead|valve -left4dead2|Left 4 Dead 2|valve -mohaa|Medal of Honor: Allied Assault|gamespy1|12300 -mohsh|Medal of Honor: Spearhead|gamespy1|12300 -mohbt|Medal of Honor: Breakthrough|gamespy1|12300 -moh2010|Medal of Honor 2010|battlefield|48888 -mohwf|Medal of Honor: Warfighter|battlefield|25200 -mnc|Monday Night Combat|valve -mta|Multi Theft Auto|ase|22126 -nmrih|No More Room in Hell|valve -ns|Natural Selection|valve -ns2|Natural Selection 2|valve|27016 -nucleardawn|Nuclear Dawn|valve -prey|Prey|doom3|27719 -quake2|Quake 2|quake2 -quake3|Quake 3|quake3 -redorchestraost|Red Orchestra: Ostfront 41-45|gamespy1|7767 -redorchestra2|Red Orchestra 2|valve -rtcw|Return to Castle Wolfenstein|quake3|27960 -ricochet|Ricochet|valve -rust|Rust|valve|28016 -ship|The Ship|valve -shootmania|Shootmania|nadeo -sof2|Soldier of Fortune 2|quake3|20100 -swbf2|Star Wars: Battlefront 2|gamespy2|3658 -swjk|Star Wars: Jedi Knight|quake3|29070 -swjk2|Star Wars: Jedi Knight 2|quake3|28070 -starbound|Starbound|valve|21025 -suicidesurvival|Suicide Survival|valve -swat4|SWAT 4|gamespy2|10482 -svencoop|Sven Coop|valve -synergy|Synergy|valve -tfc|Team Fortress Classic|valve -tf2|Team Fortress 2|valve -trackmania2|Trackmania 2|nadeo -trackmaniaforever|Trackmania Forever|nadeo -ut|Unreal Tournament|gamespy1|7778 -ut2003|Unreal Tournament 2003|unreal2|8978 -urbanterror|Urban Terror|quake3|27960 -wolfensteinet|Wolfenstein: Enemy Territory|quake3|27960 -zombiemaster|Zombie Master|valve -zps|Zombie Panic: Source|valve diff --git a/games/bf2.js b/games/bf2.js deleted file mode 100644 index a1abeaa..0000000 --- a/games/bf2.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = require('./protocols/gamespy3').extend({ - init: function() { - this._super(); - this.noChallenge = true; - this.pretty = 'Battlefield 2'; - this.options.port = 29900; - } -}); diff --git a/games/bfbc2.js b/games/bfbc2.js deleted file mode 100644 index e4939cd..0000000 --- a/games/bfbc2.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = require('./protocols/battlefield').extend({ - init: function() { - this._super(); - this.pretty = 'Battlefield: Bad Company 2'; - this.options.port = 48888; - this.isBadCompany2 = true; - } -}); diff --git a/games/etqw.js b/games/etqw.js deleted file mode 100644 index eba71ab..0000000 --- a/games/etqw.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = require('./protocols/doom3').extend({ - init: function() { - this._super(); - this.pretty = 'Enemy Territory Quake Wars'; - this.options.port = 27733; - this.isEtqw = true; - this.hasSpaceBeforeClanTag = true; - this.hasClanTag = true; - this.hasTypeFlag = true; - } -}); diff --git a/games/killingfloor.js b/games/killingfloor.js deleted file mode 100644 index 041394d..0000000 --- a/games/killingfloor.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = require('./protocols/unreal2').extend({ - init: function() { - this._super(); - this.options.port = 7708; - this.pretty = 'Killing Floor'; - }, - readExtraInfo: function(reader,state) { - state.raw.wavecurrent = reader.uint(4); - state.raw.wavetotal = reader.uint(4); - } -}); diff --git a/games/minecraft.js b/games/minecraft.js deleted file mode 100644 index 5e76ef6..0000000 --- a/games/minecraft.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = require('./protocols/gamespy3').extend({ - init: function() { - this._super(); - this.pretty = 'Minecraft'; - this.maxAttempts = 2; - this.options.port = 25565; - this.srvRecord = '_minecraft._tcp'; - } -}); diff --git a/games/protocols/valvegold.js b/games/protocols/valvegold.js deleted file mode 100644 index 5177bc0..0000000 --- a/games/protocols/valvegold.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = require('./valve').extend({ - init: function() { - this._super(); - this.goldsrc = true; - } -}); diff --git a/games/quake1.js b/games/quake1.js deleted file mode 100644 index c53847a..0000000 --- a/games/quake1.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = require('./protocols/quake2').extend({ - init: function() { - this._super(); - this.pretty = 'Quake 1'; - this.options.port = 27500; - this.responseHeader = 'n'; - this.isQuake1 = true; - } -}); diff --git a/games/quake4.js b/games/quake4.js deleted file mode 100644 index 4727e6c..0000000 --- a/games/quake4.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = require('./protocols/doom3').extend({ - init: function() { - this._super(); - this.pretty = 'Quake 4'; - this.hasClanTag = true; - this.options.port = 28004; - } -}); diff --git a/games/ut2004.js b/games/ut2004.js deleted file mode 100644 index ea1b9f4..0000000 --- a/games/ut2004.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = require('./protocols/unreal2').extend({ - init: function() { - this._super(); - this.options.port = 7778; - this.pretty = 'Unreal Tournament 2004'; - }, - readExtraInfo: function(reader,state) { - state.raw.ping = reader.uint(4); - state.raw.flags = reader.uint(4); - state.raw.skill = reader.uint(2); - } -}); diff --git a/games/wolfenstein2009.js b/games/wolfenstein2009.js deleted file mode 100644 index 669d3a0..0000000 --- a/games/wolfenstein2009.js +++ /dev/null @@ -1,12 +0,0 @@ -// this was assembled from old docs and not tested -// hopefully it still works - -module.exports = require('./protocols/doom3').extend({ - init: function() { - this._super(); - this.pretty = 'Wolfenstein 2009'; - this.hasSpaceBeforeClanTag = true; - this.hasClanTag = true; - this.hasTypeFlag = true; - } -}); diff --git a/lib/index.js b/lib/index.js index ee198ae..b59e0b9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -17,7 +17,7 @@ udpSocket.on('message', function(buffer, rinfo) { query.options.address != rinfo.address && query.options.altaddress != rinfo.address ) continue; - if(query.options.port != rinfo.port) continue; + if(query.options.port_query != rinfo.port) continue; query._udpResponse(buffer); break; } @@ -31,10 +31,12 @@ Gamedig = { query: function(options,callback) { if(callback) options.callback = callback; - var query = TypeResolver(options.type); - if(!query) { + var query; + try { + query = TypeResolver.lookup(options.type); + } catch(e) { process.nextTick(function() { - callback({error:'Invalid server type: '+options.type}); + callback({error:e.message}); }); return; } diff --git a/lib/typeresolver.js b/lib/typeresolver.js index bbd3b98..c67f199 100644 --- a/lib/typeresolver.js +++ b/lib/typeresolver.js @@ -1,51 +1,85 @@ var Path = require('path'), fs = require('fs'); -var gamesDir = Path.normalize(__dirname+'/../games'); +var protocolDir = Path.normalize(__dirname+'/../protocols'); +var gamesFile = Path.normalize(__dirname+'/../games.txt'); -function readAliases() { - var lines = fs.readFileSync(gamesDir+'/aliases.txt','utf8').split('\n'); - var aliases = {}; +function parseList(str) { + if(!str) return {}; + var split = str.split(','); + var out = {}; + split.forEach(function(one) { + var equals = one.indexOf('='); + var key = equals == -1 ? one : one.substr(0,equals); + var value = equals == -1 ? '' : one.substr(equals+1); + + if(value === 'true' || value === '') value = true; + else if(value === 'false') value = false; + else if(!isNaN(value)) value = parseInt(value); + + out[key] = value; + }); + return out; +} +function readGames() { + var lines = fs.readFileSync(gamesFile,'utf8').split('\n'); + var games = {}; lines.forEach(function(line) { + // strip comments + var comment = line.indexOf('#'); + if(comment != -1) line = line.substr(0,comment); line = line.trim(); if(!line) return; - if(line.charAt(0) == '#') return; + var split = line.split('|'); - aliases[split[0].trim()] = { + games[split[0].trim()] = { pretty: split[1].trim(), protocol: split[2].trim(), - port: split[3] ? parseInt(split[3]) : 0 + options: parseList(split[3]), + params: parseList(split[4]) }; }); - return aliases; + return games; } -var aliases = readAliases(); +var games = readGames(); -function createQueryInstance(type) { +function createProtocolInstance(type) { type = Path.basename(type); - var path = gamesDir+'/'+type; - if(type.substr(0,9) == 'protocol-') { - path = gamesDir+'/protocols/'+type.substr(9); - } - - if(!fs.existsSync(path+'.js')) return false; + var path = protocolDir+'/'+type; + if(!fs.existsSync(path+'.js')) throw Error('Protocol definition file missing: '+type); var protocol = require(path); return new protocol(); } -module.exports = function(type) { - var alias = aliases[type]; +module.exports = { + lookup: function(type) { + if(type.substr(0,9) == 'protocol-') { + return createProtocolInstance(type.substr(9)); + } + + var game = games[type]; + if(!game) throw Error('Invalid game: '+type); + + var query = createProtocolInstance(game.protocol); + query.pretty = game.pretty; + for(var key in game.options) + query.options[key] = game.options[key]; + for(var key in game.params) + query[key] = game.params[key]; - if(alias) { - var query = createQueryInstance('protocol-'+alias.protocol); - if(!query) return false; - query.pretty = alias.pretty; - if(alias.port) query.options.port = alias.port; return query; + }, + printReadme: function() { + for(var key in games) { + var game = games[key]; + var out = "* "+game.pretty+" ("+key+")"; + if(game.options.port_query_offset || game.options.port_query) + out += " [[Separate Query Port](#separate-query-port)]"; + console.log(out); + } } - return createQueryInstance(type); -} +}; diff --git a/games/americasarmy.js b/protocols/americasarmy.js similarity index 75% rename from games/americasarmy.js rename to protocols/americasarmy.js index e19eb71..e8efa32 100644 --- a/games/americasarmy.js +++ b/protocols/americasarmy.js @@ -1,9 +1,4 @@ -module.exports = require('./protocols/gamespy2').extend({ - init: function() { - this._super(); - this.options.port = 1717; - this.pretty = 'America\'s Army 1'; - }, +module.exports = require('./gamespy2').extend({ finalizeState: function(state) { this._super(state); state.name = this.stripColor(state.name); diff --git a/games/armagetron.js b/protocols/armagetron.js similarity index 93% rename from games/armagetron.js rename to protocols/armagetron.js index ac67717..7f13ef4 100644 --- a/games/armagetron.js +++ b/protocols/armagetron.js @@ -1,10 +1,8 @@ -module.exports = require('./protocols/core').extend({ +module.exports = require('./core').extend({ init: function() { this._super(); - this.pretty = 'Armagetron'; this.encoding = 'latin1'; this.byteorder = 'be'; - this.options.port = 4534; }, run: function(state) { var self = this; diff --git a/games/protocols/ase.js b/protocols/ase.js similarity index 94% rename from games/protocols/ase.js rename to protocols/ase.js index d7d72ed..5382684 100644 --- a/games/protocols/ase.js +++ b/protocols/ase.js @@ -1,7 +1,4 @@ module.exports = require('./core').extend({ - init: function() { - this._super(); - }, run: function(state) { var self = this; self.udpSend('s',function(buffer) { diff --git a/games/protocols/battlefield.js b/protocols/battlefield.js similarity index 95% rename from games/protocols/battlefield.js rename to protocols/battlefield.js index 995c8de..fed15dd 100644 --- a/games/protocols/battlefield.js +++ b/protocols/battlefield.js @@ -1,37 +1,9 @@ var async = require('async'); -function buildPacket(params) { - var self = this; - - var paramBuffers = []; - params.forEach(function(param) { - paramBuffers.push(new Buffer(param,'utf8')); - }); - - var totalLength = 12; - paramBuffers.forEach(function(paramBuffer) { - totalLength += paramBuffer.length+1+4; - }); - - var b = new Buffer(totalLength); - b.writeUInt32LE(0,0); - b.writeUInt32LE(totalLength,4); - b.writeUInt32LE(params.length,8); - var offset = 12; - paramBuffers.forEach(function(paramBuffer) { - b.writeUInt32LE(paramBuffer.length, offset); offset += 4; - paramBuffer.copy(b, offset); offset += paramBuffer.length; - b.writeUInt8(0, offset); offset += 1; - }); - - return b; -} - module.exports = require('./core').extend({ init: function() { this._super(); this.encoding = 'latin1'; - this.options.port = 25200+22000; }, run: function(state) { var self = this; @@ -162,3 +134,30 @@ module.exports = require('./core').extend({ return params; } }); + +function buildPacket(params) { + var self = this; + + var paramBuffers = []; + params.forEach(function(param) { + paramBuffers.push(new Buffer(param,'utf8')); + }); + + var totalLength = 12; + paramBuffers.forEach(function(paramBuffer) { + totalLength += paramBuffer.length+1+4; + }); + + var b = new Buffer(totalLength); + b.writeUInt32LE(0,0); + b.writeUInt32LE(totalLength,4); + b.writeUInt32LE(params.length,8); + var offset = 12; + paramBuffers.forEach(function(paramBuffer) { + b.writeUInt32LE(paramBuffer.length, offset); offset += 4; + paramBuffer.copy(b, offset); offset += paramBuffer.length; + b.writeUInt8(0, offset); offset += 1; + }); + + return b; +} diff --git a/games/buildandshoot.js b/protocols/buildandshoot.js similarity index 85% rename from games/buildandshoot.js rename to protocols/buildandshoot.js index 04ecbb2..00fc46e 100644 --- a/games/buildandshoot.js +++ b/protocols/buildandshoot.js @@ -1,15 +1,10 @@ var request = require('request'); -module.exports = require('./protocols/core').extend({ - init: function() { - this._super(); - this.pretty = 'Build and Shoot'; - this.options.port = 32886; - }, +module.exports = require('./core').extend({ run: function(state) { var self = this; request({ - uri: 'http://'+this.options.address+':'+this.options.port+'/', + uri: 'http://'+this.options.address+':'+this.options.port_query+'/', timeout: 3000, }, function(e,r,body) { if(e) return self.fatal('HTTP error'); diff --git a/games/protocols/core.js b/protocols/core.js similarity index 88% rename from games/protocols/core.js rename to protocols/core.js index e1a7cf5..49cbab7 100644 --- a/games/protocols/core.js +++ b/protocols/core.js @@ -2,8 +2,8 @@ var EventEmitter = require('events').EventEmitter, dns = require('dns'), net = require('net'), async = require('async'), - Class = require('../../lib/Class'), - Reader = require('../../lib/reader'); + Class = require('../lib/Class'), + Reader = require('../lib/reader'); module.exports = Class.extend(EventEmitter,{ init: function() { @@ -65,6 +65,7 @@ module.exports = Class.extend(EventEmitter,{ if('host' in this.options) state.query.host = this.options.host; if('address' in this.options) state.query.address = this.options.address; if('port' in this.options) state.query.port = this.options.port; + if('port_query' in this.options) state.query.port_query = this.options.port_query; state.query.type = this.type; if('pretty' in this) state.query.pretty = this.pretty; @@ -92,19 +93,30 @@ module.exports = Class.extend(EventEmitter,{ }, start: function() { var self = this; + var options = self.options; this.reset(); async.series([ function(c) { // resolve host names - if(!('host' in self.options)) return c(); - if(self.options.host.match(/\d+\.\d+\.\d+\.\d+/)) { - self.options.address = self.options.host; + if(!('host' in options)) return c(); + if(options.host.match(/\d+\.\d+\.\d+\.\d+/)) { + options.address = options.host; c(); } else { - self.parseDns(self.options.host,c); + self.parseDns(options.host,c); } - }, function(c) { + }, + function(c) { + // calculate query port if needed + if(!('port_query' in options) && 'port' in options) { + var offset = options.port_query_offset || 0; + options.port_query = options.port + offset; + } + c(); + }, + function(c) { + // run self.run(self.initState()); } @@ -206,7 +218,7 @@ module.exports = Class.extend(EventEmitter,{ var connected = false; var received = new Buffer(0); var address = this.options.address; - var port = this.options.port; + var port = this.options.port_query; var socket = this.tcpSocket = net.connect(port,address,function() { if(self.debug) console.log(address+':'+port+" TCPCONNECTED"); @@ -276,13 +288,13 @@ module.exports = Class.extend(EventEmitter,{ }); }, _udpSendNow: function(buffer) { - if(!('port' in this.options)) return this.fatal('Attempted to send without setting a port'); + if(!('port_query' in this.options)) return this.fatal('Attempted to send without setting a port'); if(!('address' in this.options)) return this.fatal('Attempted to send without setting an address'); if(typeof buffer == 'string') buffer = new Buffer(buffer,'binary'); - if(this.debug) console.log(this.options.address+':'+this.options.port+" UDP--> "+buffer.toString('hex')); - this.udpSocket.send(buffer,0,buffer.length,this.options.port,this.options.address); + if(this.debug) console.log(this.options.address+':'+this.options.port_query+" UDP--> "+buffer.toString('hex')); + this.udpSocket.send(buffer,0,buffer.length,this.options.port_query,this.options.address); }, _udpResponse: function(buffer) { if(this.udpCallback) { diff --git a/games/protocols/doom3.js b/protocols/doom3.js similarity index 98% rename from games/protocols/doom3.js rename to protocols/doom3.js index 539e2fa..9379fba 100644 --- a/games/protocols/doom3.js +++ b/protocols/doom3.js @@ -2,7 +2,6 @@ module.exports = require('./core').extend({ init: function() { this._super(); this.pretty = 'Doom 3'; - this.options.port = 27666; this.encoding = 'latin1'; this.isEtqw = false; this.hasSpaceBeforeClanTag = false; diff --git a/games/ffow.js b/protocols/ffow.js similarity index 86% rename from games/ffow.js rename to protocols/ffow.js index f8536e1..589f222 100644 --- a/games/ffow.js +++ b/protocols/ffow.js @@ -1,8 +1,6 @@ -module.exports = require('./protocols/valve').extend({ +module.exports = require('./valve').extend({ init: function() { this._super(); - this.pretty = 'Frontlines: Fuel of War'; - this.options.port = 5478; this.byteorder = 'be'; this.legacyChallenge = true; }, diff --git a/games/protocols/gamespy1.js b/protocols/gamespy1.js similarity index 100% rename from games/protocols/gamespy1.js rename to protocols/gamespy1.js diff --git a/games/protocols/gamespy2.js b/protocols/gamespy2.js similarity index 89% rename from games/protocols/gamespy2.js rename to protocols/gamespy2.js index e4e6db3..86b4596 100644 --- a/games/protocols/gamespy2.js +++ b/protocols/gamespy2.js @@ -18,7 +18,6 @@ module.exports = require('./core').extend({ }, function() { var buffer = Buffer.concat(packets); - console.log(buffer.toString()); var reader = self.reader(buffer); var header = reader.uint(1); if(header != 0) return; @@ -50,8 +49,7 @@ module.exports = require('./core').extend({ // count is unreliable (often it's wrong), so we don't use it. // read until we hit an empty first field string - if(this.debug) - console.log("Reading fields, starting at: "+reader.rest()); + if(this.debug) console.log("Reading fields, starting at: "+reader.rest()); var fields = []; while(!reader.done()) { @@ -79,8 +77,14 @@ module.exports = require('./core').extend({ else if(key == 'team_t') key = 'name'; else if(key == 'tickets_t') key = 'tickets'; - if(key == 'score' || key == 'deaths' || key == 'ping' || key == 'team' - || key == 'kills' || key == 'tickets') value = parseInt(value); + if( + key == 'score' || key == 'deaths' + || key == 'ping' || key == 'team' + || key == 'kills' || key == 'tickets' + ) { + if(value === '') continue; + value = parseInt(value); + } unit[key] = value; } diff --git a/games/protocols/gamespy3.js b/protocols/gamespy3.js similarity index 100% rename from games/protocols/gamespy3.js rename to protocols/gamespy3.js diff --git a/games/jc2mp.js b/protocols/jc2mp.js similarity index 55% rename from games/jc2mp.js rename to protocols/jc2mp.js index 41fb5a3..545dc54 100644 --- a/games/jc2mp.js +++ b/protocols/jc2mp.js @@ -1,20 +1,16 @@ /* -module.exports = require('./protocols/valve').extend({ +module.exports = require('./valve').extend({ init: function() { this._super(); - this.options.port = 7777; - this.pretty = 'Just Cause 2 Multiplayer'; } }); */ // supposedly, gamespy3 is the "official" query protocol for jcmp, -// but it's broken (requires singlePacketSplits), and doesn't include player names -module.exports = require('./protocols/gamespy3').extend({ +// but it's broken (requires useOnlySingleSplit), and doesn't include player names +module.exports = require('./gamespy3').extend({ init: function() { this._super(); - this.options.port = 7777; - this.pretty = 'Just Cause 2 Multiplayer'; this.useOnlySingleSplit = true; }, finalizeState: function(state) { diff --git a/protocols/killingfloor.js b/protocols/killingfloor.js new file mode 100644 index 0000000..4b82b96 --- /dev/null +++ b/protocols/killingfloor.js @@ -0,0 +1,6 @@ +module.exports = require('./unreal2').extend({ + readExtraInfo: function(reader,state) { + state.raw.wavecurrent = reader.uint(4); + state.raw.wavetotal = reader.uint(4); + } +}); diff --git a/games/m2mp.js b/protocols/m2mp.js similarity index 86% rename from games/m2mp.js rename to protocols/m2mp.js index 52a75de..5522a14 100644 --- a/games/m2mp.js +++ b/protocols/m2mp.js @@ -1,9 +1,7 @@ -module.exports = require('./protocols/core').extend({ +module.exports = require('./core').extend({ init: function() { this._super(); this.encoding = 'latin1'; - this.pretty = 'Mafia 2 Multiplayer'; - this.options.port = 27016; }, run: function(state) { var self = this; diff --git a/games/minecraftping.js b/protocols/minecraftping.js similarity index 89% rename from games/minecraftping.js rename to protocols/minecraftping.js index 2722b90..150312f 100644 --- a/games/minecraftping.js +++ b/protocols/minecraftping.js @@ -14,13 +14,7 @@ function buildPacket(id,data) { ]); } -module.exports = require('./protocols/core').extend({ - init: function() { - this._super(); - this.pretty = 'Minecraft'; - this.options.port = 25565; - this.srvRecord = '_minecraft._tcp'; - }, +module.exports = require('./core').extend({ run: function(state) { var self = this; var receivedData; @@ -30,7 +24,7 @@ module.exports = require('./protocols/core').extend({ // build and send handshake and status TCP packet var portBuf = new Buffer(2); - portBuf.writeUInt16BE(self.options.port,0); + portBuf.writeUInt16BE(self.options.port_query,0); var addressBuf = new Buffer(self.options.address,'utf8'); diff --git a/games/mumble.js b/protocols/mumble.js similarity index 89% rename from games/mumble.js rename to protocols/mumble.js index 787d0db..c4313fd 100644 --- a/games/mumble.js +++ b/protocols/mumble.js @@ -1,10 +1,8 @@ var async = require('async'); -module.exports = require('./protocols/core').extend({ +module.exports = require('./core').extend({ init: function() { this._super(); - this.pretty = 'Mumble'; - this.options.port = 27800; this.options.tcpTimeout = 5000; }, run: function(state) { diff --git a/games/mumbleping.js b/protocols/mumbleping.js similarity index 93% rename from games/mumbleping.js rename to protocols/mumbleping.js index abbe7c0..808f702 100644 --- a/games/mumbleping.js +++ b/protocols/mumbleping.js @@ -3,8 +3,6 @@ var async = require('async'); module.exports = require('./protocols/core').extend({ init: function() { this._super(); - this.pretty = 'Mumble'; - this.options.port = 64738; this.byteorder = 'be'; }, run: function(state) { diff --git a/games/mutantfactions.js b/protocols/mutantfactions.js similarity index 93% rename from games/mutantfactions.js rename to protocols/mutantfactions.js index 5df35bc..bfff46a 100644 --- a/games/mutantfactions.js +++ b/protocols/mutantfactions.js @@ -1,11 +1,6 @@ var request = require('request'); module.exports = require('./protocols/core').extend({ - init: function() { - this._super(); - this.pretty = 'Mutant Factions'; - this.options.port = 11235; - }, run: function(state) { var self = this; request({ diff --git a/games/protocols/nadeo.js b/protocols/nadeo.js similarity index 94% rename from games/protocols/nadeo.js rename to protocols/nadeo.js index 560a1e5..d3c6ff0 100644 --- a/games/protocols/nadeo.js +++ b/protocols/nadeo.js @@ -4,7 +4,8 @@ var gbxremote = require('gbxremote'), module.exports = require('./core').extend({ init: function() { this._super(); - this.options.port = 5000; + this.options.port = 2350; + this.options.port_query = 5000; this.gbxclient = false; }, reset: function() { @@ -33,7 +34,7 @@ module.exports = require('./core').extend({ var params = cmdset.slice(1); if(cmd == 'Connect') { - var client = self.gbxclient = gbxremote.createClient(self.options.port,self.options.host, function(err) { + var client = self.gbxclient = gbxremote.createClient(self.options.port_query,self.options.host, function(err) { if(err) return self.fatal('GBX error '+JSON.stringify(err)); c(); }); diff --git a/protocols/quake1.js b/protocols/quake1.js new file mode 100644 index 0000000..4b18c9a --- /dev/null +++ b/protocols/quake1.js @@ -0,0 +1,7 @@ +module.exports = require('./quake2').extend({ + init: function() { + this._super(); + this.responseHeader = 'n'; + this.isQuake1 = true; + } +}); diff --git a/games/protocols/quake2.js b/protocols/quake2.js similarity index 97% rename from games/protocols/quake2.js rename to protocols/quake2.js index 9d9e21a..802ad87 100644 --- a/games/protocols/quake2.js +++ b/protocols/quake2.js @@ -1,8 +1,6 @@ module.exports = require('./core').extend({ init: function() { this._super(); - this.pretty = 'Quake 2'; - this.options.port = 27910; this.encoding = 'latin1'; this.delimiter = '\n'; this.sendHeader = 'status'; diff --git a/games/protocols/quake3.js b/protocols/quake3.js similarity index 90% rename from games/protocols/quake3.js rename to protocols/quake3.js index c82d602..7fc7990 100644 --- a/games/protocols/quake3.js +++ b/protocols/quake3.js @@ -1,8 +1,6 @@ module.exports = require('./quake2').extend({ init: function() { this._super(); - this.pretty = 'Quake 3'; - this.options.port = 27960; this.sendHeader = 'getstatus'; this.responseHeader = 'statusResponse'; }, diff --git a/games/teamspeak2.js b/protocols/teamspeak2.js similarity index 85% rename from games/teamspeak2.js rename to protocols/teamspeak2.js index 173de76..a61e687 100644 --- a/games/teamspeak2.js +++ b/protocols/teamspeak2.js @@ -1,21 +1,12 @@ var async = require('async'); -module.exports = require('./protocols/core').extend({ - init: function() { - this._super(); - this.pretty = 'Teamspeak 2'; - this.options.port = 8767; - this.options.master_port = 51234; - }, +module.exports = require('./core').extend({ run: function(state) { var self = this; - - var port = this.options.port; - this.options.port = this.options.master_port; - + async.series([ function(c) { - self.sendCommand('sel '+port, function(data) { + self.sendCommand('sel '+self.options.port, function(data) { if(data != '[TS]') self.fatal('Invalid header'); c(); }); diff --git a/games/teamspeak3.js b/protocols/teamspeak3.js similarity index 82% rename from games/teamspeak3.js rename to protocols/teamspeak3.js index 9309342..77597a0 100644 --- a/games/teamspeak3.js +++ b/protocols/teamspeak3.js @@ -1,21 +1,12 @@ var async = require('async'); -module.exports = require('./protocols/core').extend({ - init: function() { - this._super(); - this.pretty = 'Teamspeak 3'; - this.options.port = 9987; - this.options.master_port = 10011; - }, +module.exports = require('./core').extend({ run: function(state) { var self = this; - - var port = this.options.port; - this.options.port = this.options.master_port; - + async.series([ function(c) { - self.sendCommand('use port='+port, function(data) { + self.sendCommand('use port='+self.options.port, function(data) { var split = data.split('\n\r'); if(split[0] != 'TS3') self.fatal('Invalid header'); c(); diff --git a/games/terraria.js b/protocols/terraria.js similarity index 74% rename from games/terraria.js rename to protocols/terraria.js index e3e7c3d..e35bd80 100644 --- a/games/terraria.js +++ b/protocols/terraria.js @@ -1,15 +1,10 @@ var request = require('request'); -module.exports = require('./protocols/core').extend({ - init: function() { - this._super(); - this.pretty = 'Terraria'; - this.options.port = 7878; - }, +module.exports = require('./core').extend({ run: function(state) { var self = this; request({ - uri: 'http://'+this.options.address+':'+this.options.port+'/v2/server/status', + uri: 'http://'+this.options.address+':'+this.options.port_query+'/v2/server/status', timeout: 3000, qs: { players: 'true', diff --git a/games/protocols/unreal2.js b/protocols/unreal2.js similarity index 95% rename from games/protocols/unreal2.js rename to protocols/unreal2.js index 8acf4c5..b4ea301 100644 --- a/games/protocols/unreal2.js +++ b/protocols/unreal2.js @@ -107,7 +107,11 @@ module.exports = require('./core').extend({ if(length > 0) out = reader.string(); } else { length = (length&0x7f)*2; - out = length+reader.string({encoding:'ucs2',length:length}); + if(this.debug) { + console.log("UCS2 STRING"); + console.log(length,reader.buffer.slice(reader.i,reader.i+length)); + } + out = reader.string({encoding:'ucs2',length:length}); } if(out.charCodeAt(out.length-1) == 0) diff --git a/protocols/ut2004.js b/protocols/ut2004.js new file mode 100644 index 0000000..784101a --- /dev/null +++ b/protocols/ut2004.js @@ -0,0 +1,7 @@ +module.exports = require('./unreal2').extend({ + readExtraInfo: function(reader,state) { + state.raw.ping = reader.uint(4); + state.raw.flags = reader.uint(4); + state.raw.skill = reader.uint(2); + } +}); diff --git a/games/ut3.js b/protocols/ut3.js similarity index 87% rename from games/ut3.js rename to protocols/ut3.js index 154b2ef..9a605d0 100644 --- a/games/ut3.js +++ b/protocols/ut3.js @@ -1,9 +1,4 @@ -module.exports = require('./protocols/gamespy3').extend({ - init: function() { - this._super(); - this.pretty = 'Unreal Tournament 3'; - this.options.port = 6500; - }, +module.exports = require('./gamespy3').extend({ finalizeState: function(state) { this._super(state); diff --git a/games/protocols/valve.js b/protocols/valve.js similarity index 97% rename from games/protocols/valve.js rename to protocols/valve.js index 0e547c6..140a334 100644 --- a/games/protocols/valve.js +++ b/protocols/valve.js @@ -128,8 +128,8 @@ module.exports = require('./core').extend({ var self = this; if(this.legacyChallenge) { self.sendPacket(0x57,false,false,0x41,function(b) { - var reader = self.reader(b); - self._challenge = reader.uint(4); + // sendPacket will catch the response packet and + // save the challenge for us c(); }); } else { @@ -295,10 +295,12 @@ module.exports = require('./core').extend({ if(self.debug) console.log('Received challenge key'); if(self._challenge) return self.fatal('Received more than one challenge key'); self._challenge = reader.uint(4); - - if(self.debug) console.log('Restarting query'); - send(); - return true; + + if(sendChallenge) { + if(self.debug) console.log('Restarting query'); + send(); + return true; + } } if(self.debug) console.log("Received "+type.toString(16)+" expected "+expect.toString(16)); diff --git a/games/ventrilo.js b/protocols/ventrilo.js similarity index 98% rename from games/ventrilo.js rename to protocols/ventrilo.js index cb4378d..101924b 100644 --- a/games/ventrilo.js +++ b/protocols/ventrilo.js @@ -1,10 +1,8 @@ var async = require('async'); -module.exports = require('./protocols/core').extend({ +module.exports = require('./core').extend({ init: function() { this._super(); - this.pretty = 'Ventrilo'; - this.options.port = 3784; this.byteorder = 'be'; }, run: function(state) { diff --git a/games/warsow.js b/protocols/warsow.js similarity index 61% rename from games/warsow.js rename to protocols/warsow.js index e007017..9f43ca2 100644 --- a/games/warsow.js +++ b/protocols/warsow.js @@ -1,9 +1,4 @@ -module.exports = require('./protocols/quake3').extend({ - init: function() { - this._super(); - this.pretty = 'Warsow'; - this.options.port = 44400; - }, +module.exports = require('./quake3').extend({ finalizeState: function(state) { this._super(state); if(state.players) { diff --git a/reference/LICENSE b/reference/LICENSE new file mode 100644 index 0000000..fc6c148 --- /dev/null +++ b/reference/LICENSE @@ -0,0 +1,5 @@ +The files in this folder are INDIVIDUALLY LICENSED. +The applicable license is located in the header of each individual file. +These files are not covered by the node-GameDig project license. +The source of node-GameDig does not use or execute the content of +any file of this folder, and maintains a separate, unrelated license. diff --git a/reference/cs2d.txt b/reference/cs2d.txt new file mode 100644 index 0000000..259ade0 --- /dev/null +++ b/reference/cs2d.txt @@ -0,0 +1,70 @@ + + /*----------------------------------------------------------------------------------------------------------\ + | | + | [ LIVE GAME SERVER LIST ] [ © RICHARD PERRY FROM GREYCUBE.COM ] | + | | + | Released under the terms and conditions of the GNU General Public License Version 3 (http://gnu.org) | + | | + \-----------------------------------------------------------------------------------------------------------*/ + + + function lgsl_query_29(&$server, &$lgsl_need, &$lgsl_fp) + { +//---------------------------------------------------------+ +// REFERENCE: http://www.cs2d.com/servers.php + + if ($lgsl_need['s'] || $lgsl_need['e']) + { + $lgsl_need['s'] = FALSE; + $lgsl_need['e'] = FALSE; + + fwrite($lgsl_fp, "\x01\x00\x03\x10\x21\xFB\x01\x75\x00"); + + $buffer = fread($lgsl_fp, 4096); + + if (!$buffer) { return FALSE; } + + $buffer = substr($buffer, 4); // REMOVE HEADER + + $server['e']['bit_flags'] = ord(lgsl_cut_byte($buffer, 1)) - 48; + $server['s']['name'] = lgsl_cut_pascal($buffer); + $server['s']['map'] = lgsl_cut_pascal($buffer); + $server['s']['players'] = ord(lgsl_cut_byte($buffer, 1)); + $server['s']['playersmax'] = ord(lgsl_cut_byte($buffer, 1)); + $server['e']['gamemode'] = ord(lgsl_cut_byte($buffer, 1)); + $server['e']['bots'] = ord(lgsl_cut_byte($buffer, 1)); + + $server['s']['password'] = ($server['e']['bit_flags'] & 1) ? "1" : "0"; + $server['e']['registered_only'] = ($server['e']['bit_flags'] & 2) ? "1" : "0"; + $server['e']['fog_of_war'] = ($server['e']['bit_flags'] & 4) ? "1" : "0"; + $server['e']['friendlyfire'] = ($server['e']['bit_flags'] & 8) ? "1" : "0"; + } + + if ($lgsl_need['p']) + { + $lgsl_need['p'] = FALSE; + + fwrite($lgsl_fp, "\x01\x00\xFB\x05"); + + $buffer = fread($lgsl_fp, 4096); + + if (!$buffer) { return FALSE; } + + $buffer = substr($buffer, 4); // REMOVE HEADER + + $player_total = ord(lgsl_cut_byte($buffer, 1)); + + for ($i=0; $i<$player_total; $i++) + { + $server['p'][$i]['pid'] = ord(lgsl_cut_byte($buffer, 1)); + $server['p'][$i]['name'] = lgsl_cut_pascal($buffer); + $server['p'][$i]['team'] = ord(lgsl_cut_byte($buffer, 1)); + $server['p'][$i]['score'] = lgsl_unpack(lgsl_cut_byte($buffer, 4), "l"); + $server['p'][$i]['deaths'] = lgsl_unpack(lgsl_cut_byte($buffer, 4), "l"); + } + } + +//---------------------------------------------------------+ + + return TRUE; + } diff --git a/reference/cube.txt b/reference/cube.txt new file mode 100644 index 0000000..ca60d1f --- /dev/null +++ b/reference/cube.txt @@ -0,0 +1,168 @@ + + /*----------------------------------------------------------------------------------------------------------\ + | | + | [ LIVE GAME SERVER LIST ] [ © RICHARD PERRY FROM GREYCUBE.COM ] | + | | + | Released under the terms and conditions of the GNU General Public License Version 3 (http://gnu.org) | + | | + \-----------------------------------------------------------------------------------------------------------*/ + + + function lgsl_query_24(&$server, &$lgsl_need, &$lgsl_fp) + { +//---------------------------------------------------------+ +// REFERENCE: http://cubelister.sourceforge.net + + fwrite($lgsl_fp, "\x21\x21"); + + $buffer = fread($lgsl_fp, 4096); + + if (!$buffer) { return FALSE; } + + $buffer = substr($buffer, 2); // REMOVE HEADER + +//---------------------------------------------------------+ + + if ($buffer[0] == "\x1b") // CUBE 1 + { + // RESPONSE IS XOR ENCODED FOR SOME STRANGE REASON + for ($i=0; $i $value) + { + $value = substr($value, 1); + $value = strtolower($value); + $team_field[$key] = $value; + } + +//---------------------------------------------------------+ + + $player_field = "?".lgsl_cut_pascal($buffer); + $player_field = split("\t", $player_field); + + foreach ($player_field as $key => $value) + { + $value = substr($value, 1); + $value = strtolower($value); + + if ($value == "player name") { $value = "name"; } + + $player_field[$key] = $value; + } + + $player_field[] = "unknown_1"; + $player_field[] = "unknown_2"; + +//---------------------------------------------------------+ + + for ($i=0; $i<$server['e']['teams']; $i++) + { + $team_name = lgsl_cut_pascal($buffer); + $team_info = lgsl_cut_pascal($buffer); + + if (!$team_info) { continue; } + + $team_info = str_replace("%t", $team_name, $team_info); + $team_info = split("\t", $team_info); + + foreach ($team_info as $key => $value) + { + $field = $team_field[$key]; + $value = trim($value); + + if ($field == "team name") { $field = "name"; } + + $server['t'][$i][$field] = $value; + } + } + +//---------------------------------------------------------+ + + for ($i=0; $i<$server['s']['players']; $i++) + { + $player_bits = array(); + $player_bits[] = ord(lgsl_cut_byte($buffer, 1)) * 4; // %p = PING + $player_bits[] = ord(lgsl_cut_byte($buffer, 1)); // %l = PACKET LOSS + $player_bits[] = ord(lgsl_cut_byte($buffer, 1)); // %t = TEAM + $player_bits[] = lgsl_cut_pascal($buffer); // %n = PLAYER NAME + $player_info = lgsl_cut_pascal($buffer); + + if (!$player_info) { continue; } + + $player_info = str_replace(array("%p","%l","%t","%n"), $player_bits, $player_info); + $player_info = split("\t", $player_info); + + foreach ($player_info as $key => $value) + { + $field = $player_field[$key]; + $value = trim($value); + + if ($field == "team") { $value = $server['t'][$value]['name']; } + + $server['p'][$i][$field] = $value; + } + } + +//---------------------------------------------------------+ + + return TRUE; + } diff --git a/reference/tribes2.txt b/reference/tribes2.txt new file mode 100644 index 0000000..cf4373c --- /dev/null +++ b/reference/tribes2.txt @@ -0,0 +1,72 @@ + + /*----------------------------------------------------------------------------------------------------------\ + | | + | [ LIVE GAME SERVER LIST ] [ © RICHARD PERRY FROM GREYCUBE.COM ] | + | | + | Released under the terms and conditions of the GNU General Public License Version 3 (http://gnu.org) | + | | + \-----------------------------------------------------------------------------------------------------------*/ + + + function lgsl_query_25(&$server, &$lgsl_need, &$lgsl_fp) + { +//---------------------------------------------------------+ +// REFERENCE: http://www.tribesnext.com + + fwrite($lgsl_fp,"\x12\x02\x21\x21\x21\x21"); + + $buffer = fread($lgsl_fp, 4096); + + if (!$buffer) { return FALSE; } + + $buffer = substr($buffer, 6); // REMOVE HEADER + +//---------------------------------------------------------+ + + $server['s']['game'] = lgsl_cut_pascal($buffer); + $server['e']['gamemode'] = lgsl_cut_pascal($buffer); + $server['s']['map'] = lgsl_cut_pascal($buffer); + $server['e']['bit_flags'] = ord(lgsl_cut_byte($buffer, 1)); + $server['s']['players'] = ord(lgsl_cut_byte($buffer, 1)); + $server['s']['playersmax'] = ord(lgsl_cut_byte($buffer, 1)); + $server['e']['bots'] = ord(lgsl_cut_byte($buffer, 1)); + $server['e']['cpu'] = lgsl_unpack(lgsl_cut_byte($buffer, 2), "S"); + $server['e']['motd'] = lgsl_cut_pascal($buffer); + $server['e']['unknown'] = lgsl_unpack(lgsl_cut_byte($buffer, 2), "S"); + + $server['e']['dedicated'] = ($server['e']['bit_flags'] & 1) ? "1" : "0"; + $server['s']['password'] = ($server['e']['bit_flags'] & 2) ? "1" : "0"; + $server['e']['os'] = ($server['e']['bit_flags'] & 4) ? "L" : "W"; + $server['e']['tournament'] = ($server['e']['bit_flags'] & 8) ? "1" : "0"; + $server['e']['no_alias'] = ($server['e']['bit_flags'] & 16) ? "1" : "0"; + + unset($server['e']['bit_flags']); + +//---------------------------------------------------------+ + + $team_total = lgsl_cut_string($buffer, 0, "\x0A"); + + for ($i=0; $i<$team_total; $i++) + { + $server['t'][$i]['name'] = lgsl_cut_string($buffer, 0, "\x09"); + $server['t'][$i]['score'] = lgsl_cut_string($buffer, 0, "\x0A"); + } + + $player_total = lgsl_cut_string($buffer, 0, "\x0A"); + + for ($i=0; $i<$player_total; $i++) + { + lgsl_cut_byte($buffer, 1); // ? 16 + lgsl_cut_byte($buffer, 1); // ? 8 or 14 = BOT / 12 = ALIAS / 11 = NORMAL + if (ord($buffer[0]) < 32) { lgsl_cut_byte($buffer, 1); } // ? 8 PREFIXES SOME NAMES + + $server['p'][$i]['name'] = lgsl_cut_string($buffer, 0, "\x11"); + lgsl_cut_string($buffer, 0, "\x09"); // ALWAYS BLANK + $server['p'][$i]['team'] = lgsl_cut_string($buffer, 0, "\x09"); + $server['p'][$i]['score'] = lgsl_cut_string($buffer, 0, "\x0A"); + } + +//---------------------------------------------------------+ + + return TRUE; + } diff --git a/reference/vcmp.txt b/reference/vcmp.txt new file mode 100644 index 0000000..22a3cb2 --- /dev/null +++ b/reference/vcmp.txt @@ -0,0 +1,90 @@ + + /*----------------------------------------------------------------------------------------------------------\ + | | + | [ LIVE GAME SERVER LIST ] [ © RICHARD PERRY FROM GREYCUBE.COM ] | + | | + | Released under the terms and conditions of the GNU General Public License Version 3 (http://gnu.org) | + | | + \-----------------------------------------------------------------------------------------------------------*/ + + function lgsl_query_12(&$server, &$lgsl_need, &$lgsl_fp) + { +//---------------------------------------------------------+ +// REFERENCE: +// VICE CITY CURRENTLY ONLY SUPPORTS THE 'i' CHALLENGE + + if ($server['b']['type'] == "samp") { $challenge_packet = "SAMP\x21\x21\x21\x21\x00\x00"; } + elseif ($server['b']['type'] == "vcmp") { $challenge_packet = "VCMP\x21\x21\x21\x21\x00\x00"; $lgsl_need['e'] = FALSE; $lgsl_need['p'] = FALSE; } + + if ($lgsl_need['s']) { $challenge_packet .= "i"; } + elseif ($lgsl_need['e']) { $challenge_packet .= "r"; } + elseif ($lgsl_need['p']) { $challenge_packet .= "d"; } + + fwrite($lgsl_fp, $challenge_packet); + + $buffer = fread($lgsl_fp, 4096); + + if (!$buffer) { return FALSE; } + +//---------------------------------------------------------+ + + $buffer = substr($buffer, 10); // REMOVE HEADER + + $response_type = lgsl_cut_byte($buffer, 1); + +//---------------------------------------------------------+ + + if ($response_type == "i") + { + $lgsl_need['s'] = FALSE; + + $server['s']['password'] = ord(lgsl_cut_byte($buffer, 1)); + $server['s']['players'] = lgsl_unpack(lgsl_cut_byte($buffer, 2), "S"); + $server['s']['playersmax'] = lgsl_unpack(lgsl_cut_byte($buffer, 2), "S"); + $server['s']['name'] = lgsl_cut_pascal($buffer, 4); + $server['e']['gamemode'] = lgsl_cut_pascal($buffer, 4); + $server['s']['map'] = lgsl_cut_pascal($buffer, 4); + } + +//---------------------------------------------------------+ + + elseif ($response_type == "r") + { + $lgsl_need['e'] = FALSE; + + $item_total = lgsl_unpack(lgsl_cut_byte($buffer, 2), "S"); + + for ($i=0; $i<$item_total; $i++) + { + if (!$buffer) { return FALSE; } + + $data_key = strtolower(lgsl_cut_pascal($buffer)); + $data_value = lgsl_cut_pascal($buffer); + + $server['e'][$data_key] = $data_value; + } + } + +//---------------------------------------------------------+ + + elseif ($response_type == "d") + { + $lgsl_need['p'] = FALSE; + + $player_total = lgsl_unpack(lgsl_cut_byte($buffer, 2), "S"); + + for ($i=0; $i<$player_total; $i++) + { + if (!$buffer) { return FALSE; } + + $server['p'][$i]['pid'] = ord(lgsl_cut_byte($buffer, 1)); + $server['p'][$i]['name'] = lgsl_cut_pascal($buffer); + $server['p'][$i]['score'] = lgsl_unpack(lgsl_cut_byte($buffer, 4), "S"); + $server['p'][$i]['ping'] = lgsl_unpack(lgsl_cut_byte($buffer, 4), "S"); + } + } + +//---------------------------------------------------------+ + + return TRUE; + } diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..8b55e2c --- /dev/null +++ b/test.txt @@ -0,0 +1,216 @@ +* Age of Chivalry (ageofchivalry) +* Age of Empires 2 (aoe2) [[Separate Query Port](#separate-query-port)] +* Alien Arena (alienarena) +* Alien Swarm (alienswarm) +* Aliens vs Predator 2 (avp2) +* Aliens vs Predator 2010 (avp2010) +* America's Army (americasarmy) [[Separate Query Port](#separate-query-port)] +* America's Army 2 (americasarmy2) [[Separate Query Port](#separate-query-port)] +* America's Army 3 (americasarmy3) [[Separate Query Port](#separate-query-port)] +* America's Army: Proving Grounds (americasarmypg) [[Separate Query Port](#separate-query-port)] +* ArmA Armed Assault 1 (arma) +* ArmA Armed Assault 2 (arma2) +* ArmA Armed Assault 3 (arma3) +* Armagetron (armagetron) +* Baldur's Gate (baldursgate) [[Separate Query Port](#separate-query-port)] +* Battlefield 1942 (bf1942) [[Separate Query Port](#separate-query-port)] +* Battlefield Vietnam (bfv) [[Separate Query Port](#separate-query-port)] +* Battlefield 2 (bf2) [[Separate Query Port](#separate-query-port)] +* Battlefield 2142 (bf2142) [[Separate Query Port](#separate-query-port)] +* Battlefield: Bad Company 2 (bfbc2) [[Separate Query Port](#separate-query-port)] +* Battlefield 3 (bf3) [[Separate Query Port](#separate-query-port)] +* Battlefield 4 (bf4) [[Separate Query Port](#separate-query-port)] +* Breach (breach) +* Breed (breed) +* Brink (brink) [[Separate Query Port](#separate-query-port)] +* Build and Shoot (buildandshoot) [[Separate Query Port](#separate-query-port)] +* Call of Duty (cod) +* Call of Duty: United Offensive (coduo) +* Call of Duty 2 (cod2) +* Call of Duty 3 (cod3) +* Call of Duty 4: Modern Warfare (cod4) +* Call of Duty: World at War (codwaw) +* Call of Duty: Modern Warfare 2 (codmw2) +* Call of Duty: Modern Warfare 3 (codmw3) [[Separate Query Port](#separate-query-port)] +* Call of Juarez (callofjuarez) [[Separate Query Port](#separate-query-port)] +* Chaser (chaser) [[Separate Query Port](#separate-query-port)] +* Chrome (chrome) [[Separate Query Port](#separate-query-port)] +* Codename Eagle (codenameeagle) +* Commandos 3: Destination Berlin (commandos3) +* Command and Conquer: Renegade (cacrenegade) [[Separate Query Port](#separate-query-port)] +* Contact J.A.C.K. (contactjack) +* Counter-Strike 1.6 (cs16) +* Counter-Strike: Condition Zero (cscz) +* Counter-Strike: Source (css) +* Counter-Strike: Global Offensive (csgo) +* Cross Racing Championship (crossracing) [[Separate Query Port](#separate-query-port)] +* Crysis (crysis) +* Crysis Wars (crysiswars) +* Crysis 2 (crysis2) +* Daikatana (daikatana) [[Separate Query Port](#separate-query-port)] +* Dark Messiah of Might and Magic (dmomam) +* Darkest Hour (darkesthour) [[Separate Query Port](#separate-query-port)] +* DayZ (dayz) +* Deadly Dozen: Pacific Theater (deadlydozenpt) +* Deer Hunter 2005 (dh2005) [[Separate Query Port](#separate-query-port)] +* Descent 3 (descent3) [[Separate Query Port](#separate-query-port)] +* Deus Ex (deusex) [[Separate Query Port](#separate-query-port)] +* Devastation (devastation) [[Separate Query Port](#separate-query-port)] +* Dino D-Day (dinodday) +* Dirt Track Racing 2 (dirttrackracing2) [[Separate Query Port](#separate-query-port)] +* Day of Defeat (dod) +* Day of Defeat: Source (dods) +* Doom 3 (doom3) +* DOTA 2 (dota2) +* Drakan (drakan) [[Separate Query Port](#separate-query-port)] +* Enemy Territory Quake Wars (etqw) [[Separate Query Port](#separate-query-port)] +* F.E.A.R. (fear) +* F1 2002 (f12002) +* F1 Challenge 99-02 (f1c9902) +* Far Cry (farcry) [[Separate Query Port](#separate-query-port)] +* Far Cry (farcry2) +* Fortress Forever (fortressforever) +* Flashpoint (flashpoint) [[Separate Query Port](#separate-query-port)] +* Frontlines: Fuel of War (ffow) [[Separate Query Port](#separate-query-port)] +* Garry's Mod (garrysmod) +* Ghost Recon: Advanced Warfighter (graw) +* Ghost Recon: Advanced Warfighter 2 (graw2) +* Giants: Citizen Kabuto (giantscitizenkabuto) +* Global Operations (globaloperations) +* Gore (gore) [[Separate Query Port](#separate-query-port)] +* Gunman Chronicles (gunmanchronicles) +* Half-Life 1 Deathmatch (hldm) +* Half-Life 2 Deathmatch (hl2dm) +* Halo (halo) +* Halo 2 (halo2) +* Heretic 2 (heretic2) +* The Hidden: Source (hidden) +* Hidden and Dangerous 2 (had2) [[Separate Query Port](#separate-query-port)] +* Homefront (homefront) +* Homeworld 2 (homeworld2) +* IGI-2: Covert Strike (igi2) +* IL-2 Sturmovik (il2) +* Insurgency (insurgency) +* Iron Storm (ironstorm) +* James Bond: Nightfire (jamesbondnightfire) +* Just Cause 2 Multiplayer (jc2mp) +* Killing Floor (killingfloor) [[Separate Query Port](#separate-query-port)] +* Kingpin: Life of Crime (kingpin) [[Separate Query Port](#separate-query-port)] +* KISS Psycho Circus (kisspc) [[Separate Query Port](#separate-query-port)] +* KzMod (kzmod) +* Left 4 Dead (left4dead) +* Left 4 Dead 2 (left4dead2) +* Mafia 2 Multiplayer (m2mp) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Allied Assault (mohaa) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Pacific Assault (mohpa) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Airborne (mohab) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Spearhead (mohsh) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Breakthrough (mohbt) [[Separate Query Port](#separate-query-port)] +* Medal of Honor 2010 (moh2010) [[Separate Query Port](#separate-query-port)] +* Medal of Honor: Warfighter (mohwf) [[Separate Query Port](#separate-query-port)] +* Minecraft (minecraft) +* Minecraft (minecraftping) +* Monday Night Combat (mnc) [[Separate Query Port](#separate-query-port)] +* Multi Theft Auto: Vice City (mtavc) [[Separate Query Port](#separate-query-port)] +* Multi Theft Auto: San Andreas (mtasa) [[Separate Query Port](#separate-query-port)] +* Mumble (mumble) [[Separate Query Port](#separate-query-port)] +* Mumble (mumbleping) +* Mutant Factions (mutantfactions) +* Nascar Thunder 2004 (nascarthunder2004) +* netPanzer (netpanzer) +* No More Room in Hell (nmrih) +* Natural Selection (ns) +* Natural Selection 2 (ns2) [[Separate Query Port](#separate-query-port)] +* Need for Speed: Hot Pursuit 2 (nfshp2) +* Nerf Arena Blast (nab) [[Separate Query Port](#separate-query-port)] +* Neverwinter Nights (nwn) +* Neverwinter Nights 2 (nwn2) [[Separate Query Port](#separate-query-port)] +* Nexuiz (nexuiz) +* Nitro Family (nitrofamily) +* No One Lives Forever (nolf) +* No One Lives Forever 2 (nolf2) +* Nuclear Dawn (nucleardawn) +* OpenArena (openarena) +* Operation Flashpoint (operationflashpoint) [[Separate Query Port](#separate-query-port)] +* Painkiller (painkiller) [[Separate Query Port](#separate-query-port)] +* Postal 2 (postal2) [[Separate Query Port](#separate-query-port)] +* Prey (prey) +* Quake 1: QuakeWorld (quake1) +* Quake 2 (quake2) +* Quake 3: Arena (quake3) +* Quake 4 (quake4) +* Rag Doll Kung Fu (ragdollkungfu) +* Rainbow Six (r6) +* Rainbow Six: Raven Shield (r6ravenshield) [[Separate Query Port](#separate-query-port)] +* Rainbow Six: Rogue Spear (r6roguespear) +* RalliSport Challenge (rallisportchallenge) +* Rally Masters (rallymasters) +* Red Orchestra (redorchestra) [[Separate Query Port](#separate-query-port)] +* Red Orchestra: Ostfront 41-45 (redorchestraost) [[Separate Query Port](#separate-query-port)] +* Red Orchestra 2 (redorchestra2) [[Separate Query Port](#separate-query-port)] +* Redline (redline) +* Return to Castle Wolfenstein (rtcw) +* Ricochet (ricochet) +* Rise of Nations (riseofnations) +* Rune (rune) [[Separate Query Port](#separate-query-port)] +* Rust (rust) [[Separate Query Port](#separate-query-port)] +* Serious Sam (ss) [[Separate Query Port](#separate-query-port)] +* Serious Sam 2 (ss2) +* Shattered Horizon (shatteredhorizon) +* The Ship (ship) +* Shogo (shogo) +* Shootmania (shootmania) +* SiN (sin) +* SiN Episodes (sinep) +* Soldat (soldat) [[Separate Query Port](#separate-query-port)] +* Soldier of Fortune (sof) +* Soldier of Fortune 2 (sof2) +* S.T.A.L.K.E.R. (stalker) [[Separate Query Port](#separate-query-port)] +* Star Trek: Bridge Commander (stbc) +* Star Trek: Voyager - Elite Force (stvef) +* Star Trek: Voyager - Elite Force 2 (stvef2) +* Star Wars: Battlefront (swbf) +* Star Wars: Battlefront 2 (swbf2) +* Star Wars: Jedi Knight (swjk) +* Star Wars: Jedi Knight 2 (swjk2) +* Star Wars: Republic Commando (swrc) [[Separate Query Port](#separate-query-port)] +* Starbound (starbound) +* Suicide Survival (suicidesurvival) +* SWAT 4 (swat4) [[Separate Query Port](#separate-query-port)] +* Sven Coop (svencoop) +* Synergy (synergy) +* Tactical Ops (tacticalops) [[Separate Query Port](#separate-query-port)] +* Team Factor (teamfactor) +* Team Fortress Classic (tfc) +* Team Fortress 2 (tf2) +* Teamspeak 2 (teamspeak2) [[Separate Query Port](#separate-query-port)] +* Teamspeak 3 (teamspeak3) [[Separate Query Port](#separate-query-port)] +* Terminus (terminus) +* Terraria (terraria) [[Separate Query Port](#separate-query-port)] +* Tony Hawk's Pro Skater 3 (thps3) +* Tony Hawk's Pro Skater 4 (thps4) +* Tony Hawk's Underground 2 (thu2) +* Trackmania 2 (trackmania2) +* Trackmania Forever (trackmaniaforever) +* Tremulous (tremulous) +* Tribes: Vengeance (tribesvengeance) [[Separate Query Port](#separate-query-port)] +* Tron 2.0 (tron20) +* Turok 2 (turok2) +* Universal Combat (universalcombat) [[Separate Query Port](#separate-query-port)] +* Unreal (unreal) [[Separate Query Port](#separate-query-port)] +* Unreal Tournament (ut) [[Separate Query Port](#separate-query-port)] +* Unreal Tournament 2003 (ut2003) [[Separate Query Port](#separate-query-port)] +* Unreal Tournament 2004 (ut2004) [[Separate Query Port](#separate-query-port)] +* Unreal Tournament 3 (ut3) [[Separate Query Port](#separate-query-port)] +* Urban Terror (urbanterror) +* V8 Supercar Challenge (v8supercar) +* Ventrilo (ventrilo) +* Vietcong (vietcong) [[Separate Query Port](#separate-query-port)] +* Vietcong 2 (vietcong2) [[Separate Query Port](#separate-query-port)] +* Warsow (warsow) +* Wheel of Time (wheeloftime) [[Separate Query Port](#separate-query-port)] +* Wolfenstein 2009 (wolfenstein2009) +* Wolfenstein: Enemy Territory (wolfensteinet) +* Xpand Rally (xpandrally) [[Separate Query Port](#separate-query-port)] +* Zombie Master (zombiemaster) +* Zombie Panic: Source (zps)