From bd17fb00010308c5e4b97b9fdbcf4435cfedef40 Mon Sep 17 00:00:00 2001 From: Michael Morrison Date: Sat, 29 Mar 2014 09:34:12 -0500 Subject: [PATCH] Add SA:MP support, fixes #3 --- README.md | 1 + games.txt | 2 +- lib/typeresolver.js | 2 + protocols/samp.js | 90 ++++++++++++++++++ test.txt | 218 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 protocols/samp.js create mode 100644 test.txt diff --git a/README.md b/README.md index 8bde389..6457f04 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,7 @@ Supported Games * Rise of Nations (riseofnations) [[Separate Query Port](#separate-query-port)] * Rune (rune) [[Separate Query Port](#separate-query-port)] * Rust (rust) [[Separate Query Port](#separate-query-port)] +* San Andreas Multiplayer (samp) [[Separate Query Port](#separate-query-port)] * Serious Sam (ss) [[Separate Query Port](#separate-query-port)] * Serious Sam 2 (ss2) * Shattered Horizon (shatteredhorizon) diff --git a/games.txt b/games.txt index 0f4424a..0fb58f7 100644 --- a/games.txt +++ b/games.txt @@ -19,7 +19,6 @@ # openttd|OpenTTD|openttd|port=3979 # plainsight|Plain Sight|plainsight # redfaction|Red Faction|redfaction|port_query=7755 -# samp|San Andreas Multiplayer|samp|port_query=7777 # savage|Savage|savage|port_query=11235 # savage2|Savage 2|savage2|port_query=11235 # teeworlds|Teeworlds|teeworlds|port=8303 @@ -206,6 +205,7 @@ ricochet|Ricochet|valve riseofnations|Rise of Nations|gamespy1|port_query=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_query=7777 ss|Serious Sam|gamespy1|port=25600,port_query_offset=1 ss2|Serious Sam 2|gamespy2|port=25600 shatteredhorizon|Shattered Horizon|valve diff --git a/lib/typeresolver.js b/lib/typeresolver.js index c67f199..3a2678f 100644 --- a/lib/typeresolver.js +++ b/lib/typeresolver.js @@ -57,6 +57,8 @@ function createProtocolInstance(type) { module.exports = { lookup: function(type) { + if(!type) throw Error('No game specified'); + if(type.substr(0,9) == 'protocol-') { return createProtocolInstance(type.substr(9)); } diff --git a/protocols/samp.js b/protocols/samp.js new file mode 100644 index 0000000..d440038 --- /dev/null +++ b/protocols/samp.js @@ -0,0 +1,90 @@ +var async = require('async'); + +module.exports = require('./core').extend({ + run: function(state) { + + var self = this; + var len; + + async.series([ + function(c) { + self.sendPacket('i',function(reader) { + state.password = !!reader.uint(1); + state.raw.numplayers = reader.uint(2); + state.maxplayers = reader.uint(2); + state.name = self.readString(reader,4); + state.raw.gamemode = self.readString(reader,4); + self.map = self.readString(reader,4); + c(); + }); + }, + function(c) { + self.sendPacket('r',function(reader) { + var ruleCount = reader.uint(2); + state.raw.rules = {}; + for(var i = 0; i < ruleCount; i++) { + var key = self.readString(reader,1); + var value = self.readString(reader,1); + state.raw.rules[key] = value; + } + if('mapname' in state.raw.rules) + state.map = state.raw.rules.mapname; + c(); + }); + }, + function(c) { + self.sendPacket('d',function(reader) { + var playerCount = reader.uint(2); + for(var i = 0; i < playerCount; i++) { + var player = {}; + player.id = reader.uint(1); + player.name = self.readString(reader,1); + player.score = reader.int(4); + player.ping = reader.uint(4); + state.players.push(player); + } + c(); + },function() { + for(var i = 0; i < state.raw.numplayers; i++) { + state.players.push({}); + } + }); + }, + function(c) { + self.finish(state); + } + ]); + }, + readString: function(reader,lenBytes) { + var length = reader.uint(lenBytes); + if(!length) return ''; + var string = reader.string({length:length}); + return string; + }, + sendPacket: function(type,onresponse,ontimeout) { + var self = this; + var outbuffer = new Buffer(11); + outbuffer.writeUInt32BE(0x53414D50,0); + var ipSplit = self.options.address.split('.'); + outbuffer.writeUInt8(parseInt(ipSplit[0]),4); + outbuffer.writeUInt8(parseInt(ipSplit[1]),5); + outbuffer.writeUInt8(parseInt(ipSplit[2]),6); + outbuffer.writeUInt8(parseInt(ipSplit[3]),7); + outbuffer.writeUInt16LE(self.options.port,8); + outbuffer.writeUInt8(type.charCodeAt(0),10); + + this.udpSend(outbuffer,function(buffer) { + var reader = self.reader(buffer); + for(var i = 0; i < outbuffer.length; i++) { + if(outbuffer.readUInt8(i) !== reader.uint(1)) return; + } + onresponse(reader); + return true; + },function() { + if(ontimeout) { + ontimeout(); + return true; + } + }); + } +}); diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..58605ad --- /dev/null +++ b/test.txt @@ -0,0 +1,218 @@ +* Age of Chivalry (ageofchivalry) +* Age of Empires 2 (aoe2) [[Separate Query Port](#separate-query-port)] +* Alien Arena (alienarena) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* Commandos 3: Destination Berlin (commandos3) [[Separate Query Port](#separate-query-port)] +* Command and Conquer: Renegade (cacrenegade) [[Separate Query Port](#separate-query-port)] +* Contact J.A.C.K. (contactjack) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* F1 2002 (f12002) [[Separate Query Port](#separate-query-port)] +* F1 Challenge 99-02 (f1c9902) [[Separate Query Port](#separate-query-port)] +* Far Cry (farcry) [[Separate Query Port](#separate-query-port)] +* Far Cry (farcry2) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* Ghost Recon: Advanced Warfighter 2 (graw2) [[Separate Query Port](#separate-query-port)] +* Giants: Citizen Kabuto (giantscitizenkabuto) [[Separate Query Port](#separate-query-port)] +* Global Operations (globaloperations) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* Hexen World (hexenworld) [[Separate Query Port](#separate-query-port)] +* The Hidden: Source (hidden) +* Hidden and Dangerous 2 (had2) [[Separate Query Port](#separate-query-port)] +* Homefront (homefront) +* Homeworld 2 (homeworld2) [[Separate Query Port](#separate-query-port)] +* IGI-2: Covert Strike (igi2) [[Separate Query Port](#separate-query-port)] +* IL-2 Sturmovik (il2) [[Separate Query Port](#separate-query-port)] +* Insurgency (insurgency) +* Iron Storm (ironstorm) [[Separate Query Port](#separate-query-port)] +* James Bond: Nightfire (jamesbondnightfire) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* Nerf Arena Blast (nab) [[Separate Query Port](#separate-query-port)] +* Neverwinter Nights (nwn) [[Separate Query Port](#separate-query-port)] +* Neverwinter Nights 2 (nwn2) [[Separate Query Port](#separate-query-port)] +* Nexuiz (nexuiz) [[Separate Query Port](#separate-query-port)] +* Nitro Family (nitrofamily) [[Separate Query Port](#separate-query-port)] +* No One Lives Forever (nolf) [[Separate Query Port](#separate-query-port)] +* No One Lives Forever 2 (nolf2) [[Separate Query Port](#separate-query-port)] +* Nuclear Dawn (nucleardawn) +* OpenArena (openarena) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* Quake 1: QuakeWorld (quake1) +* Quake 2 (quake2) +* Quake 3: Arena (quake3) +* Quake 4 (quake4) +* Rag Doll Kung Fu (ragdollkungfu) +* Rainbow Six (r6) [[Separate Query Port](#separate-query-port)] +* Rainbow Six 2: Rogue Spear (r6roguespear) [[Separate Query Port](#separate-query-port)] +* Rainbow Six 3: Raven Shield (r6ravenshield) [[Separate Query Port](#separate-query-port)] +* RalliSport Challenge (rallisportchallenge) [[Separate Query Port](#separate-query-port)] +* Rally Masters (rallymasters) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* Return to Castle Wolfenstein (rtcw) [[Separate Query Port](#separate-query-port)] +* Ricochet (ricochet) +* Rise of Nations (riseofnations) [[Separate Query Port](#separate-query-port)] +* Rune (rune) [[Separate Query Port](#separate-query-port)] +* Rust (rust) [[Separate Query Port](#separate-query-port)] +* San Andreas Multiplayer (samp) [[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) [[Separate Query Port](#separate-query-port)] +* Shootmania (shootmania) +* SiN (sin) [[Separate Query Port](#separate-query-port)] +* SiN Episodes (sinep) +* Soldat (soldat) [[Separate Query Port](#separate-query-port)] +* Soldier of Fortune (sof) [[Separate Query Port](#separate-query-port)] +* Soldier of Fortune 2 (sof2) [[Separate Query Port](#separate-query-port)] +* S.T.A.L.K.E.R. (stalker) [[Separate Query Port](#separate-query-port)] +* Star Trek: Bridge Commander (stbc) [[Separate Query Port](#separate-query-port)] +* Star Trek: Voyager - Elite Force (stvef) [[Separate Query Port](#separate-query-port)] +* Star Trek: Voyager - Elite Force 2 (stvef2) [[Separate Query Port](#separate-query-port)] +* Star Wars: Battlefront (swbf) [[Separate Query Port](#separate-query-port)] +* Star Wars: Battlefront 2 (swbf2) [[Separate Query Port](#separate-query-port)] +* Star Wars: Jedi Knight (swjk) [[Separate Query Port](#separate-query-port)] +* Star Wars: Jedi Knight 2 (swjk2) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* Terraria (terraria) [[Separate Query Port](#separate-query-port)] +* Tony Hawk's Pro Skater 3 (thps3) [[Separate Query Port](#separate-query-port)] +* Tony Hawk's Pro Skater 4 (thps4) [[Separate Query Port](#separate-query-port)] +* Tony Hawk's Underground 2 (thu2) [[Separate Query Port](#separate-query-port)] +* Trackmania 2 (trackmania2) +* Trackmania Forever (trackmaniaforever) +* Tremulous (tremulous) [[Separate Query Port](#separate-query-port)] +* Tribes: Vengeance (tribesvengeance) [[Separate Query Port](#separate-query-port)] +* Tron 2.0 (tron20) [[Separate Query Port](#separate-query-port)] +* Turok 2 (turok2) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* V8 Supercar Challenge (v8supercar) [[Separate Query Port](#separate-query-port)] +* 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) [[Separate Query Port](#separate-query-port)] +* Wolfenstein: Enemy Territory (wolfensteinet) [[Separate Query Port](#separate-query-port)] +* Xpand Rally (xpandrally) [[Separate Query Port](#separate-query-port)] +* Zombie Master (zombiemaster) +* Zombie Panic: Source (zps)