From 3419645a6037c95a9a0d5683809ea61872f4f34c Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 25 Jan 2023 14:12:31 +0100 Subject: [PATCH] PHP 8 Fix for GameQ -Updated Gameq to V3.1 (the directory is still gameqv2 i will rename it later) --- stuff/methods/functions_gs.php | 9 +- third_party/gameq/GameQ/Buffer.php | 41 +- third_party/gameq/GameQ/Filters/Base.php | 5 + .../gameq/GameQ/Filters/Stripcolors.php | 23 +- third_party/gameq/GameQ/GameQ.php | 10 + .../GameQ/Protocols/Aa3.php | 0 .../GameQ/Protocols/Aapg.php | 0 third_party/gameq/GameQ/Protocols/Arma3.php | 184 ++- .../GameQ/Protocols/Avorion.php | 0 .../GameQ/Protocols/Barotrauma.php | 0 .../GameQ/Protocols/Blackmesa.php | 0 .../GameQ/Protocols/Citadel.php | 0 .../GameQ/Protocols/Codmw2.php | 0 third_party/gameq/GameQ/Protocols/Dayzmod.php | 1 - .../GameQ/Protocols/Doom3.php | 0 .../GameQ/Protocols/Fof.php | 0 .../GameQ/Protocols/Had2.php | 0 .../GameQ/Protocols/Halo.php | 0 .../GameQ/Protocols/Hl1.php | 0 .../GameQ/Protocols/Hll.php | 0 .../gameq/GameQ/Protocols/Killingfloor.php | 2 +- .../gameq/GameQ/Protocols/Killingfloor2.php | 2 +- .../GameQ/Protocols/Kingpin.php | 0 .../GameQ/Protocols/M2mp.php | 0 .../GameQ/Protocols/Miscreated.php | 0 .../GameQ/Protocols/Modiverse.php | 0 .../GameQ/Protocols/Nmrih.php | 0 .../GameQ/Protocols/Of.php | 0 .../GameQ/Protocols/Openttd.php | 0 .../GameQ/Protocols/Postscriptum.php | 0 .../GameQ/Protocols/Quake4.php | 0 .../GameQ/Protocols/Rf2.php | 0 third_party/gameq/GameQ/Protocols/Rust.php | 21 + .../GameQ/Protocols/Sco.php | 0 .../gameq/GameQ/Protocols/Sevendaystodie.php | 4 +- .../GameQ/Protocols/Stormworks.php | 0 .../gameq/GameQ/Protocols/Teamspeak3.php | 4 +- third_party/gameq/GameQ/Protocols/Valheim.php | 11 +- .../GameQ/Protocols/Vrising.php | 0 .../GameQ/Protocols/Zomboid.php | 0 third_party/gameq/GameQ/Query/Core.php | 25 + third_party/gameq/GameQ/Server.php | 23 +- third_party/gameq/LICENSE.lgpl | 165 --- .../GameQ => gameq_v2/gameq}/Autoloader.php | 0 .../GameQ => gameq_v2/gameq}/GameQ.php | 0 .../GameQ => gameq_v2/gameq}/Protocol.php | 0 .../GameQ => gameq_v2/gameq}/Server.php | 0 third_party/gameq_v2/gameq/buffer.php | 416 +++--- .../gameq/exception}/Protocol.php | 0 .../gameq/exception}/Query.php | 0 .../gameq/exception}/Server.php | 0 third_party/gameq_v2/gameq/filters.php | 34 - .../gameq/filters}/Base.php | 0 .../gameq/filters}/Normalize.php | 0 .../gameq/filters}/Secondstohuman.php | 0 .../gameq/filters}/Stripcolors.php | 0 .../gameq/filters}/Test.php | 0 third_party/gameq_v2/gameq/filters/core.php | 55 - .../gameq_v2/gameq/filters/normalise.php | 193 --- .../gameq_v2/gameq/filters/stripcolor.php | 76 -- third_party/gameq_v2/gameq/protocols.php | 37 - third_party/gameq_v2/gameq/protocols/7d2d.php | 44 - .../gameq/protocols/Aapg.php} | 8 +- .../gameq/protocols}/Arkse.php | 0 .../gameq/protocols}/Arma.php | 0 .../gameq/protocols}/Arma3.php | 0 .../gameq/protocols}/Atlas.php | 0 .../gameq/protocols/Avorion.php} | 19 +- .../gameq/protocols/Barotrauma.php} | 10 +- .../gameq/protocols}/Batt1944.php | 0 .../gameq/protocols}/Bfh.php | 0 .../gameq/protocols/Blackmesa.php} | 11 +- .../gameq/protocols/Citadel.php} | 11 +- .../gameq/protocols/Codmw2.php} | 65 +- .../gameq/protocols}/Conanexiles.php | 0 .../gameq/protocols}/Contagion.php | 0 .../gameq/protocols}/Cs15.php | 0 .../gameq/protocols}/Cs2d.php | 0 .../gameq/protocols}/Dal.php | 0 .../gameq/protocols}/Dow.php | 0 .../gameq/protocols}/Eco.php | 0 .../gameq/protocols}/Egs.php | 0 .../gameq/protocols}/Grav.php | 0 .../gameq/protocols}/Gta5m.php | 0 .../gameq/protocols}/Gtan.php | 0 .../gameq/protocols}/Gtar.php | 0 .../gameq/protocols/Had2.php} | 22 +- .../gameq/protocols/Halo.php} | 13 +- .../gameq/protocols/Hl1.php} | 9 +- .../gameq/protocols/Hll.php} | 42 +- .../gameq/protocols}/Hurtworld.php | 0 .../gameq/protocols}/Insurgencysand.php | 0 .../gameq/protocols}/Jediacademy.php | 0 .../gameq/protocols}/Jedioutcast.php | 0 .../gameq/protocols}/Justcause2.php | 0 .../gameq/protocols}/Justcause3.php | 0 .../gameq/protocols}/Killingfloor2.php | 0 .../gameq/protocols/Kingpin.php} | 8 +- .../gameq/protocols}/Lhmp.php | 0 .../gameq/protocols}/Minecraftpe.php | 0 .../gameq/protocols/Miscreated.php} | 39 +- .../gameq/protocols/Modiverse.php} | 9 +- .../gameq/protocols}/Mordhau.php | 0 .../gameq/protocols/Of.php} | 11 +- .../gameq_v2/gameq/protocols/Openttd.php | 183 +++ .../gameq/protocols}/Pixark.php | 0 .../gameq/protocols/Postscriptum.php} | 14 +- .../gameq/protocols}/Projectrealitybf2.php | 0 .../gameq/protocols}/Quakelive.php | 0 .../gameq/protocols}/Redorchestraostfront.php | 0 .../gameq/protocols/Rf2.php} | 12 +- .../gameq/protocols}/Risingstorm2.php | 0 .../gameq/protocols/Sco.php} | 16 +- .../gameq/protocols}/Serioussam.php | 0 .../gameq/protocols}/Sevendaystodie.php | 0 .../gameq/protocols}/Ship.php | 0 .../gameq/protocols}/Spaceengineers.php | 0 .../gameq/protocols}/Squad.php | 0 .../gameq/protocols}/Starmade.php | 0 .../gameq_v2/gameq/protocols/Stormworks.php | 50 + .../gameq/protocols}/Swat4.php | 0 .../gameq/protocols}/Theforrest.php | 0 .../gameq/protocols}/Tibia.php | 0 .../gameq/protocols}/Unturned.php | 0 .../gameq/protocols}/Urbanterror.php | 0 .../gameq/protocols}/Valheim.php | 0 .../gameq/protocols/Vrising.php} | 10 +- .../gameq/protocols}/Won.php | 0 .../gameq/protocols}/Wurm.php | 0 .../gameq/protocols/Zomboid.php} | 9 +- third_party/gameq_v2/gameq/protocols/aa.php | 32 - third_party/gameq_v2/gameq/protocols/aa3.php | 41 +- .../gameq_v2/gameq/protocols/aa3pre32.php | 425 ------ .../gameq_v2/gameq/protocols/alienswarm.php | 28 - third_party/gameq_v2/gameq/protocols/aoc.php | 28 - .../gameq_v2/gameq/protocols/armedassault.php | 30 - .../gameq/protocols/armedassault2.php | 44 - .../gameq/protocols/armedassault2oa.php | 46 +- .../gameq/protocols/armedassault3.php | 31 +- third_party/gameq_v2/gameq/protocols/ase.php | 263 ++-- third_party/gameq_v2/gameq/protocols/avp.php | 30 - third_party/gameq_v2/gameq/protocols/avp2.php | 32 - .../gameq_v2/gameq/protocols/bf1942.php | 84 +- third_party/gameq_v2/gameq/protocols/bf2.php | 106 +- .../gameq_v2/gameq/protocols/bf2142.php | 30 - third_party/gameq_v2/gameq/protocols/bf3.php | 547 ++++---- third_party/gameq_v2/gameq/protocols/bf4.php | 229 ++-- .../gameq_v2/gameq/protocols/bfbc2.php | 457 ++++--- third_party/gameq_v2/gameq/protocols/bfv.php | 30 - .../gameq_v2/gameq/protocols/brink.php | 38 +- third_party/gameq_v2/gameq/protocols/cod.php | 29 +- third_party/gameq_v2/gameq/protocols/cod2.php | 28 +- third_party/gameq_v2/gameq/protocols/cod4.php | 28 +- .../gameq_v2/gameq/protocols/codmw3.php | 46 +- .../gameq_v2/gameq/protocols/coduo.php | 39 +- .../gameq_v2/gameq/protocols/codwaw.php | 39 +- third_party/gameq_v2/gameq/protocols/core.php | 708 ---------- .../gameq_v2/gameq/protocols/crysis.php | 39 +- .../gameq_v2/gameq/protocols/crysis2.php | 39 +- .../gameq/protocols/crysiswarhead.php | 30 - .../gameq_v2/gameq/protocols/crysiswars.php | 39 +- third_party/gameq_v2/gameq/protocols/cs16.php | 62 +- third_party/gameq_v2/gameq/protocols/cscz.php | 50 +- third_party/gameq_v2/gameq/protocols/csgo.php | 31 +- third_party/gameq_v2/gameq/protocols/css.php | 28 +- .../gameq_v2/gameq/protocols/cube2.php | 175 --- third_party/gameq_v2/gameq/protocols/dayz.php | 56 +- .../gameq_v2/gameq/protocols/dayzmod.php | 33 +- third_party/gameq_v2/gameq/protocols/dod.php | 33 +- third_party/gameq_v2/gameq/protocols/dods.php | 28 +- .../gameq_v2/gameq/protocols/doom3.php | 300 +++-- third_party/gameq_v2/gameq/protocols/et.php | 29 +- third_party/gameq_v2/gameq/protocols/etqw.php | 361 +++--- third_party/gameq_v2/gameq/protocols/fear.php | 30 - third_party/gameq_v2/gameq/protocols/ffe.php | 31 +- third_party/gameq_v2/gameq/protocols/ffow.php | 413 +++--- third_party/gameq_v2/gameq/protocols/fof.php | 36 +- .../gameq_v2/gameq/protocols/gamespy.php | 305 ++--- .../gameq_v2/gameq/protocols/gamespy2.php | 386 +++--- .../gameq_v2/gameq/protocols/gamespy3.php | 608 ++++----- .../gameq_v2/gameq/protocols/gamespy4.php | 12 +- third_party/gameq_v2/gameq/protocols/gmod.php | 28 +- third_party/gameq_v2/gameq/protocols/gore.php | 30 - third_party/gameq_v2/gameq/protocols/graw.php | 30 - .../gameq_v2/gameq/protocols/graw2.php | 30 - .../gameq_v2/gameq/protocols/hl2dm.php | 28 +- third_party/gameq_v2/gameq/protocols/hldm.php | 28 - .../gameq_v2/gameq/protocols/homefront.php | 28 - third_party/gameq_v2/gameq/protocols/http.php | 51 +- .../gameq_v2/gameq/protocols/insurgency.php | 28 +- third_party/gameq_v2/gameq/protocols/jc2.php | 60 - .../gameq_v2/gameq/protocols/killingfloor.php | 110 +- third_party/gameq_v2/gameq/protocols/l4d.php | 28 +- third_party/gameq_v2/gameq/protocols/l4d2.php | 28 +- third_party/gameq_v2/gameq/protocols/m2mp.php | 281 ++-- .../gameq_v2/gameq/protocols/minecraft.php | 66 +- .../gameq_v2/gameq/protocols/minequery.php | 133 -- .../gameq_v2/gameq/protocols/mohaa.php | 75 +- .../gameq_v2/gameq/protocols/mohsh.php | 30 - .../gameq_v2/gameq/protocols/mohwf.php | 131 -- third_party/gameq_v2/gameq/protocols/mta.php | 55 +- .../gameq_v2/gameq/protocols/mumble.php | 303 +++-- .../gameq_v2/gameq/protocols/nmrih.php | 28 +- third_party/gameq_v2/gameq/protocols/ns.php | 28 - third_party/gameq_v2/gameq/protocols/ns2.php | 42 +- .../gameq_v2/gameq/protocols/projectcars.php | 28 - .../gameq_v2/gameq/protocols/quake2.php | 346 ++--- .../gameq_v2/gameq/protocols/quake3.php | 348 ++--- .../gameq_v2/gameq/protocols/quake4.php | 80 +- .../gameq_v2/gameq/protocols/redeclipse.php | 212 --- .../gameq_v2/gameq/protocols/redfaction.php | 121 -- .../gameq_v2/gameq/protocols/redorchestra.php | 30 - .../gameq/protocols/redorchestra2.php | 38 +- third_party/gameq_v2/gameq/protocols/rtcw.php | 30 - third_party/gameq_v2/gameq/protocols/rust.php | 66 +- third_party/gameq_v2/gameq/protocols/samp.php | 412 +++--- third_party/gameq_v2/gameq/protocols/sof2.php | 45 +- .../gameq_v2/gameq/protocols/soldat.php | 55 +- .../gameq_v2/gameq/protocols/source.php | 769 ++++++----- .../gameq_v2/gameq/protocols/stalker.php | 30 - .../gameq_v2/gameq/protocols/starbound.php | 33 - .../gameq_v2/gameq/protocols/teamspeak2.php | 494 ++++--- .../gameq_v2/gameq/protocols/teamspeak3.php | 587 ++++----- .../gameq_v2/gameq/protocols/teeworlds.php | 174 ++- .../gameq_v2/gameq/protocols/terraria.php | 55 +- third_party/gameq_v2/gameq/protocols/tf2.php | 28 +- third_party/gameq_v2/gameq/protocols/tfc.php | 28 - .../gameq_v2/gameq/protocols/tribes2.php | 204 --- .../gameq_v2/gameq/protocols/tshock.php | 132 +- .../gameq_v2/gameq/protocols/unreal2.php | 446 +++---- third_party/gameq_v2/gameq/protocols/ut.php | 57 +- .../gameq_v2/gameq/protocols/ut2004.php | 26 +- third_party/gameq_v2/gameq/protocols/ut3.php | 142 +- .../gameq_v2/gameq/protocols/ventrilo.php | 1141 ++++++++++++----- .../gameq_v2/gameq/protocols/warsow.php | 103 +- .../gameq_v2/gameq/protocols/zombiemaster.php | 28 - third_party/gameq_v2/gameq/protocols/zps.php | 28 - .../Query => gameq_v2/gameq/query}/Core.php | 0 .../Query => gameq_v2/gameq/query}/Native.php | 0 third_party/gameq_v2/gameq/result.php | 43 +- third_party/gameq_v3.1/GameQ/Buffer.php | 526 -------- .../GameQ/Protocols/Armedassault3.php | 32 - .../gameq_v3.1/GameQ/Protocols/Ase.php | 217 ---- .../gameq_v3.1/GameQ/Protocols/Bf2.php | 98 -- .../gameq_v3.1/GameQ/Protocols/Bf3.php | 348 ----- .../gameq_v3.1/GameQ/Protocols/Bf4.php | 114 -- .../gameq_v3.1/GameQ/Protocols/Bfbc2.php | 326 ----- .../gameq_v3.1/GameQ/Protocols/Cod2.php | 42 - .../gameq_v3.1/GameQ/Protocols/Cod4.php | 42 - .../gameq_v3.1/GameQ/Protocols/Coduo.php | 43 - .../gameq_v3.1/GameQ/Protocols/Codwaw.php | 43 - .../gameq_v3.1/GameQ/Protocols/Crysiswars.php | 43 - .../gameq_v3.1/GameQ/Protocols/Cs16.php | 69 - .../gameq_v3.1/GameQ/Protocols/Cscz.php | 45 - .../gameq_v3.1/GameQ/Protocols/Dayz.php | 66 - .../gameq_v3.1/GameQ/Protocols/Dayzmod.php | 44 - .../gameq_v3.1/GameQ/Protocols/Etqw.php | 234 ---- .../gameq_v3.1/GameQ/Protocols/Ffe.php | 43 - .../gameq_v3.1/GameQ/Protocols/Ffow.php | 243 ---- .../gameq_v3.1/GameQ/Protocols/Gamespy.php | 181 --- .../gameq_v3.1/GameQ/Protocols/Gamespy2.php | 269 ---- .../gameq_v3.1/GameQ/Protocols/Gamespy3.php | 340 ----- .../gameq_v3.1/GameQ/Protocols/Gamespy4.php | 34 - .../gameq_v3.1/GameQ/Protocols/Http.php | 67 - .../gameq_v3.1/GameQ/Protocols/Insurgency.php | 42 - .../GameQ/Protocols/Killingfloor.php | 96 -- .../gameq_v3.1/GameQ/Protocols/L4d.php | 42 - .../gameq_v3.1/GameQ/Protocols/L4d2.php | 42 - .../gameq_v3.1/GameQ/Protocols/Minecraft.php | 87 -- .../gameq_v3.1/GameQ/Protocols/Mta.php | 59 - .../gameq_v3.1/GameQ/Protocols/Mumble.php | 194 --- .../gameq_v3.1/GameQ/Protocols/Quake2.php | 219 ---- .../gameq_v3.1/GameQ/Protocols/Quake3.php | 214 ---- .../gameq_v3.1/GameQ/Protocols/Rust.php | 64 - .../gameq_v3.1/GameQ/Protocols/Samp.php | 279 ---- .../gameq_v3.1/GameQ/Protocols/Sof2.php | 49 - .../gameq_v3.1/GameQ/Protocols/Soldat.php | 59 - .../gameq_v3.1/GameQ/Protocols/Source.php | 522 -------- .../gameq_v3.1/GameQ/Protocols/Teamspeak2.php | 290 ----- .../gameq_v3.1/GameQ/Protocols/Teamspeak3.php | 328 ----- .../gameq_v3.1/GameQ/Protocols/Teeworlds.php | 181 --- .../gameq_v3.1/GameQ/Protocols/Terraria.php | 59 - .../gameq_v3.1/GameQ/Protocols/Tf2.php | 42 - .../gameq_v3.1/GameQ/Protocols/Tshock.php | 157 --- .../gameq_v3.1/GameQ/Protocols/Unreal2.php | 246 ---- .../gameq_v3.1/GameQ/Protocols/Ut2004.php | 42 - .../gameq_v3.1/GameQ/Protocols/Ut3.php | 133 -- .../gameq_v3.1/GameQ/Protocols/Ventrilo.php | 877 ------------- third_party/gameq_v3.1/GameQ/Result.php | 130 -- 289 files changed, 7644 insertions(+), 16934 deletions(-) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Aa3.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Aapg.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Avorion.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Barotrauma.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Blackmesa.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Citadel.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Codmw2.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Doom3.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Fof.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Had2.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Halo.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Hl1.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Hll.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Kingpin.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/M2mp.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Miscreated.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Modiverse.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Nmrih.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Of.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Openttd.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Postscriptum.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Quake4.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Rf2.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Sco.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Stormworks.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Vrising.php (100%) rename third_party/{gameq_v3.1 => gameq}/GameQ/Protocols/Zomboid.php (100%) delete mode 100644 third_party/gameq/LICENSE.lgpl rename third_party/{gameq_v3.1/GameQ => gameq_v2/gameq}/Autoloader.php (100%) rename third_party/{gameq_v3.1/GameQ => gameq_v2/gameq}/GameQ.php (100%) rename third_party/{gameq_v3.1/GameQ => gameq_v2/gameq}/Protocol.php (100%) rename third_party/{gameq_v3.1/GameQ => gameq_v2/gameq}/Server.php (100%) rename third_party/{gameq_v3.1/GameQ/Exception => gameq_v2/gameq/exception}/Protocol.php (100%) rename third_party/{gameq_v3.1/GameQ/Exception => gameq_v2/gameq/exception}/Query.php (100%) rename third_party/{gameq_v3.1/GameQ/Exception => gameq_v2/gameq/exception}/Server.php (100%) delete mode 100644 third_party/gameq_v2/gameq/filters.php rename third_party/{gameq_v3.1/GameQ/Filters => gameq_v2/gameq/filters}/Base.php (100%) rename third_party/{gameq_v3.1/GameQ/Filters => gameq_v2/gameq/filters}/Normalize.php (100%) rename third_party/{gameq_v3.1/GameQ/Filters => gameq_v2/gameq/filters}/Secondstohuman.php (100%) rename third_party/{gameq_v3.1/GameQ/Filters => gameq_v2/gameq/filters}/Stripcolors.php (100%) rename third_party/{gameq_v3.1/GameQ/Filters => gameq_v2/gameq/filters}/Test.php (100%) delete mode 100644 third_party/gameq_v2/gameq/filters/core.php delete mode 100644 third_party/gameq_v2/gameq/filters/normalise.php delete mode 100644 third_party/gameq_v2/gameq/filters/stripcolor.php delete mode 100644 third_party/gameq_v2/gameq/protocols.php delete mode 100644 third_party/gameq_v2/gameq/protocols/7d2d.php rename third_party/{gameq_v3.1/GameQ/Protocols/Dods.php => gameq_v2/gameq/protocols/Aapg.php} (88%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Arkse.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Arma.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Arma3.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Atlas.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Dod.php => gameq_v2/gameq/protocols/Avorion.php} (80%) rename third_party/{gameq_v3.1/GameQ/Protocols/Ns2.php => gameq_v2/gameq/protocols/Barotrauma.php} (85%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Batt1944.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Bfh.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Crysis2.php => gameq_v2/gameq/protocols/Blackmesa.php} (84%) rename third_party/{gameq_v3.1/GameQ/Protocols/Cod.php => gameq_v2/gameq/protocols/Citadel.php} (84%) rename third_party/{gameq_v3.1/GameQ/Protocols/Warsow.php => gameq_v2/gameq/protocols/Codmw2.php} (61%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Conanexiles.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Contagion.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Cs15.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Cs2d.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Dal.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Dow.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Eco.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Egs.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Grav.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Gta5m.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Gtan.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Gtar.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Ut.php => gameq_v2/gameq/protocols/Had2.php} (77%) rename third_party/{gameq_v3.1/GameQ/Protocols/Crysis.php => gameq_v2/gameq/protocols/Halo.php} (83%) rename third_party/{gameq_v3.1/GameQ/Protocols/Css.php => gameq_v2/gameq/protocols/Hl1.php} (87%) rename third_party/{gameq_v3.1/GameQ/Protocols/Bf1942.php => gameq_v2/gameq/protocols/Hll.php} (63%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Hurtworld.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Insurgencysand.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Jediacademy.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Jedioutcast.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Justcause2.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Justcause3.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Killingfloor2.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Et.php => gameq_v2/gameq/protocols/Kingpin.php} (86%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Lhmp.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Minecraftpe.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Mohaa.php => gameq_v2/gameq/protocols/Miscreated.php} (68%) rename third_party/{gameq_v3.1/GameQ/Protocols/Gmod.php => gameq_v2/gameq/protocols/Modiverse.php} (85%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Mordhau.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Hl2dm.php => gameq_v2/gameq/protocols/Of.php} (82%) create mode 100644 third_party/gameq_v2/gameq/protocols/Openttd.php rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Pixark.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Armedassault2oa.php => gameq_v2/gameq/protocols/Postscriptum.php} (81%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Projectrealitybf2.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Quakelive.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Redorchestraostfront.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Codmw3.php => gameq_v2/gameq/protocols/Rf2.php} (84%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Risingstorm2.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Redorchestra2.php => gameq_v2/gameq/protocols/Sco.php} (77%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Serioussam.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Sevendaystodie.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Ship.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Spaceengineers.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Squad.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Starmade.php (100%) create mode 100644 third_party/gameq_v2/gameq/protocols/Stormworks.php rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Swat4.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Theforrest.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Tibia.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Unturned.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Urbanterror.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Valheim.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Brink.php => gameq_v2/gameq/protocols/Vrising.php} (88%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Won.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols => gameq_v2/gameq/protocols}/Wurm.php (100%) rename third_party/{gameq_v3.1/GameQ/Protocols/Csgo.php => gameq_v2/gameq/protocols/Zomboid.php} (87%) delete mode 100644 third_party/gameq_v2/gameq/protocols/aa.php delete mode 100644 third_party/gameq_v2/gameq/protocols/aa3pre32.php delete mode 100644 third_party/gameq_v2/gameq/protocols/alienswarm.php delete mode 100644 third_party/gameq_v2/gameq/protocols/aoc.php delete mode 100644 third_party/gameq_v2/gameq/protocols/armedassault.php delete mode 100644 third_party/gameq_v2/gameq/protocols/armedassault2.php delete mode 100644 third_party/gameq_v2/gameq/protocols/avp.php delete mode 100644 third_party/gameq_v2/gameq/protocols/avp2.php delete mode 100644 third_party/gameq_v2/gameq/protocols/bf2142.php delete mode 100644 third_party/gameq_v2/gameq/protocols/bfv.php delete mode 100644 third_party/gameq_v2/gameq/protocols/core.php delete mode 100644 third_party/gameq_v2/gameq/protocols/crysiswarhead.php delete mode 100644 third_party/gameq_v2/gameq/protocols/cube2.php delete mode 100644 third_party/gameq_v2/gameq/protocols/fear.php delete mode 100644 third_party/gameq_v2/gameq/protocols/gore.php delete mode 100644 third_party/gameq_v2/gameq/protocols/graw.php delete mode 100644 third_party/gameq_v2/gameq/protocols/graw2.php delete mode 100644 third_party/gameq_v2/gameq/protocols/hldm.php delete mode 100644 third_party/gameq_v2/gameq/protocols/homefront.php delete mode 100644 third_party/gameq_v2/gameq/protocols/jc2.php delete mode 100644 third_party/gameq_v2/gameq/protocols/minequery.php delete mode 100644 third_party/gameq_v2/gameq/protocols/mohsh.php delete mode 100644 third_party/gameq_v2/gameq/protocols/mohwf.php delete mode 100644 third_party/gameq_v2/gameq/protocols/ns.php delete mode 100644 third_party/gameq_v2/gameq/protocols/projectcars.php delete mode 100644 third_party/gameq_v2/gameq/protocols/redeclipse.php delete mode 100644 third_party/gameq_v2/gameq/protocols/redfaction.php delete mode 100644 third_party/gameq_v2/gameq/protocols/redorchestra.php delete mode 100644 third_party/gameq_v2/gameq/protocols/rtcw.php delete mode 100644 third_party/gameq_v2/gameq/protocols/stalker.php delete mode 100644 third_party/gameq_v2/gameq/protocols/starbound.php delete mode 100644 third_party/gameq_v2/gameq/protocols/tfc.php delete mode 100644 third_party/gameq_v2/gameq/protocols/tribes2.php delete mode 100644 third_party/gameq_v2/gameq/protocols/zombiemaster.php delete mode 100644 third_party/gameq_v2/gameq/protocols/zps.php rename third_party/{gameq_v3.1/GameQ/Query => gameq_v2/gameq/query}/Core.php (100%) rename third_party/{gameq_v3.1/GameQ/Query => gameq_v2/gameq/query}/Native.php (100%) delete mode 100644 third_party/gameq_v3.1/GameQ/Buffer.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Armedassault3.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Ase.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Bf2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Bf3.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Bf4.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Bfbc2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Cod2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Cod4.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Coduo.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Codwaw.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Crysiswars.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Cs16.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Cscz.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Dayz.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Dayzmod.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Etqw.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Ffe.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Ffow.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Gamespy.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Gamespy2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Gamespy3.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Gamespy4.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Http.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Insurgency.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Killingfloor.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/L4d.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/L4d2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Minecraft.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Mta.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Mumble.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Quake2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Quake3.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Rust.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Samp.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Sof2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Soldat.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Source.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Teamspeak2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Teamspeak3.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Teeworlds.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Terraria.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Tf2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Tshock.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Unreal2.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Ut2004.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Ut3.php delete mode 100644 third_party/gameq_v3.1/GameQ/Protocols/Ventrilo.php delete mode 100644 third_party/gameq_v3.1/GameQ/Result.php diff --git a/stuff/methods/functions_gs.php b/stuff/methods/functions_gs.php index 5fe1a0fb..b94b64bc 100644 --- a/stuff/methods/functions_gs.php +++ b/stuff/methods/functions_gs.php @@ -284,8 +284,10 @@ if (!function_exists('eacchange')) { // Figure out the class name $class_name = 'GameQ_Protocols_' . ucfirst(pathinfo($entry, PATHINFO_FILENAME)); + // Lets get some info on the class - $reflection = new ReflectionClass($class_name); + if (method_exists($class_name, "get_site_editor_type")) { + $reflection = new \ReflectionClass( $class_name ); // Check to make sure we can actually load the class try { @@ -307,7 +309,10 @@ if (!function_exists('eacchange')) { } catch (ReflectionException $e) { $errors['reflection'] = $e->getMessage(); - } + + + } + } } // Close the directory diff --git a/third_party/gameq/GameQ/Buffer.php b/third_party/gameq/GameQ/Buffer.php index ca23eb6d..a080e427 100644 --- a/third_party/gameq/GameQ/Buffer.php +++ b/third_party/gameq/GameQ/Buffer.php @@ -262,8 +262,8 @@ class Buffer * * If not found, return everything * - * @param $delims - * @param null $delimfound + * @param $delims + * @param null|string &$delimfound * * @return string * @throws \GameQ\Exception\Protocol @@ -380,25 +380,30 @@ class Buffer * @return int * @throws \GameQ\Exception\Protocol */ - public function readInt32() + public function readInt32($length = 4) { - // Change the integer type we are looking up + $littleEndian = null; switch ($this->number_type) { case self::NUMBER_TYPE_BIGENDIAN: - $type = 'Nint'; + $type = 'N'; + $littleEndian = false; break; case self::NUMBER_TYPE_LITTLEENDIAN: - $type = 'Vint'; + $type = 'V'; + $littleEndian = true; break; default: - $type = 'Lint'; + $type = 'L'; } + // read from the buffer and append/prepend empty bytes for shortened int32 + $corrected = $this->read($length); + // Unpack the number - $int = unpack($type, $this->read(4)); + $int = unpack($type . 'int', self::extendBinaryString($corrected, 4, $littleEndian)); return $int['int']; } @@ -498,4 +503,24 @@ class Buffer return $float['float']; } + + private static function extendBinaryString($input, $length = 4, $littleEndian = null) + { + if (is_null($littleEndian)) { + $littleEndian = self::isLittleEndian(); + } + + $extension = str_repeat(pack($littleEndian ? 'V' : 'N', 0b0000), $length - strlen($input)); + + if ($littleEndian) { + return $input . $extension; + } else { + return $extension . $input; + } + } + + private static function isLittleEndian() + { + return 0x00FF === current(unpack('v', pack('S', 0x00FF))); + } } diff --git a/third_party/gameq/GameQ/Filters/Base.php b/third_party/gameq/GameQ/Filters/Base.php index 1a3f4e59..501f77d4 100644 --- a/third_party/gameq/GameQ/Filters/Base.php +++ b/third_party/gameq/GameQ/Filters/Base.php @@ -46,6 +46,11 @@ abstract class Base $this->options = $options; } + public function getOptions() + { + return $this->options; + } + /** * Apply the filter to the data * diff --git a/third_party/gameq/GameQ/Filters/Stripcolors.php b/third_party/gameq/GameQ/Filters/Stripcolors.php index 58953042..1760b73a 100644 --- a/third_party/gameq/GameQ/Filters/Stripcolors.php +++ b/third_party/gameq/GameQ/Filters/Stripcolors.php @@ -67,6 +67,9 @@ class Stripcolors extends Base case 'source': array_walk_recursive($result, [$this, 'stripSource']); break; + case 'gta5m': + array_walk_recursive($result, [$this, 'stripQuake']); + break; } /*$data['filtered'][ $server->id() ] = $result; @@ -93,16 +96,6 @@ class Stripcolors extends Base $string = preg_replace('#(\^.)#', '', $string); } - /** - * Strip color codes from Unreal based games - * - * @param string $string - */ - protected function stripUnreal(&$string) - { - $string = preg_replace('/\x1b.../', '', $string); - } - /** * Strip color codes from Source based games * @@ -112,4 +105,14 @@ class Stripcolors extends Base { $string = strip_tags($string); } + + /** + * Strip color codes from Unreal based games + * + * @param string $string + */ + protected function stripUnreal(&$string) + { + $string = preg_replace('/\x1b.../', '', $string); + } } diff --git a/third_party/gameq/GameQ/GameQ.php b/third_party/gameq/GameQ/GameQ.php index fdc8ef70..a4ec2036 100644 --- a/third_party/gameq/GameQ/GameQ.php +++ b/third_party/gameq/GameQ/GameQ.php @@ -160,6 +160,16 @@ class GameQ return true; } + public function getServers() + { + return $this->servers; + } + + public function getOptions() + { + return $this->options; + } + /** * Chainable call to __set, uses set as the actual setter * diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Aa3.php b/third_party/gameq/GameQ/Protocols/Aa3.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Aa3.php rename to third_party/gameq/GameQ/Protocols/Aa3.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Aapg.php b/third_party/gameq/GameQ/Protocols/Aapg.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Aapg.php rename to third_party/gameq/GameQ/Protocols/Aapg.php diff --git a/third_party/gameq/GameQ/Protocols/Arma3.php b/third_party/gameq/GameQ/Protocols/Arma3.php index 51d6e5da..fdc2cba4 100644 --- a/third_party/gameq/GameQ/Protocols/Arma3.php +++ b/third_party/gameq/GameQ/Protocols/Arma3.php @@ -1,5 +1,4 @@ * @author Austin Bischoff + * @author Memphis017 */ -class Arma3 extends Armedassault2oa +class Arma3 extends Source { + // Base DLC names + const BASE_DLC_KART = 'Karts'; + const BASE_DLC_MARKSMEN = 'Marksmen'; + const BASE_DLC_HELI = 'Helicopters'; + const BASE_DLC_CURATOR = 'Curator'; + const BASE_DLC_EXPANSION = 'Expansion'; + const BASE_DLC_JETS = 'Jets'; + const BASE_DLC_ORANGE = 'Laws of War'; + const BASE_DLC_ARGO = 'Malden'; + const BASE_DLC_TACOPS = 'Tac-Ops'; + const BASE_DLC_TANKS = 'Tanks'; + const BASE_DLC_CONTACT = 'Contact'; + const BASE_DLC_ENOCH = 'Contact (Platform)'; + + // Special + const BASE_DLC_AOW = 'Art of War'; + + // Creator DLC names + const CREATOR_DLC_GM = 'Global Mobilization'; + const CREATOR_DLC_VN = 'S.O.G. Prairie Fire'; + const CREATOR_DLC_CSLA = 'ČSLA - Iron Curtain'; + const CREATOR_DLC_WS = 'Western Sahara'; + + /** + * DLC Flags/Bits as defined in the documentation. + * + * @see https://community.bistudio.com/wiki/Arma_3:_ServerBrowserProtocol3 + * + * @var array + */ + protected $dlcFlags = [ + 0b0000000000000001 => self::BASE_DLC_KART, + 0b0000000000000010 => self::BASE_DLC_MARKSMEN, + 0b0000000000000100 => self::BASE_DLC_HELI, + 0b0000000000001000 => self::BASE_DLC_CURATOR, + 0b0000000000010000 => self::BASE_DLC_EXPANSION, + 0b0000000000100000 => self::BASE_DLC_JETS, + 0b0000000001000000 => self::BASE_DLC_ORANGE, + 0b0000000010000000 => self::BASE_DLC_ARGO, + 0b0000000100000000 => self::BASE_DLC_TACOPS, + 0b0000001000000000 => self::BASE_DLC_TANKS, + 0b0000010000000000 => self::BASE_DLC_CONTACT, + 0b0000100000000000 => self::BASE_DLC_ENOCH, + 0b0001000000000000 => self::BASE_DLC_AOW, + 0b0010000000000000 => 'Unknown', + 0b0100000000000000 => 'Unknown', + 0b1000000000000000 => 'Unknown', + ]; /** * String name of this protocol class @@ -42,4 +94,128 @@ class Arma3 extends Armedassault2oa * @type string */ protected $name_long = "Arma3"; + + /** + * Query port = client_port + 1 + * + * @type int + */ + protected $port_diff = 1; + + /** + * Process the rules since Arma3 changed their response for rules + * + * @param Buffer $buffer + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + protected function processRules(Buffer $buffer) + { + // Total number of packets, burn it + $buffer->readInt16(); + + // Will hold the data string + $data = ''; + + // Loop until we run out of strings + while ($buffer->getLength()) { + // Burn the delimiters (i.e. \x01\x04\x00) + $buffer->readString(); + + // Add the data to the string, we are reassembling it + $data .= $buffer->readString(); + } + + // Restore escaped sequences + $data = str_replace(["\x01\x01", "\x01\x02", "\x01\x03"], ["\x01", "\x00", "\xFF"], $data); + + // Make a new buffer with the reassembled data + $responseBuffer = new Buffer($data); + + // Kill the old buffer, should be empty + unset($buffer, $data); + + // Set the result to a new result instance + $result = new Result(); + + // Get results + $result->add('rules_protocol_version', $responseBuffer->readInt8()); // read protocol version + $result->add('overflow', $responseBuffer->readInt8()); // Read overflow flags + $dlcByte = $responseBuffer->readInt8(); // Grab DLC byte 1 and use it later + $dlcByte2 = $responseBuffer->readInt8(); // Grab DLC byte 2 and use it later + $dlcBits = ($dlcByte2 << 8) | $dlcByte; // concatenate DLC bits to 16 Bit int + + // Grab difficulty so we can man handle it... + $difficulty = $responseBuffer->readInt8(); + + // Process difficulty + $result->add('3rd_person', $difficulty >> 7); + $result->add('advanced_flight_mode', ($difficulty >> 6) & 1); + $result->add('difficulty_ai', ($difficulty >> 3) & 3); + $result->add('difficulty_level', $difficulty & 3); + + unset($difficulty); + + // Crosshair + $result->add('crosshair', $responseBuffer->readInt8()); + + // Loop over the base DLC bits so we can pull in the info for the DLC (if enabled) + foreach ($this->dlcFlags as $dlcFlag => $dlcName) { + // Check that the DLC bit is enabled + if (($dlcBits & $dlcFlag) === $dlcFlag) { + // Add the DLC to the list + $result->addSub('dlcs', 'name', $dlcName); + $result->addSub('dlcs', 'hash', dechex($responseBuffer->readInt32())); + } + } + + // Read the mount of mods, these include DLC as well as Creator DLC and custom modifications + $modCount = $responseBuffer->readInt8(); + + // Add mod count + $result->add('mod_count', $modCount); + + // Loop over the mods + while ($modCount) { + // Read the mods hash + $result->addSub('mods', 'hash', dechex($responseBuffer->readInt32())); + + // Get the information byte containing DLC flag and steamId length + $infoByte = $responseBuffer->readInt8(); + + // Determine isDLC by flag, first bit in upper nibble + $result->addSub('mods', 'dlc', ($infoByte & 0b00010000) === 0b00010000); + + // Read the steam id of the mod/CDLC (might be less than 4 bytes) + $result->addSub('mods', 'steam_id', $responseBuffer->readInt32($infoByte & 0x0F)); + + // Read the name of the mod + $result->addSub('mods', 'name', $responseBuffer->readPascalString(0, true) ?: 'Unknown'); + + --$modCount; + } + + // No longer needed + unset($dlcByte, $dlcByte2, $dlcBits); + + // Get the signatures count + $signatureCount = $responseBuffer->readInt8(); + $result->add('signature_count', $signatureCount); + + // Make signatures array + $signatures = []; + + // Loop until we run out of signatures + for ($x = 0; $x < $signatureCount; $x++) { + $signatures[] = $responseBuffer->readPascalString(0, true); + } + + // Add as a simple array + $result->add('signatures', $signatures); + + unset($responseBuffer, $signatureCount, $signatures, $x); + + return $result->fetch(); + } } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Avorion.php b/third_party/gameq/GameQ/Protocols/Avorion.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Avorion.php rename to third_party/gameq/GameQ/Protocols/Avorion.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Barotrauma.php b/third_party/gameq/GameQ/Protocols/Barotrauma.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Barotrauma.php rename to third_party/gameq/GameQ/Protocols/Barotrauma.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Blackmesa.php b/third_party/gameq/GameQ/Protocols/Blackmesa.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Blackmesa.php rename to third_party/gameq/GameQ/Protocols/Blackmesa.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Citadel.php b/third_party/gameq/GameQ/Protocols/Citadel.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Citadel.php rename to third_party/gameq/GameQ/Protocols/Citadel.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Codmw2.php b/third_party/gameq/GameQ/Protocols/Codmw2.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Codmw2.php rename to third_party/gameq/GameQ/Protocols/Codmw2.php diff --git a/third_party/gameq/GameQ/Protocols/Dayzmod.php b/third_party/gameq/GameQ/Protocols/Dayzmod.php index 80b798e3..2ce1076d 100644 --- a/third_party/gameq/GameQ/Protocols/Dayzmod.php +++ b/third_party/gameq/GameQ/Protocols/Dayzmod.php @@ -1,5 +1,4 @@ options[Server::SERVER_OPTIONS_QUERY_PORT]) + if (!isset($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) || empty($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) ) { throw new Exception(__METHOD__ . " Missing required setting '" . Server::SERVER_OPTIONS_QUERY_PORT . "'."); diff --git a/third_party/gameq/GameQ/Protocols/Valheim.php b/third_party/gameq/GameQ/Protocols/Valheim.php index 106a66e8..18469229 100644 --- a/third_party/gameq/GameQ/Protocols/Valheim.php +++ b/third_party/gameq/GameQ/Protocols/Valheim.php @@ -19,10 +19,9 @@ namespace GameQ\Protocols; /** - * Class Valheim + * Valheim Protocol Class * * @package GameQ\Protocols - * */ class Valheim extends Source { @@ -32,10 +31,18 @@ class Valheim extends Source * @type string */ protected $name = 'valheim'; + /** * Longer string name of this protocol class * * @type string */ protected $name_long = "Valheim"; + + /** + * query_port = client_port + 1 + * + * @type int + */ + protected $port_diff = 1; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Vrising.php b/third_party/gameq/GameQ/Protocols/Vrising.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Vrising.php rename to third_party/gameq/GameQ/Protocols/Vrising.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Zomboid.php b/third_party/gameq/GameQ/Protocols/Zomboid.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Zomboid.php rename to third_party/gameq/GameQ/Protocols/Zomboid.php diff --git a/third_party/gameq/GameQ/Query/Core.php b/third_party/gameq/GameQ/Query/Core.php index 5eb08ad0..fd1949da 100644 --- a/third_party/gameq/GameQ/Query/Core.php +++ b/third_party/gameq/GameQ/Query/Core.php @@ -119,6 +119,31 @@ abstract class Core $this->blocking = false; } + public function getTransport() + { + return $this->transport; + } + + public function getIp() + { + return $this->ip; + } + + public function getPort() + { + return $this->port; + } + + public function getTimeout() + { + return $this->timeout; + } + + public function getBlocking() + { + return $this->blocking; + } + /** * Create a new socket * diff --git a/third_party/gameq/GameQ/Server.php b/third_party/gameq/GameQ/Server.php index dff8f77c..1725d461 100644 --- a/third_party/gameq/GameQ/Server.php +++ b/third_party/gameq/GameQ/Server.php @@ -27,7 +27,6 @@ use GameQ\Exception\Server as Exception; */ class Server { - /* * Server array keys */ @@ -203,13 +202,18 @@ class Server ); } - // Validate the IPv4 value, if FALSE is not a valid IP, maybe a hostname. Try to resolve - if (!filter_var($this->ip, FILTER_VALIDATE_IP, ['flags' => FILTER_FLAG_IPV4,]) - && $this->ip === gethostbyname($this->ip) - ) { + // Validate the IPv4 value, if FALSE is not a valid IP, maybe a hostname. + if (! filter_var($this->ip, FILTER_VALIDATE_IP, ['flags' => FILTER_FLAG_IPV4,])) { + // Try to resolve the hostname to IPv4 + $resolved = gethostbyname($this->ip); + // When gethostbyname() fails it returns the original string - // so if ip and the result from gethostbyname() are equal this failed. - throw new Exception("Unable to resolve the host '{$this->ip}' to an IP address."); + if ($this->ip === $resolved) { + // so if ip and the result from gethostbyname() are equal this failed. + throw new Exception("Unable to resolve the host '{$this->ip}' to an IP address."); + } else { + $this->ip = $resolved; + } } } } @@ -258,6 +262,11 @@ class Server return (array_key_exists($key, $this->options)) ? $this->options[$key] : null; } + public function getOptions() + { + return $this->options; + } + /** * Get the ID for this server * diff --git a/third_party/gameq/LICENSE.lgpl b/third_party/gameq/LICENSE.lgpl deleted file mode 100644 index 02bbb60b..00000000 --- a/third_party/gameq/LICENSE.lgpl +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. \ No newline at end of file diff --git a/third_party/gameq_v3.1/GameQ/Autoloader.php b/third_party/gameq_v2/gameq/Autoloader.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Autoloader.php rename to third_party/gameq_v2/gameq/Autoloader.php diff --git a/third_party/gameq_v3.1/GameQ/GameQ.php b/third_party/gameq_v2/gameq/GameQ.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/GameQ.php rename to third_party/gameq_v2/gameq/GameQ.php diff --git a/third_party/gameq_v3.1/GameQ/Protocol.php b/third_party/gameq_v2/gameq/Protocol.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocol.php rename to third_party/gameq_v2/gameq/Protocol.php diff --git a/third_party/gameq_v3.1/GameQ/Server.php b/third_party/gameq_v2/gameq/Server.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Server.php rename to third_party/gameq_v2/gameq/Server.php diff --git a/third_party/gameq_v2/gameq/buffer.php b/third_party/gameq_v2/gameq/buffer.php index bb14ad2f..a080e427 100644 --- a/third_party/gameq_v2/gameq/buffer.php +++ b/third_party/gameq_v2/gameq/buffer.php @@ -3,84 +3,107 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * */ +namespace GameQ; + +use GameQ\Exception\Protocol as Exception; + /** - * Provide an interface for easy manipulation of a server response + * Class Buffer * - * @author Aidan Lister - * @author Tom Buskens - * @version $Revision: 1.4 $ + * Read specific byte sequences from a provided string or Buffer + * + * @package GameQ + * + * @author Austin Bischoff + * @author Aidan Lister + * @author Tom Buskens */ -class GameQ_Buffer +class Buffer { + + /** + * Constants for the byte code types we need to read as + */ + const NUMBER_TYPE_BIGENDIAN = 'be', + NUMBER_TYPE_LITTLEENDIAN = 'le', + NUMBER_TYPE_MACHINE = 'm'; + + /** + * The number type we use for reading integers. Defaults to little endian + * + * @type string + */ + private $number_type = self::NUMBER_TYPE_LITTLEENDIAN; + /** * The original data * - * @var string - * @access public + * @type string */ private $data; /** * The original data * - * @var string - * @access public + * @type int */ private $length; - /** * Position of pointer * - * @var string - * @access public + * @type int */ private $index = 0; - /** * Constructor * - * @param string|array $response The data + * @param string $data + * @param string $number_type */ - public function __construct($data) + public function __construct($data, $number_type = self::NUMBER_TYPE_LITTLEENDIAN) { - $this->data = $data; + + $this->number_type = $number_type; + $this->data = $data; $this->length = strlen($data); } /** * Return all the data * - * @return string|array The data + * @return string The data */ public function getData() { + return $this->data; } /** * Return data currently in the buffer * - * @return string|array The data currently in the buffer + * @return string The data currently in the buffer */ public function getBuffer() { + return substr($this->data, $this->index); } @@ -91,19 +114,23 @@ class GameQ_Buffer */ public function getLength() { + return max($this->length - $this->index, 0); } /** * Read from the buffer * - * @param int $length Length of data to read - * @return string The data read + * @param int $length + * + * @return string + * @throws \GameQ\Exception\Protocol */ public function read($length = 1) { + if (($length + $this->index) > $this->length) { - throw new GameQ_ProtocolsException('Unable to read length={$length} from buffer. Bad protocol format or return?'); + throw new Exception("Unable to read length={$length} from buffer. Bad protocol format or return?"); } $string = substr($this->data, $this->index, $length); @@ -118,13 +145,14 @@ class GameQ_Buffer * Unlike the other read functions, this function actually removes * the character from the buffer. * - * @return string The data read + * @return string */ public function readLast() { - $len = strlen($this->data); - $string = $this->data{strlen($this->data) - 1}; - $this->data = substr($this->data, 0, $len - 1); + + $len = strlen($this->data); + $string = $this->data[strlen($this->data) - 1]; + $this->data = substr($this->data, 0, $len - 1); $this->length -= 1; return $string; @@ -133,24 +161,24 @@ class GameQ_Buffer /** * Look at the buffer, but don't remove * - * @param int $length Length of data to read - * @return string The data read + * @param int $length + * + * @return string */ public function lookAhead($length = 1) { - $string = substr($this->data, $this->index, $length); - return $string; + return substr($this->data, $this->index, $length); } /** * Skip forward in the buffer * - * @param int $length Length of data to skip - * @return void + * @param int $length */ public function skip($length = 1) { + $this->index += $length; } @@ -158,21 +186,22 @@ class GameQ_Buffer * Jump to a specific position in the buffer, * will not jump past end of buffer * - * @param int $index Position to go to - * @return void + * @param $index */ public function jumpto($index) { + $this->index = min($index, $this->length - 1); } /** * Get the current pointer position * - * @return int The current pointer position + * @return int */ public function getPosition() { + return $this->index; } @@ -181,11 +210,14 @@ class GameQ_Buffer * * If not found, return everything * - * @param string $delim Read until this character is reached - * @return string The data read + * @param string $delim + * + * @return string + * @throws \GameQ\Exception\Protocol */ public function readString($delim = "\x00") { + // Get position of delimiter $len = strpos($this->data, $delim, min($this->index, $this->length)); @@ -204,13 +236,15 @@ class GameQ_Buffer /** * Reads a pascal string from the buffer * - * @paran int $offset Number of bits to cut off the end - * @param bool $read_offset True if the data after the offset is - * to be read - * @return string The data read + * @param int $offset Number of bits to cut off the end + * @param bool $read_offset True if the data after the offset is to be read + * + * @return string + * @throws \GameQ\Exception\Protocol */ public function readPascalString($offset = 0, $read_offset = false) { + // Get the proper offset $len = $this->readInt8(); $offset = max($len - $offset, 0); @@ -218,8 +252,7 @@ class GameQ_Buffer // Read the data if ($read_offset) { return $this->read($offset); - } - else { + } else { return substr($this->read($len), 0, $offset); } } @@ -229,16 +262,22 @@ class GameQ_Buffer * * If not found, return everything * - * @param array $delims Read until these characters are reached - * @return string The data read + * @param $delims + * @param null|string &$delimfound + * + * @return string + * @throws \GameQ\Exception\Protocol + * + * @todo: Check to see if this is even used anymore */ public function readStringMulti($delims, &$delimfound = null) { + // Get position of delimiters - $pos = array(); + $pos = []; foreach ($delims as $delim) { - if ($p = strpos($this->data, $delim, min($this->index, $this->length))) { - $pos[] = $p; + if ($index = strpos($this->data, $delim, min($this->index, $this->length))) { + $pos[] = $index; } } @@ -256,141 +295,232 @@ class GameQ_Buffer } /** - * Read a 32-bit unsigned integer + * Read an 8-bit unsigned integer + * + * @return int + * @throws \GameQ\Exception\Protocol */ - public function readInt32() + public function readInt8() { - $int = unpack('Lint', $this->read(4)); + + $int = unpack('Cint', $this->read(1)); + return $int['int']; } /** - * Read a 32-bit signed integer + * Read and 8-bit signed integer + * + * @return int + * @throws \GameQ\Exception\Protocol */ - public function readInt32Signed() + public function readInt8Signed() { - $int = unpack('lint', $this->read(4)); + + $int = unpack('cint', $this->read(1)); return $int['int']; } /** * Read a 16-bit unsigned integer + * + * @return int + * @throws \GameQ\Exception\Protocol */ public function readInt16() { - $int = unpack('Sint', $this->read(2)); + + // Change the integer type we are looking up + switch ($this->number_type) { + case self::NUMBER_TYPE_BIGENDIAN: + $type = 'nint'; + break; + + case self::NUMBER_TYPE_LITTLEENDIAN: + $type = 'vint'; + break; + + default: + $type = 'Sint'; + } + + $int = unpack($type, $this->read(2)); + return $int['int']; } /** * Read a 16-bit signed integer + * + * @return int + * @throws \GameQ\Exception\Protocol */ public function readInt16Signed() { - $int = unpack('sint', $this->read(2)); - return $int['int']; - } - /** - * Read a 16-bit unsigned little endian integer - */ - public function readInt16LE() - { - $int = unpack('vint', $this->read(2)); - return $int['int']; - } + // Read the data into a string + $string = $this->read(2); - /** - * Read a 16-bit unsigned big endian integer - */ - public function readInt16BE() - { - $int = unpack('nint', $this->read(2)); - return $int['int']; - } - - /** - * Read an int8 from the buffer - * - * @return int The data read - */ - public function readInt8() - { - return ord($this->read(1)); - } - - /** - * Read an float32 from the buffer - * - * @return int The data read - */ - public function readFloat32() - { - $float = unpack('ffloat', $this->read(4)); - return $float['float']; - } - - /** - * Conversion to float - * - * @access public - * @param string $string String to convert - * @return float 32 bit float - */ - public function toFloat($string) - { - // Check length - if (strlen($string) !== 4) { - return false; + // For big endian we need to reverse the bytes + if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) { + $string = strrev($string); } - // Convert - $float = unpack('ffloat', $string); - return $float['float']; + $int = unpack('sint', $string); + + unset($string); + + return $int['int']; } /** - * Conversion to integer + * Read a 32-bit unsigned integer * - * @access public - * @param string $string String to convert - * @param int $bits Number of bits - * @return int Integer according to type + * @return int + * @throws \GameQ\Exception\Protocol */ - public function toInt($string, $bits = 8) + public function readInt32($length = 4) { - // Check length - if (strlen($string) !== ($bits / 8)) { - return false; - } - - // Convert - switch($bits) { - - // 8 bit unsigned - case 8: - $int = ord($string); + // Change the integer type we are looking up + $littleEndian = null; + switch ($this->number_type) { + case self::NUMBER_TYPE_BIGENDIAN: + $type = 'N'; + $littleEndian = false; break; - // 16 bit unsigned - case 16: - $int = unpack('Sint', $string); - $int = $int['int']; + case self::NUMBER_TYPE_LITTLEENDIAN: + $type = 'V'; + $littleEndian = true; break; - // 32 bit unsigned - case 32: - $int = unpack('Lint', $string); - $int = $int['int']; - break; - - // Invalid type default: - $int = false; - break; + $type = 'L'; + } + + // read from the buffer and append/prepend empty bytes for shortened int32 + $corrected = $this->read($length); + + // Unpack the number + $int = unpack($type . 'int', self::extendBinaryString($corrected, 4, $littleEndian)); + + return $int['int']; + } + + /** + * Read a 32-bit signed integer + * + * @return int + * @throws \GameQ\Exception\Protocol + */ + public function readInt32Signed() + { + + // Read the data into a string + $string = $this->read(4); + + // For big endian we need to reverse the bytes + if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) { + $string = strrev($string); + } + + $int = unpack('lint', $string); + + unset($string); + + return $int['int']; + } + + /** + * Read a 64-bit unsigned integer + * + * @return int + * @throws \GameQ\Exception\Protocol + */ + public function readInt64() + { + + // We have the pack 64-bit codes available. See: http://php.net/manual/en/function.pack.php + if (version_compare(PHP_VERSION, '5.6.3') >= 0 && PHP_INT_SIZE == 8) { + // Change the integer type we are looking up + switch ($this->number_type) { + case self::NUMBER_TYPE_BIGENDIAN: + $type = 'Jint'; + break; + + case self::NUMBER_TYPE_LITTLEENDIAN: + $type = 'Pint'; + break; + + default: + $type = 'Qint'; + } + + $int64 = unpack($type, $this->read(8)); + + $int = $int64['int']; + + unset($int64); + } else { + if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) { + $high = $this->readInt32(); + $low = $this->readInt32(); + } else { + $low = $this->readInt32(); + $high = $this->readInt32(); + } + + // We have to determine the number via bitwise + $int = ($high << 32) | $low; + + unset($low, $high); } return $int; } + + /** + * Read a 32-bit float + * + * @return float + * @throws \GameQ\Exception\Protocol + */ + public function readFloat32() + { + + // Read the data into a string + $string = $this->read(4); + + // For big endian we need to reverse the bytes + if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) { + $string = strrev($string); + } + + $float = unpack('ffloat', $string); + + unset($string); + + return $float['float']; + } + + private static function extendBinaryString($input, $length = 4, $littleEndian = null) + { + if (is_null($littleEndian)) { + $littleEndian = self::isLittleEndian(); + } + + $extension = str_repeat(pack($littleEndian ? 'V' : 'N', 0b0000), $length - strlen($input)); + + if ($littleEndian) { + return $input . $extension; + } else { + return $extension . $input; + } + } + + private static function isLittleEndian() + { + return 0x00FF === current(unpack('v', pack('S', 0x00FF))); + } } diff --git a/third_party/gameq_v3.1/GameQ/Exception/Protocol.php b/third_party/gameq_v2/gameq/exception/Protocol.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Exception/Protocol.php rename to third_party/gameq_v2/gameq/exception/Protocol.php diff --git a/third_party/gameq_v3.1/GameQ/Exception/Query.php b/third_party/gameq_v2/gameq/exception/Query.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Exception/Query.php rename to third_party/gameq_v2/gameq/exception/Query.php diff --git a/third_party/gameq_v3.1/GameQ/Exception/Server.php b/third_party/gameq_v2/gameq/exception/Server.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Exception/Server.php rename to third_party/gameq_v2/gameq/exception/Server.php diff --git a/third_party/gameq_v2/gameq/filters.php b/third_party/gameq_v2/gameq/filters.php deleted file mode 100644 index 4acf7cff..00000000 --- a/third_party/gameq_v2/gameq/filters.php +++ /dev/null @@ -1,34 +0,0 @@ -. - */ - -/** - * Generic function to make extending shorter - * - * @author Austin Bischoff - */ -abstract class GameQ_Filters extends GameQ_Filters_Core {} - -/** - * GameQ Filters Exception - * - * Allows for a level of exception handling incase there is an issue/error within - * a filter or a required dependency has not been met. - * - * @author Austin Bischoff - */ -class GameQ_FiltersException extends Exception {} diff --git a/third_party/gameq_v3.1/GameQ/Filters/Base.php b/third_party/gameq_v2/gameq/filters/Base.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Filters/Base.php rename to third_party/gameq_v2/gameq/filters/Base.php diff --git a/third_party/gameq_v3.1/GameQ/Filters/Normalize.php b/third_party/gameq_v2/gameq/filters/Normalize.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Filters/Normalize.php rename to third_party/gameq_v2/gameq/filters/Normalize.php diff --git a/third_party/gameq_v3.1/GameQ/Filters/Secondstohuman.php b/third_party/gameq_v2/gameq/filters/Secondstohuman.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Filters/Secondstohuman.php rename to third_party/gameq_v2/gameq/filters/Secondstohuman.php diff --git a/third_party/gameq_v3.1/GameQ/Filters/Stripcolors.php b/third_party/gameq_v2/gameq/filters/Stripcolors.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Filters/Stripcolors.php rename to third_party/gameq_v2/gameq/filters/Stripcolors.php diff --git a/third_party/gameq_v3.1/GameQ/Filters/Test.php b/third_party/gameq_v2/gameq/filters/Test.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Filters/Test.php rename to third_party/gameq_v2/gameq/filters/Test.php diff --git a/third_party/gameq_v2/gameq/filters/core.php b/third_party/gameq_v2/gameq/filters/core.php deleted file mode 100644 index 1d7f7d7a..00000000 --- a/third_party/gameq_v2/gameq/filters/core.php +++ /dev/null @@ -1,55 +0,0 @@ -. - */ - -/** - * Abstract class which all filters must inherit - * - * @author Austin Bischoff - */ -abstract class GameQ_Filters_Core -{ - protected $params = array(); - - /** - * Constructor, receives parameters - * - * @param array $params Filter parameters - */ - function __construct($params) - { - if(is_array($params)) - { - foreach ($params as $key => $param) - { - $this->params[$key] = $param; - } - } - else - { - $this->params = $params; - } - } - - /** - * Actually apply the filter to the passed results - * - * @param array $results - * @param GameQ_Protocols_Core $protocol_instance - */ - abstract public function filter($results, GameQ_Protocols_Core $protocol_instance); -} diff --git a/third_party/gameq_v2/gameq/filters/normalise.php b/third_party/gameq_v2/gameq/filters/normalise.php deleted file mode 100644 index 7999b82f..00000000 --- a/third_party/gameq_v2/gameq/filters/normalise.php +++ /dev/null @@ -1,193 +0,0 @@ -. - */ - -/** - * This filter makes sure a fixed set of properties (i.e. gq_) is always available regardless of protocol - * - * @author Austin Bischoff - */ -class GameQ_Filters_Normalise extends GameQ_Filters -{ - /** - * Default normalization items. Can be overwritten on a protocol basis. - * - * @var array - */ - protected $normalize = array( - // General - 'general' => array( - // target => source - 'dedicated' => array('listenserver', 'dedic', 'bf2dedicated', 'netserverdedicated', 'bf2142dedicated'), - 'gametype' => array('ggametype', 'sigametype', 'matchtype'), - 'hostname' => array('svhostname', 'servername', 'siname', 'name'), - 'mapname' => array('map', 'simap'), - 'maxplayers' => array('svmaxclients', 'simaxplayers', 'maxclients'), - 'mod' => array('game', 'gamedir', 'gamevariant'), - 'numplayers' => array('clients', 'sinumplayers'), - 'password' => array('protected', 'siusepass', 'sineedpass', 'pswrd', 'gneedpass', 'auth'), - 'players' => array('players'), - 'teams' => array('team'), - ), - - // Indvidual - 'player' => array( - 'name' => array('nick', 'player', 'playername', 'name'), - 'kills' => array('kills'), - 'deaths' => array('deaths'), - 'score' => array('kills', 'frags', 'skill', 'score'), - 'ping' => array('ping'), - ), - - // Team - 'team' => array( - 'name' => array('name', 'teamname', 'team_t'), - 'score' => array('score', 'score_t'), - ), - ); - - /** - * Normalize the server data - * @see GameQ_Filters_Core::filter() - */ - public function filter($data, GameQ_Protocols_Core $protocol_instance) - { - $result = array(); - - // No data passed so something bad happened - if(empty($data)) - { - return $result; - } - - // Here we check to see if we override these defaults. - if(($normalize = $protocol_instance->getNormalize()) !== FALSE) - { - // Merge this stuff in - $this->normalize = array_merge_recursive($this->normalize, $normalize); - } - - // normalize the general items - $result = $this->normalize($data, 'general'); - - // normalize players - if (isset($result['gq_players']) && is_array($result['gq_players'])) - { - // Don't rename the players array - $result['players'] = $result['gq_players']; - - foreach ($result['players'] as $key => $player) - { - $result['players'][$key] = array_merge($player, $this->normalize($player, 'player')); - } - - $result['gq_numplayers'] = count($result['players']); - } - else - { - $result['players'] = array(); - } - - // normalize teams - if (isset($result['gq_teams']) && is_array($result['gq_teams'])) - { - // Don't rename the teams array - $result['teams'] = $result['gq_teams']; - - foreach ($result['teams'] as $key => $team) - { - $result['teams'][$key] = array_merge($team, $this->normalize($team, 'team')); - } - - $result['gq_numteams'] = count($result['teams']); - } - else - { - $result['teams'] = array(); - } - - unset($result['gq_players'], $result['gq_teams']); - - - // Merge and sort array - $result = (array_merge($data, $result)); - - ksort($result); - - return $result; - } - - - /** - * normalize an array - * - * @param array $data The data to normalize - * @param array $properties The properties we want to normalize - * @return array A normalized array - */ - private function normalize($data, $properties) - { - // Make sure this is not empty - if(!isset($this->normalize[$properties])) - { - // We just return empty array - return array(); - } - - $props = $this->normalize[$properties]; - - // Create a new array, with all the specified variables - $new = $this->fill($props); - - foreach ($data as $var => $value) - { - // normalize values - $stripped = strtolower(str_replace('_', '', $var)); - - foreach ($props as $target => $sources) - { - if ($target == $stripped or in_array($stripped, $sources)) - { - $new['gq_' . $target] = $value; - //unset($vars[$target]); - break; - } - } - } - - return $new; - } - - /** - * Fill array with array keys - * - * @param array $vars The array keys - * @param mixed $val Value of each key - * @return array An array filled with keys - */ - private function fill($vars, $val = false) - { - $data = array(); - - foreach ($vars as $target => $source) - { - $data['gq_' . $target] = $val; - } - - return $data; - } -} diff --git a/third_party/gameq_v2/gameq/filters/stripcolor.php b/third_party/gameq_v2/gameq/filters/stripcolor.php deleted file mode 100644 index 2656a7af..00000000 --- a/third_party/gameq_v2/gameq/filters/stripcolor.php +++ /dev/null @@ -1,76 +0,0 @@ -. - */ - -/** - * Strip color codes from specific protocol types. This code was adapted from the original filter class - * - * @author Austin Bischoff - */ -class GameQ_Filters_Stripcolor extends GameQ_Filters -{ - /** - * Strip all the color junk from returns - * @see GameQ_Filters_Core::filter() - */ - public function filter($data, GameQ_Protocols_Core $protocol_instance) - { - // Check the type of protocol - switch($protocol_instance->protocol()) - { - case 'quake2': - case 'quake3': - case 'doom3': - array_walk_recursive($data, array($this, 'stripQuake')); - break; - - case 'unreal2': - case 'ut3': - case 'gamespy3': //not sure if gamespy3 supports ut colors but won't hurt - case 'gamespy2': - array_walk_recursive($data, array($this, 'stripUT')); - break; - - default: - break; - } - - return $data; - } - - /** - * Strips quake color tags - * - * @param $string string String to strip - * @param $key string Array key - */ - protected function stripQuake(&$string, $key) - { - $string = preg_replace('#(\^.)#', '', $string); - } - - /** - * Strip UT color tags - * - * @param $string string String to strip - * @param $key string Array key - */ - protected function stripUT(&$string, $key) - { - $string = preg_replace('/\x1b.../', '', $string); - } -} diff --git a/third_party/gameq_v2/gameq/protocols.php b/third_party/gameq_v2/gameq/protocols.php deleted file mode 100644 index 57a1ae20..00000000 --- a/third_party/gameq_v2/gameq/protocols.php +++ /dev/null @@ -1,37 +0,0 @@ -. - */ - -/** - * Generic function to make extending shorter - * - * @author Austin Bischoff - */ -abstract class GameQ_Protocols extends GameQ_Protocols_Core -{ - -} - -/** - * GameQ Protocol Exception - * - * Allows for another level of exception handling when doing loops. Makes it possible to recover and continue - * when there is an exception within one of the protocol classes. - * - * @author Austin Bischoff - */ -class GameQ_ProtocolsException extends Exception {} diff --git a/third_party/gameq_v2/gameq/protocols/7d2d.php b/third_party/gameq_v2/gameq/protocols/7d2d.php deleted file mode 100644 index 7b728bc9..00000000 --- a/third_party/gameq_v2/gameq/protocols/7d2d.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -/** - * 7 Days to Die Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_7d2d extends GameQ_Protocols_Source -{ - protected $name = "7d2d"; - protected $name_long = "7 Days to Die"; - - /** - * Overload for client port - * - * @param string $ip - * @param integer $port - * @param array $options - */ - public function __construct($ip = FALSE, $port = FALSE, $options = array()) - { - // Got to do this first - parent::__construct($ip, $port, $options); - - // Correct the client port since query_port = client_port + 1 - $this->port_client(($this->port_client() - 1)); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Dods.php b/third_party/gameq_v2/gameq/protocols/Aapg.php similarity index 88% rename from third_party/gameq_v3.1/GameQ/Protocols/Dods.php rename to third_party/gameq_v2/gameq/protocols/Aapg.php index 898d75b9..a207d4fe 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Dods.php +++ b/third_party/gameq_v2/gameq/protocols/Aapg.php @@ -19,24 +19,24 @@ namespace GameQ\Protocols; /** - * Class Dods + * Class Aapg * * @package GameQ\Protocols * @author Austin Bischoff */ -class Dods extends Source +class Aapg extends Aa3 { /** * String name of this protocol class * * @type string */ - protected $name = 'dods'; + protected $name = 'aapg'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Day of Defeat: Source"; + protected $name_long = "America's Army: Proving Grounds"; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Arkse.php b/third_party/gameq_v2/gameq/protocols/Arkse.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Arkse.php rename to third_party/gameq_v2/gameq/protocols/Arkse.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Arma.php b/third_party/gameq_v2/gameq/protocols/Arma.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Arma.php rename to third_party/gameq_v2/gameq/protocols/Arma.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Arma3.php b/third_party/gameq_v2/gameq/protocols/Arma3.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Arma3.php rename to third_party/gameq_v2/gameq/protocols/Arma3.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Atlas.php b/third_party/gameq_v2/gameq/protocols/Atlas.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Atlas.php rename to third_party/gameq_v2/gameq/protocols/Atlas.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Dod.php b/third_party/gameq_v2/gameq/protocols/Avorion.php similarity index 80% rename from third_party/gameq_v3.1/GameQ/Protocols/Dod.php rename to third_party/gameq_v2/gameq/protocols/Avorion.php index 0c7baf69..b4aa2d7a 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Dod.php +++ b/third_party/gameq_v2/gameq/protocols/Avorion.php @@ -19,27 +19,30 @@ namespace GameQ\Protocols; /** - * Class Dod - * - * Based off of CS 1.6 + * Avorion Protocol Class * * @package GameQ\Protocols - * @author Austin Bischoff */ -class Dod extends Cs16 +class Avorion extends Source { - /** * String name of this protocol class * * @type string */ - protected $name = 'dod'; + protected $name = 'avorion'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Day of Defeat"; + protected $name_long = "Avorion"; + + /** + * query_port = client_port + 1 + * + * @type int + * protected $port_diff = 1; + */ } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ns2.php b/third_party/gameq_v2/gameq/protocols/Barotrauma.php similarity index 85% rename from third_party/gameq_v3.1/GameQ/Protocols/Ns2.php rename to third_party/gameq_v2/gameq/protocols/Barotrauma.php index 4c323929..643428a2 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Ns2.php +++ b/third_party/gameq_v2/gameq/protocols/Barotrauma.php @@ -19,26 +19,26 @@ namespace GameQ\Protocols; /** - * Class Ns2 + * Barotrauma Protocol Class * * @package GameQ\Protocols - * @author Austin Bischoff + * @author Jesse Lukas */ -class Ns2 extends Source +class Barotrauma extends Source { /** * String name of this protocol class * * @type string */ - protected $name = 'ns2'; + protected $name = 'barotrauma'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Natural Selection 2"; + protected $name_long = "Barotrauma"; /** * query_port = client_port + 1 diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Batt1944.php b/third_party/gameq_v2/gameq/protocols/Batt1944.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Batt1944.php rename to third_party/gameq_v2/gameq/protocols/Batt1944.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Bfh.php b/third_party/gameq_v2/gameq/protocols/Bfh.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Bfh.php rename to third_party/gameq_v2/gameq/protocols/Bfh.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Crysis2.php b/third_party/gameq_v2/gameq/protocols/Blackmesa.php similarity index 84% rename from third_party/gameq_v3.1/GameQ/Protocols/Crysis2.php rename to third_party/gameq_v2/gameq/protocols/Blackmesa.php index 75c6614a..efaafdfb 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Crysis2.php +++ b/third_party/gameq_v2/gameq/protocols/Blackmesa.php @@ -19,25 +19,24 @@ namespace GameQ\Protocols; /** - * Class Crysis2 + * Blackmesa Protocol Class * * @package GameQ\Protocols - * - * @author Wilson Jesus <> + * @author Jesse Lukas */ -class Crysis2 extends Gamespy3 +class Blackmesa extends Source { /** * String name of this protocol class * * @type string */ - protected $name = 'crysis2'; + protected $name = 'blackmesa'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Crysis 2"; + protected $name_long = "Black Mesa"; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Cod.php b/third_party/gameq_v2/gameq/protocols/Citadel.php similarity index 84% rename from third_party/gameq_v3.1/GameQ/Protocols/Cod.php rename to third_party/gameq_v2/gameq/protocols/Citadel.php index 2425ea67..3d1074b1 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Cod.php +++ b/third_party/gameq_v2/gameq/protocols/Citadel.php @@ -19,25 +19,24 @@ namespace GameQ\Protocols; /** - * Call of Duty Protocol Class + * Citadel Protocol Class * * @package GameQ\Protocols - * - * @author Wilson Jesus <> + * @author Jesse Lukas */ -class Cod extends Quake3 +class Citadel extends Source { /** * String name of this protocol class * * @type string */ - protected $name = 'cod'; + protected $name = 'citadel'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Call of Duty"; + protected $name_long = "Citadel"; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Warsow.php b/third_party/gameq_v2/gameq/protocols/Codmw2.php similarity index 61% rename from third_party/gameq_v3.1/GameQ/Protocols/Warsow.php rename to third_party/gameq_v2/gameq/protocols/Codmw2.php index f1d629a9..290e43c9 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Warsow.php +++ b/third_party/gameq_v2/gameq/protocols/Codmw2.php @@ -22,74 +22,67 @@ use GameQ\Buffer; use GameQ\Result; /** - * Warsow Protocol Class + * Call of Duty: Modern Warfare 2 Protocol Class * * @package GameQ\Protocols - * @author Austin Bischoff + * @author Wilson Jesus <> */ -class Warsow extends Quake3 +class Codmw2 extends Quake3 { /** * String name of this protocol class * * @type string */ - protected $name = 'warsow'; + protected $name = 'codmw2'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Warsow"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "warsow://%s:%d/"; - - /** - * Handle player info, different than quake3 base - * - * @param Buffer $buffer - * - * @return array - * @throws \GameQ\Exception\Protocol - */ + protected $name_long = "Call of Duty: Modern Warfare 2"; + protected function processPlayers(Buffer $buffer) { - // Set the result to a new result instance - $result = new Result(); + // Temporarily cache players in order to remove last + $players = []; // Loop until we are out of data while ($buffer->getLength()) { // Make a new buffer with this block $playerInfo = new Buffer($buffer->readString("\x0A")); - // Add player info - $result->addPlayer('frags', $playerInfo->readString("\x20")); - $result->addPlayer('ping', $playerInfo->readString("\x20")); + // Read player info + $player = [ + 'frags' => $playerInfo->readString("\x20"), + 'ping' => $playerInfo->readString("\x20"), + ]; // Skip first " $playerInfo->skip(1); // Add player name, encoded - $result->addPlayer('name', utf8_encode(trim(($playerInfo->readString('"'))))); + $player['name'] = utf8_encode(trim(($playerInfo->readString('"')))); - // Skip space - $playerInfo->skip(1); - - // Add team - $result->addPlayer('team', $playerInfo->read()); - - // Clear - unset($playerInfo); + // Add player + $players[] = $player; } + // Remove last, empty player + array_pop($players); + + // Set the result to a new result instance + $result = new Result(); + + // Add players + $result->add('players', $players); + + // Add Playercount + $result->add('clients', count($players)); + // Clear - unset($buffer); + unset($buffer, $players); return $result->fetch(); } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Conanexiles.php b/third_party/gameq_v2/gameq/protocols/Conanexiles.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Conanexiles.php rename to third_party/gameq_v2/gameq/protocols/Conanexiles.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Contagion.php b/third_party/gameq_v2/gameq/protocols/Contagion.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Contagion.php rename to third_party/gameq_v2/gameq/protocols/Contagion.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Cs15.php b/third_party/gameq_v2/gameq/protocols/Cs15.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Cs15.php rename to third_party/gameq_v2/gameq/protocols/Cs15.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Cs2d.php b/third_party/gameq_v2/gameq/protocols/Cs2d.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Cs2d.php rename to third_party/gameq_v2/gameq/protocols/Cs2d.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Dal.php b/third_party/gameq_v2/gameq/protocols/Dal.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Dal.php rename to third_party/gameq_v2/gameq/protocols/Dal.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Dow.php b/third_party/gameq_v2/gameq/protocols/Dow.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Dow.php rename to third_party/gameq_v2/gameq/protocols/Dow.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Eco.php b/third_party/gameq_v2/gameq/protocols/Eco.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Eco.php rename to third_party/gameq_v2/gameq/protocols/Eco.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Egs.php b/third_party/gameq_v2/gameq/protocols/Egs.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Egs.php rename to third_party/gameq_v2/gameq/protocols/Egs.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Grav.php b/third_party/gameq_v2/gameq/protocols/Grav.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Grav.php rename to third_party/gameq_v2/gameq/protocols/Grav.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Gta5m.php b/third_party/gameq_v2/gameq/protocols/Gta5m.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Gta5m.php rename to third_party/gameq_v2/gameq/protocols/Gta5m.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Gtan.php b/third_party/gameq_v2/gameq/protocols/Gtan.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Gtan.php rename to third_party/gameq_v2/gameq/protocols/Gtan.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Gtar.php b/third_party/gameq_v2/gameq/protocols/Gtar.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Gtar.php rename to third_party/gameq_v2/gameq/protocols/Gtar.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ut.php b/third_party/gameq_v2/gameq/protocols/Had2.php similarity index 77% rename from third_party/gameq_v3.1/GameQ/Protocols/Ut.php rename to third_party/gameq_v2/gameq/protocols/Had2.php index 75722ce1..92134351 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Ut.php +++ b/third_party/gameq_v2/gameq/protocols/Had2.php @@ -19,11 +19,11 @@ namespace GameQ\Protocols; /** - * Unreal Tournament Protocol Class + * Hidden & Dangerous 2 Protocol Class * - * @author Austin Bischoff + * @author Wilson Jesus <> */ -class Ut extends Gamespy +class Had2 extends Gamespy2 { /** @@ -31,21 +31,21 @@ class Ut extends Gamespy * * @type string */ - protected $name = 'ut'; + protected $name = 'had2'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Unreal Tournament"; + protected $name_long = "Hidden & Dangerous 2"; /** - * query_port = client_port + 1 + * The difference between the client port and query port * * @type int */ - protected $port_diff = 1; + protected $port_diff = 3; /** * Normalize settings for this protocol @@ -56,7 +56,7 @@ class Ut extends Gamespy // General 'general' => [ // target => source - 'dedicated' => 'dedicated', + 'dedicated' => 'isdedicated', 'gametype' => 'gametype', 'hostname' => 'hostname', 'mapname' => 'mapname', @@ -66,8 +66,10 @@ class Ut extends Gamespy ], // Individual 'player' => [ - 'name' => 'name', - 'score' => 'frags', + 'name' => 'player', + 'score' => 'score', + 'deaths' => 'deaths', + 'ping' => 'ping', ], ]; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Crysis.php b/third_party/gameq_v2/gameq/protocols/Halo.php similarity index 83% rename from third_party/gameq_v3.1/GameQ/Protocols/Crysis.php rename to third_party/gameq_v2/gameq/protocols/Halo.php index e09a673d..f402f94d 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Crysis.php +++ b/third_party/gameq_v2/gameq/protocols/Halo.php @@ -19,25 +19,24 @@ namespace GameQ\Protocols; /** - * Class Crysis + * Halo: Combat Evolved Protocol Class * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> + * @author Wilson Jesus <> */ -class Crysis extends Gamespy3 +class Halo extends Gamespy2 { + /** * String name of this protocol class * * @type string */ - protected $name = 'crysis'; + protected $name = 'halo'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Crysis"; + protected $name_long = "Halo: Combat Evolved"; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Css.php b/third_party/gameq_v2/gameq/protocols/Hl1.php similarity index 87% rename from third_party/gameq_v3.1/GameQ/Protocols/Css.php rename to third_party/gameq_v2/gameq/protocols/Hl1.php index be75da3d..e17667b6 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Css.php +++ b/third_party/gameq_v2/gameq/protocols/Hl1.php @@ -19,24 +19,25 @@ namespace GameQ\Protocols; /** - * Class Css + * Class Hl1 * * @package GameQ\Protocols * @author Austin Bischoff + * @author Jesse Lukas */ -class Css extends Source +class Hl1 extends Source { /** * String name of this protocol class * * @type string */ - protected $name = 'css'; + protected $name = 'hl1'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Counter-Strike: Source"; + protected $name_long = "Half Life"; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Bf1942.php b/third_party/gameq_v2/gameq/protocols/Hll.php similarity index 63% rename from third_party/gameq_v3.1/GameQ/Protocols/Bf1942.php rename to third_party/gameq_v2/gameq/protocols/Hll.php index 4cf06c5e..bf0b00c1 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Bf1942.php +++ b/third_party/gameq_v2/gameq/protocols/Hll.php @@ -19,70 +19,50 @@ namespace GameQ\Protocols; /** - * Class Battlefield 1942 + * Class Hll * * @package GameQ\Protocols - * @author Austin Bischoff + * @author Wilson Jesus <> */ -class Bf1942 extends Gamespy +class Hll extends Source { - /** * String name of this protocol class * * @type string */ - protected $name = 'bf1942'; + protected $name = 'hll'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Battlefield 1942"; + protected $name_long = "Hell Let Loose"; /** - * query_port = client_port + 8433 - * 23000 = 14567 + 8433 + * query_port = client_port + 15 + * 64015 = 64000 + 15 * * @type int */ - protected $port_diff = 8433; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "bf1942://%s:%d"; + protected $port_diff = 15; /** * Normalize settings for this protocol * * @type array */ - protected $normalize = [ - // General + /*protected $normalize = [ 'general' => [ // target => source 'dedicated' => 'dedicated', 'gametype' => 'gametype', - 'hostname' => 'hostname', + 'servername' => 'hostname', 'mapname' => 'mapname', 'maxplayers' => 'maxplayers', 'numplayers' => 'numplayers', 'password' => 'password', ], - // Individual - 'player' => [ - 'name' => 'playername', - 'kills' => 'kills', - 'deaths' => 'deaths', - 'ping' => 'ping', - 'score' => 'score', - ], - 'team' => [ - 'name' => 'teamname', - ], - ]; + ];*/ } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Hurtworld.php b/third_party/gameq_v2/gameq/protocols/Hurtworld.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Hurtworld.php rename to third_party/gameq_v2/gameq/protocols/Hurtworld.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Insurgencysand.php b/third_party/gameq_v2/gameq/protocols/Insurgencysand.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Insurgencysand.php rename to third_party/gameq_v2/gameq/protocols/Insurgencysand.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Jediacademy.php b/third_party/gameq_v2/gameq/protocols/Jediacademy.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Jediacademy.php rename to third_party/gameq_v2/gameq/protocols/Jediacademy.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Jedioutcast.php b/third_party/gameq_v2/gameq/protocols/Jedioutcast.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Jedioutcast.php rename to third_party/gameq_v2/gameq/protocols/Jedioutcast.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Justcause2.php b/third_party/gameq_v2/gameq/protocols/Justcause2.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Justcause2.php rename to third_party/gameq_v2/gameq/protocols/Justcause2.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Justcause3.php b/third_party/gameq_v2/gameq/protocols/Justcause3.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Justcause3.php rename to third_party/gameq_v2/gameq/protocols/Justcause3.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Killingfloor2.php b/third_party/gameq_v2/gameq/protocols/Killingfloor2.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Killingfloor2.php rename to third_party/gameq_v2/gameq/protocols/Killingfloor2.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Et.php b/third_party/gameq_v2/gameq/protocols/Kingpin.php similarity index 86% rename from third_party/gameq_v3.1/GameQ/Protocols/Et.php rename to third_party/gameq_v2/gameq/protocols/Kingpin.php index 63b5beb7..87007d91 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Et.php +++ b/third_party/gameq_v2/gameq/protocols/Kingpin.php @@ -19,25 +19,25 @@ namespace GameQ\Protocols; /** - * Wolfenstein Enemy Territory Protocol Class + * Kingpin: Life of Crime Protocol Class * * @package GameQ\Protocols * * @author Wilson Jesus <> */ -class Et extends Quake3 +class Kingpin extends Quake2 { /** * String name of this protocol class * * @type string */ - protected $name = 'et'; + protected $name = 'kingpin'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Wolfenstein Enemy Territory"; + protected $name_long = "Kingpin: Life of Crime"; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Lhmp.php b/third_party/gameq_v2/gameq/protocols/Lhmp.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Lhmp.php rename to third_party/gameq_v2/gameq/protocols/Lhmp.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Minecraftpe.php b/third_party/gameq_v2/gameq/protocols/Minecraftpe.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Minecraftpe.php rename to third_party/gameq_v2/gameq/protocols/Minecraftpe.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Mohaa.php b/third_party/gameq_v2/gameq/protocols/Miscreated.php similarity index 68% rename from third_party/gameq_v3.1/GameQ/Protocols/Mohaa.php rename to third_party/gameq_v2/gameq/protocols/Miscreated.php index 66ddd7e7..d59fed12 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Mohaa.php +++ b/third_party/gameq_v2/gameq/protocols/Miscreated.php @@ -19,27 +19,34 @@ namespace GameQ\Protocols; /** - * Medal of honor: Allied Assault Protocol Class + * Class Miscreated * * @package GameQ\Protocols - * @author Bram - * @author Austin Bischoff + * @author Wilson Jesus <> */ -class Mohaa extends Gamespy +class Miscreated extends Source { /** * String name of this protocol class * * @type string */ - protected $name = 'mohaa'; + protected $name = 'miscreated'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Medal of honor: Allied Assault"; + protected $name_long = "Miscreated"; + + /** + * query_port = client_port + 2 + * 64092 = 64090 + 2 + * + * @type int + */ + protected $port_diff = 2; /** * Normalize settings for this protocol @@ -51,29 +58,11 @@ class Mohaa extends Gamespy // target => source 'dedicated' => 'dedicated', 'gametype' => 'gametype', - 'hostname' => 'hostname', + 'servername' => 'hostname', 'mapname' => 'mapname', 'maxplayers' => 'maxplayers', 'numplayers' => 'numplayers', 'password' => 'password', ], - // Individual - 'player' => [ - 'name' => 'player', - 'score' => 'frags', - 'ping' => 'ping', - ], ]; - - /** - * Query port is always the client port + 97 in MOHAA - * - * @param int $clientPort - * - * @return int - */ - public function findQueryPort($clientPort) - { - return $clientPort + 97; - } } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Gmod.php b/third_party/gameq_v2/gameq/protocols/Modiverse.php similarity index 85% rename from third_party/gameq_v3.1/GameQ/Protocols/Gmod.php rename to third_party/gameq_v2/gameq/protocols/Modiverse.php index 65967247..64b41ed5 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Gmod.php +++ b/third_party/gameq_v2/gameq/protocols/Modiverse.php @@ -19,24 +19,25 @@ namespace GameQ\Protocols; /** - * Class Gmod + * Class Modiverse * * @package GameQ\Protocols * @author Austin Bischoff + * @author Jesse Lukas */ -class Gmod extends Source +class Modiverse extends Source { /** * String name of this protocol class * * @type string */ - protected $name = 'gmod'; + protected $name = 'modiverse'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Garry's Mod"; + protected $name_long = "Modiverse"; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Mordhau.php b/third_party/gameq_v2/gameq/protocols/Mordhau.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Mordhau.php rename to third_party/gameq_v2/gameq/protocols/Mordhau.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Hl2dm.php b/third_party/gameq_v2/gameq/protocols/Of.php similarity index 82% rename from third_party/gameq_v3.1/GameQ/Protocols/Hl2dm.php rename to third_party/gameq_v2/gameq/protocols/Of.php index 15f881aa..bce7612d 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Hl2dm.php +++ b/third_party/gameq_v2/gameq/protocols/Of.php @@ -19,24 +19,25 @@ namespace GameQ\Protocols; /** - * Class Hl2dm + * Class Open Fortress * * @package GameQ\Protocols * @author Austin Bischoff + * @author Jesse Lukas */ -class Hl2dm extends Source +class Of extends Source { /** - * String name of this protocol class + * Open Fortress protocol class * * @type string */ - protected $name = 'hl2dm'; + protected $name = 'of'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Half Life 2: Deathmatch"; + protected $name_long = "Open Fortress"; } diff --git a/third_party/gameq_v2/gameq/protocols/Openttd.php b/third_party/gameq_v2/gameq/protocols/Openttd.php new file mode 100644 index 00000000..75c44fe1 --- /dev/null +++ b/third_party/gameq_v2/gameq/protocols/Openttd.php @@ -0,0 +1,183 @@ +. + */ + +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + +/** + * OpenTTD Protocol Class + * + * Handles processing Open Transport Tycoon Deluxe servers + * + * @package GameQ\Protocols + * @author Wilson Jesus <> + */ +class Openttd extends Protocol +{ + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_ALL => "\x03\x00\x00", + ]; + + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'openttd'; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'openttd'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Open Transport Tycoon Deluxe"; + + /** + * The client join link + * + * @type string + */ + protected $join_link = null; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'hostname' => 'hostname', + 'mapname' => 'map', + 'maxplayers' => 'max_clients', + 'numplayers' => 'clients', + 'password' => 'password', + 'dedicated' => 'dedicated', + ], + ]; + + /** + * Handle response from the server + * + * @return mixed + * @throws Exception + */ + public function processResponse() + { + // Make a buffer + $buffer = new Buffer(implode('', $this->packets_response)); + + // Get the length of the packet + $packetLength = $buffer->getLength(); + + // Grab the header + $length = $buffer->readInt16(); + //$type = $buffer->readInt8(); + $buffer->skip(1); // Skip the "$type" as its not used in the code, and to comply with phpmd it cant be assigned and not used. + + // Header + // Figure out which packet response this is + if ($packetLength != $length) { + throw new Exception(__METHOD__ . " response type '" . bin2hex($length) . "' is not valid"); + } + + return call_user_func_array([$this, 'processServerInfo'], [$buffer]); + } + + /** + * Handle processing the server information + * + * @param Buffer $buffer + * + * @return array + */ + protected function processServerInfo(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); + + $protocol_version = $buffer->readInt8(); + $result->add('protocol_version', $protocol_version); + + switch ($protocol_version) { + case 4: + $num_grfs = $buffer->readInt8(); #number of grfs + $result->add('num_grfs', $num_grfs); + //$buffer->skip ($num_grfs * 20); #skip grfs id and md5 hash + + for ($i=0; $i<$num_grfs; $i++) { + $result->add('grfs_'.$i.'_ID', strtoupper(bin2hex($buffer->read(4)))); + $result->add('grfs_'.$i.'_MD5', strtoupper(bin2hex($buffer->read(16)))); + } + // No break, cascades all the down even if case is meet + case 3: + $result->add('game_date', $buffer->readInt32()); + $result->add('start_date', $buffer->readInt32()); + // Cascades all the way down even if case is meet + case 2: + $result->add('companies_max', $buffer->readInt8()); + $result->add('companies_on', $buffer->readInt8()); + $result->add('spectators_max', $buffer->readInt8()); + // Cascades all the way down even if case is meet + case 1: + $result->add('hostname', $buffer->readString()); + $result->add('version', $buffer->readString()); + + $language = $buffer->readInt8(); + $result->add('language', $language); + $result->add('language_icon', '//media.openttd.org/images/server/'.$language.'_lang.gif'); + + $result->add('password', $buffer->readInt8()); + $result->add('max_clients', $buffer->readInt8()); + $result->add('clients', $buffer->readInt8()); + $result->add('spectators', $buffer->readInt8()); + if ($protocol_version < 3) { + $days = ( 365 * 1920 + 1920 / 4 - 1920 / 100 + 1920 / 400 ); + $result->add('game_date', $buffer->readInt16() + $days); + $result->add('start_date', $buffer->readInt16() + $days); + } + $result->add('map', $buffer->readString()); + $result->add('map_width', $buffer->readInt16()); + $result->add('map_height', $buffer->readInt16()); + $result->add('map_type', $buffer->readInt8()); + $result->add('dedicated', $buffer->readInt8()); + // Cascades all the way down even if case is meet + } + unset($buffer); + + return $result->fetch(); + } +} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Pixark.php b/third_party/gameq_v2/gameq/protocols/Pixark.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Pixark.php rename to third_party/gameq_v2/gameq/protocols/Pixark.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Armedassault2oa.php b/third_party/gameq_v2/gameq/protocols/Postscriptum.php similarity index 81% rename from third_party/gameq_v3.1/GameQ/Protocols/Armedassault2oa.php rename to third_party/gameq_v2/gameq/protocols/Postscriptum.php index e527a38d..555ba7d1 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Armedassault2oa.php +++ b/third_party/gameq_v2/gameq/protocols/Postscriptum.php @@ -19,32 +19,32 @@ namespace GameQ\Protocols; /** - * Class Armedassault2oa + * Class Postscriptum * * @package GameQ\Protocols * @author Austin Bischoff */ -class Armedassault2oa extends Source +class Postscriptum extends Source { - /** * String name of this protocol class * * @type string */ - protected $name = "armedassault2oa"; + protected $name = 'postscriptum'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Armed Assault 2: Operation Arrowhead"; + protected $name_long = "Post Scriptum"; /** - * Query port = client_port + 1 + * query_port = client_port + 10 + * 64092 = 64090 + 10 * * @type int */ - protected $port_diff = 1; + protected $port_diff = 10; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Projectrealitybf2.php b/third_party/gameq_v2/gameq/protocols/Projectrealitybf2.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Projectrealitybf2.php rename to third_party/gameq_v2/gameq/protocols/Projectrealitybf2.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Quakelive.php b/third_party/gameq_v2/gameq/protocols/Quakelive.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Quakelive.php rename to third_party/gameq_v2/gameq/protocols/Quakelive.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Redorchestraostfront.php b/third_party/gameq_v2/gameq/protocols/Redorchestraostfront.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Redorchestraostfront.php rename to third_party/gameq_v2/gameq/protocols/Redorchestraostfront.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Codmw3.php b/third_party/gameq_v2/gameq/protocols/Rf2.php similarity index 84% rename from third_party/gameq_v3.1/GameQ/Protocols/Codmw3.php rename to third_party/gameq_v2/gameq/protocols/Rf2.php index 1049b602..9901c425 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Codmw3.php +++ b/third_party/gameq_v2/gameq/protocols/Rf2.php @@ -19,30 +19,30 @@ namespace GameQ\Protocols; /** - * Class Codmw3 + * Class rFactor2 * * @package GameQ\Protocols - * @author Austin Bischoff + * @author Wilson Jesus <> */ -class Codmw3 extends Source +class Rf2 extends Source { - /** * String name of this protocol class * * @type string */ - protected $name = 'codmw3'; + protected $name = 'rf2'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Call of Duty: Modern Warfare 3"; + protected $name_long = "rFactor 2"; /** * query_port = client_port + 2 + * 64092 = 64090 + 2 * * @type int */ diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Risingstorm2.php b/third_party/gameq_v2/gameq/protocols/Risingstorm2.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Risingstorm2.php rename to third_party/gameq_v2/gameq/protocols/Risingstorm2.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Redorchestra2.php b/third_party/gameq_v2/gameq/protocols/Sco.php similarity index 77% rename from third_party/gameq_v3.1/GameQ/Protocols/Redorchestra2.php rename to third_party/gameq_v2/gameq/protocols/Sco.php index 67330167..a920fbd8 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Redorchestra2.php +++ b/third_party/gameq_v2/gameq/protocols/Sco.php @@ -19,32 +19,32 @@ namespace GameQ\Protocols; /** - * Class Redorchestra2 + * Class Sven Co-op * * @package GameQ\Protocols * @author Austin Bischoff + * @author Jesse Lukas */ -class Redorchestra2 extends Source +class Sco extends Source { /** - * String name of this protocol class + * Sven Co-op protocol class * * @type string */ - protected $name = 'redorchestra2'; + protected $name = 'sco'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Red Orchestra 2"; + protected $name_long = "Sven Co-op"; /** - * query_port = client_port + 19238 - * 27015 = 7777 + 19238 + * query_port = client_port + 1 * * @type int */ - protected $port_diff = 19238; + protected $port_diff = 1; } diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Serioussam.php b/third_party/gameq_v2/gameq/protocols/Serioussam.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Serioussam.php rename to third_party/gameq_v2/gameq/protocols/Serioussam.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Sevendaystodie.php b/third_party/gameq_v2/gameq/protocols/Sevendaystodie.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Sevendaystodie.php rename to third_party/gameq_v2/gameq/protocols/Sevendaystodie.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ship.php b/third_party/gameq_v2/gameq/protocols/Ship.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Ship.php rename to third_party/gameq_v2/gameq/protocols/Ship.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Spaceengineers.php b/third_party/gameq_v2/gameq/protocols/Spaceengineers.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Spaceengineers.php rename to third_party/gameq_v2/gameq/protocols/Spaceengineers.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Squad.php b/third_party/gameq_v2/gameq/protocols/Squad.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Squad.php rename to third_party/gameq_v2/gameq/protocols/Squad.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Starmade.php b/third_party/gameq_v2/gameq/protocols/Starmade.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Starmade.php rename to third_party/gameq_v2/gameq/protocols/Starmade.php diff --git a/third_party/gameq_v2/gameq/protocols/Stormworks.php b/third_party/gameq_v2/gameq/protocols/Stormworks.php new file mode 100644 index 00000000..735b5776 --- /dev/null +++ b/third_party/gameq_v2/gameq/protocols/Stormworks.php @@ -0,0 +1,50 @@ +. + */ + +namespace GameQ\Protocols; + +/** + * Class Stormworks + * + * @package GameQ\Protocols + * @author Austin Bischoff + * @author Jesse Lukas + */ +class Stormworks extends Source +{ + /** + * Stormworks protocol class + * + * @type string + */ + protected $name = 'stormworks'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Stormworks"; + + /** + * query_port = client_port + 1 + * + * @type int + */ + protected $port_diff = 1; +} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Swat4.php b/third_party/gameq_v2/gameq/protocols/Swat4.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Swat4.php rename to third_party/gameq_v2/gameq/protocols/Swat4.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Theforrest.php b/third_party/gameq_v2/gameq/protocols/Theforrest.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Theforrest.php rename to third_party/gameq_v2/gameq/protocols/Theforrest.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Tibia.php b/third_party/gameq_v2/gameq/protocols/Tibia.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Tibia.php rename to third_party/gameq_v2/gameq/protocols/Tibia.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Unturned.php b/third_party/gameq_v2/gameq/protocols/Unturned.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Unturned.php rename to third_party/gameq_v2/gameq/protocols/Unturned.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Urbanterror.php b/third_party/gameq_v2/gameq/protocols/Urbanterror.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Urbanterror.php rename to third_party/gameq_v2/gameq/protocols/Urbanterror.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Valheim.php b/third_party/gameq_v2/gameq/protocols/Valheim.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Valheim.php rename to third_party/gameq_v2/gameq/protocols/Valheim.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Brink.php b/third_party/gameq_v2/gameq/protocols/Vrising.php similarity index 88% rename from third_party/gameq_v3.1/GameQ/Protocols/Brink.php rename to third_party/gameq_v2/gameq/protocols/Vrising.php index 20226525..08549469 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Brink.php +++ b/third_party/gameq_v2/gameq/protocols/Vrising.php @@ -19,27 +19,25 @@ namespace GameQ\Protocols; /** - * Class Brink + * V Rining Protocol Class * * @package GameQ\Protocols - * - * @author Wilson Jesus <> */ -class Brink extends Source +class Vrising extends Source { /** * String name of this protocol class * * @type string */ - protected $name = 'brink'; + protected $name = 'vrising'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Brink"; + protected $name_long = "V Rising"; /** * query_port = client_port + 1 diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Won.php b/third_party/gameq_v2/gameq/protocols/Won.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Won.php rename to third_party/gameq_v2/gameq/protocols/Won.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Wurm.php b/third_party/gameq_v2/gameq/protocols/Wurm.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Protocols/Wurm.php rename to third_party/gameq_v2/gameq/protocols/Wurm.php diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Csgo.php b/third_party/gameq_v2/gameq/protocols/Zomboid.php similarity index 87% rename from third_party/gameq_v3.1/GameQ/Protocols/Csgo.php rename to third_party/gameq_v2/gameq/protocols/Zomboid.php index 41af7352..4733d97a 100644 --- a/third_party/gameq_v3.1/GameQ/Protocols/Csgo.php +++ b/third_party/gameq_v2/gameq/protocols/Zomboid.php @@ -19,25 +19,24 @@ namespace GameQ\Protocols; /** - * Class Csgo + * Project Zomboid Protocol Class * * @package GameQ\Protocols * @author Austin Bischoff */ -class Csgo extends Source +class Zomboid extends Source { - /** * String name of this protocol class * * @type string */ - protected $name = 'csgo'; + protected $name = 'zomboid'; /** * Longer string name of this protocol class * * @type string */ - protected $name_long = "Counter-Strike: Global Offensive"; + protected $name_long = "Project Zomboid"; } diff --git a/third_party/gameq_v2/gameq/protocols/aa.php b/third_party/gameq_v2/gameq/protocols/aa.php deleted file mode 100644 index c30b970c..00000000 --- a/third_party/gameq_v2/gameq/protocols/aa.php +++ /dev/null @@ -1,32 +0,0 @@ -. - */ - -/** - * America's Army 1/2 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Aa extends GameQ_Protocols_Gamespy2 -{ - protected $name = "aa"; - protected $name_long = "America's Army"; - - protected $link_join = "aao://%s:%d/"; - - protected $port = 1717; -} diff --git a/third_party/gameq_v2/gameq/protocols/aa3.php b/third_party/gameq_v2/gameq/protocols/aa3.php index 4fc20b0e..6ffd412a 100644 --- a/third_party/gameq_v2/gameq/protocols/aa3.php +++ b/third_party/gameq_v2/gameq/protocols/aa3.php @@ -3,30 +3,51 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * America's Army 3 Protocol Class (Version 3.2+) + * Class Aa3 * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Aa3 extends GameQ_Protocols_Source +class Aa3 extends Source { - protected $name = "aa3"; - protected $name_long = " America's Army 3 (> 3.2)"; - protected $link_join = "aa3://%s:%d/"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'aa3'; - protected $port = 27020; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "America's Army 3"; + + /** + * Query port = client_port + 18243 + * + * client_port default 8777 + * query_port default 27020 + * + * @type int + */ + protected $port_diff = 18243; } diff --git a/third_party/gameq_v2/gameq/protocols/aa3pre32.php b/third_party/gameq_v2/gameq/protocols/aa3pre32.php deleted file mode 100644 index c2d8945f..00000000 --- a/third_party/gameq_v2/gameq/protocols/aa3pre32.php +++ /dev/null @@ -1,425 +0,0 @@ -. - */ - -/** - * America's Army 3 Protocol Class (Version < 3.2) - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Aa3pre32 extends GameQ_Protocols -{ - /** - * This class is no longer valid - * - * @var int - */ - protected $state = self::STATE_DEPRECATED; - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_ALL => "\x4A\x35\xFF\xFF\x02\x00\x02\x00\x01\x00%s", - ); - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_all", - ); - - /** - * Default port for this server type - * - * @var int - */ - protected $port = 39300; // Default port, used if not set when instanced - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'aa3pre32'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'aa3pre32'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "America's Army 3 (< 3.2)"; - - /* - * Internal methods - */ - - /** - * Called before the $this->packets are sent. - * - * @see GameQ_Protocols_Core::beforeSend() - */ - public function beforeSend() - { - // Encrypt the data we want to send - $enc_data = $this->ssc_crypt("\x0A\x00playerName\x06\x06\x00query\x00", TRUE); - - // Apply this to the packet - $this->packets[self::PACKET_ALL] = sprintf($this->packets[self::PACKET_ALL], $enc_data); - - return TRUE; - } - - protected function preProcess_all($packets=array()) - { - // Check to make sure we have zlib installed - if(!function_exists('gzuncompress')) - { - throw new GameQ_ProtocolsException('Zlib is not installed. See http://www.php.net/manual/en/book.zlib.php for more info.', 0); - return FALSE; - } - - // We only got one packet - if(count($packets) == 1) - { - // @todo: Looking for example to test and verify - - $packets[0] = substr($packets[0], 10); - } - else // Multiple Packets - { - $packets_sorted = array(); - - // We need to sort the packets to make sure they are in the proper order - foreach($packets AS $packet) - { - $packets_sorted[ord($packet[10])] = substr($packet, 14); - } - - // Key sort the packets - ksort($packets_sorted); - $packets = $packets_sorted; - - unset($packet, $packets_sorted); - } - - // Merge all the packets and decypt the data - $data = $this->ssc_crypt(trim(implode("", $packets)), FALSE); - - // Decompress and return - return gzuncompress($data); - } - - - protected function process_all() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_ALL)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Let's preprocess the rules - $data = $this->preProcess_all($this->packets_response[self::PACKET_ALL]); - - // Lets parse out all the data - if(preg_match('/attributeNames(.+)attributeValues(.+)resultCode(.*)/ism', $data, $m) === FALSE) - { - throw new GameQ_ProtocolsException("AA3 Packet response is not in a valid format"); - return array(); - } - - // Init temp array - $tmp = array( - "keys" => array(), - "values" => array(), - ); - - // Pull the array into named vars - list($all, $keys, $values, $resultcode) = $m; - - // Lets look at all the keys - $buf = new GameQ_Buffer($keys); - - // Skip - $buf->skip(4); - - while($buf->getLength()) - { - // Pull out the string and strip out any junk - $str = preg_replace('/[^[:alnum:][:punct:]\s]/', '', trim($buf->readString(), "\x00..\x1F")); - - // Do not continue on empty strings - if(strlen($str) == 0) - { - continue; - } - - // Add to the temp list. We will clean this up later - $tmp['keys'][] = $str; - } - - // Now lets loop the values - $buf = new GameQ_Buffer($values); - - // Skip - $buf->skip(4); - - while($buf->getLength()) - { - $str = preg_replace('/[^[:alnum:][:punct:]\s]/', '', trim($buf->readString(), "\x00..\x1F")); - - // Do not continue on empty strings - if(strlen($str) == 0) - { - continue; - } - - // Add to the temp list. We will clean this up later - $tmp['values'][] = $str; - } - - // Combine the keys and values - $tmp = array_combine($tmp['keys'], $tmp['values']); - - $teams = array(); - $team = FALSE; - - // Let's parse the combined array and make the result. - foreach($tmp AS $key => $value) - { - // Is player - if(preg_match('/^player(\D+)(\d+)$/', $key, $matches)) - { - $result->addPlayer($matches[1], $value); - - // See if this is a team value - if($matches[1] == 'Team') - { - $team = $value; - } - elseif ($matches[1] == 'TeamIndex' && !array_key_exists($value, $teams)) - { - $teams[$value] = $team; - } - } - else // Is server var - { - $result->add(substr($key, 6), $value); - } - } - - // Do the teams - foreach ($teams AS $teamIndex => $teamName) - { - $result->addTeam('name', $teamName); - $result->addTeam('index', $teamIndex); - } - - unset($buf, $tmp, $data, $keys, $values, $resultcode, $matches, $teams); - - return $result->fetch(); - } - - /** - * encrypt|decrypt the buffer. - * - * @param string $buffer - * @param bool $encrypt - */ - protected function ssc_crypt($buffer, $encrypt = FALSE) - { - $master_key = pack("H*", - "f5c5914b27235dc0dc274200ddd187c32fe02aed5fc5c079518f49208e4c5548aaef313c5d2e7c91dc580d3cd9e1aec577595325d3c5c84b44a020802becb17e". - "7d6b6b87e8a4ebc8e4cafbaf5720f9600818b334ad2695ba0f19e1fbd48d0139f05e9059e98a15c79ebabb4f3aa8039d8720aef2bf1b4693a67a20a114b8505b". - "693cf5b24a236503582ecdb8109a7d89a8d90d660b96435b4656ecec3fff2086e94c54988843d2aa55adefb2d47fc804c0024a7897e993b2326e8990e425f7c8". - "38aef55f2002f22d84479f43849de260a8a2de6a7de09225c275a172729e65be687182bde68cb17b3fd77bf513c8045f0b6696d3a501b255db0632e36c0e7806". - "c5c193b5b9a9c621f0ac9a0ee72196edbb336e7431b75eba95d02191048ab7c3874578218d79a2623e308184fdac98a1568c09b8907d8411e29c53823a3a68bc". - "c785547ebb29401822da7fa59c6fc412cf2a9201f31336bcdffe78501058b1d7814e920ceee7aca8fa798f10f0a8ba19a1deae864e1c77f974880e5571a4380b". - "52d3357ec8cbf8ff6ff7e8f3fa6223f923e4a7bb1918054bcd2a115e466307f39d964c051983f8b2e5db0b39332ec08c94d9b36a4594ab5e868bc888e4586687". - "b6e62b2bb06ad0903544e379d744896f95346a0238b2b72c6d38ed1bf011185bad1910812cfe2c5b38db10433088f2e5a3746e7302467d35e8f07722fad1f7d4". - "283fbea23fa6f50f710491b1f0a8dd3a187939e7f344de57c256ffb063791fc556d3791570a873537c3f05f8ca08aa1eb2e3f641e0fb46fde7394f8fb4c216d7". - "55c020b405a21b8e4340136fc9583800afd87a677d3d9b6b95585ba502d6db2dec504f25b612340e29be64700682f4f012908e2672916ba83d35deb58d826d83". - "d75a61f726876747d78df10a31f6acb36cb64dec47b7da11c7e7177dcc097965a50065e8e5f91732e20647604c00c0fa451f7ee140d93515b7b5e6f9e0c92ad0". - "29648ab1e0ea363c5a19d12832c54c0ae67baa7e029217ede5f97cd07ebf3aaf14c020f4646e3792e2472409299868b9ee1ce7a69a30203218289523d848a2ee". - "42b96edf05f24182491dfb048c17f815aa8983d9ab72723defbe9750cd694bc1318c92862ed7b7ab1e37472b986a7f4745224fd723e4e6ef53ff6d5f51f1b8cd". - "34b32b9ac92968e5ec8b631aa750e7cec51e7fddca5da1cdc836c0243ab2a2f86d072479c117738fafba4d72db6fee13274d652a7c76ff962c1389b32f95f3c0". - "04d178b71646fe084507e7dd4b4db98405cb72399f78f989c188fb2ed6e18e5aa417adae504d33ad8414f9e3a6e466837062e8ea91664f63134539679b119d6b". - "3918f833ceddc249933b0ae83e0965b38fb86d3da02622d02f57c7282e5f0cdb18f71e7450c538ddca55588575f80754dd0c89840bcf7e246e8f041309069f15". - "a49c27fa0a5913c72be881ae27ff6b0332701d96dc295576d2a9bc0fd266f5604da647f78d1c2ced95c4cf8a929c55bf524198898b444c67040d7c7debcc3cc9". - "7cab1a8fe190f4db097beaccea9a34e38380b43bd2b2bf98f471c02894aaaf3944680988497aa74d293238d503a4df19d90af204fdcbb1875170a96b7f3e288c". - "0f24e1c8b9ce4f77f2b03944c2abbacba69331a244923c38f731f368d10eca82dd503bdece016064c68cb38a4e3408712959cb5216dc42bf5365eb789c484bcc". - "5813a1f1680fc5606e8da06bd5a68a73bd593fcd4aeb9aca06bb258f84a38dd0d4c6c0c355c4d5e0e1a97abaa11869f26285a99db4dfb8eab0b0f53e80d2486b". - "9a6cc63affac0b830b12434ddbc1c4ef3ee46af67fcc711b88a352d2b324c0acfb35bfbe74865afd7f3293a944cd9f69230a206c5112ed9858497ddc118c0338". - "63f1a974b033a225c74e83c9d1bec1a3e6a7b2b7ddab58aec40fe4bed9e2fd1beaded608c695dafaf4d683fdf3b9175d1283d7d99b47c40209a555c317e29bad". - "574ac49e78ae91896b527d27f04d89b10d5f754b953d1218bf01fc06086c031ff334eab692e9c6fb221ac0f3027283ac5350d860f2d6125d31edf4b7ac806f21". - "abeb04f84230e8c17455e54a27d6862cfb3279370eae1cdb1f84c10209e89241182c307b45a6b97520a62bc263c66f78d27b52ad9728f5d78c1626297b1d1cdd". - "e47fd67d9f1f4846a3643810359f2cc6b22a662683836eb48f6e1605be3a830fe29f0c54412e7d82aefff9748a2fddb368dd0103161e2a17da69216e22adf6b5". - "7ce255e400279188655820eedd5a1935aa3d8cf621fa312bab89cbb3071bfbe7e0635126de8217bd5c342f35824511769ac6b72de09b87012cd85f2cbef53e11". - "9aba484771b15bddda183501230ae6a16fcde55a161df16f178e04478a3711437dc91eeabe92e14b44d2f49036532be42c425346df9d91288aa409a63272e061". - "baaaca491cc04c44b2ac739290baa76d9fdc7b66733548af6411a6ba790c4962ddf033e63fab462bc0ccbfa45d45ce377d32f4c7e905cab5fbbb524f8c2907d0". - "41b304d1f38f348efd34a7d51c118445d05353b5f0449f368450782df457ca55169bdfa817a94e1082faf4115cf3d6d890481affb2feb95145691f152485465d". - "0f8dba4cde2079784574fadbe805222e3a132934f1a419cda032b310fd7dfa2830d3f3385d646ba0c373cba4d624a6267300014cdd2dd5e87999aa5b0e5df0a8". - "de50f3473918474ccf82f9c8ab9f31379a9d8d00bead3bc8b9d00f4ebba9c7b0ea882454e3a785e096d7887b3a507f089dba88925df12c633241ed2f9f68905b". - "66775d1d0ca3cc312f7be8641856be8de24248e55dd737df8410e23e9457024f534261f09ab278821b1c89da824f7f546a4163f4d53ccf07ee9bd59adb673822". - "87092b94a7847141a796a6abf90f7bfa5d8967bfba2275283863bfc3f8283f0e5b223748a55dff04f3c6bf228bb1e0bfd2c80289abf5819e165268b4e687bcf4". - "a33f1c42c47a6236ca14c26778ad2cbe013c20807e45276d49a4e0df7df7c42d2c73f298f61fc8e778ba953a71c6b7d1779624552df0f3896a790671a3a981fa". - "17914d856321d0997ff4b2d05944335ceac60b63b1d827eab5ef7483990e9bd1b5453a473e1efd476ba1e093466cb21dc72e35dc12bb8c8d3bb29db420251590". - "32441b8a7e9458cad9cdc1551ce52312bb27d858a8ae319e525b38f20242a60933b2a21bd858e147cc6ee702983c84bf535d1575a54dc46c03cdb42a39d1a64e". - "433d9bea41f9915f7d9d462d4308baccb19bb1adc3e0125715950f7c7f8b54312826204fd512386da587bad7bf81069dc554fd8fd77153832225e56a7fa4046b". - "d588ed258dc7e54ccf1c021f9800376376bdcfc62116555ab0e06b3161b3b7a6a7a87de2371215207c43fce54c82feddc5d444b08f6a30c0095007d526da1b02". - "41563a9360f86ef3b824294bd174679f4dee74912acdeb00ac96a713ad86dc212a544b7420fa6c83d5dec48400e1f11f8163e20c932bc893820a8261939e0f85". - "fdb416c6a0a18cc0182d675702a8362694f23ce686962150f862357fe84a0b572068c7e0578909d7f82c87cd17e7ef50e5566eab694ac76edb4b6d8a85cd2910". - "0b93272b0a524a24db8db7d4622fae63d982e4090fb519e30736d5b5152d58a234919d216d0294628841cba91ed72d985ba92f7cc548378e7ddf812816ad99dd". - "27adffdf5b6d762a79a942d8af9a8f0ac81afc98869dcdcc06835478947ced5ccbb22d02624e207c774042fa8c133221c362bef69582c52ca9c014db1ec2d351". - "a1d72bb01c06e32ca0a4ecfe923737f0f7145b27c943a9be1f174dd46d3af58e7a2f612177affd11ae7e1b9231aadb46bcb732ee79de7e62f467721f06d8e9e5". - "59b526bb702ddbc0f0b46a2162458c15c0154cbb1b1edad3fa198a0781279ecc5e5391269c335bc94b2f21da781cf943cd0e700206128fe1f1e3af4e70bfbaec". - "1c7ae4884c7e7544050036b001f87fc2f10762888701c160010e7691ea2b53b646d22178ebf1a56eb9cba86ffa2b570d846e231037d403298103c61732b04113". - "ff7ec74e0a671332f7df9da231f995c1fb53523c17c23105312b7d8ab63e5f6a0e7b9d106f3ce575d14befb3a5803aabcc9edb5f1ddf9dcabff4efbd785b169d". - "f7fb1b991faf63f064b5fc8f2c7fcac4b35a61f19c92dec36a6aadf02dc3942dde51d7225aefeaf6b7527183c2adc832c6bc8735bc7be2c18ad3d70653f91581". - "ce42a275ef6715932ae7513d0ecb726be54c167cc89445a08cb8e12fc583aee815b3947bd1ac781fcbfbdda25fe3e931a21c47058197ceffbe9bd2ac6394b2d5". - "95c3e10076c3aceba33b1556029edfbc04849e0d66713f7beeb1517dcd43279a5073ec9fa221bfaceef0f639e771a44156778cbb696af28e2437eea3fc025d27". - "70b1409d978e4ec808c58288d525ac977db0ace80d9554925bf8767b8e91a9bf1ed25deabdbb93315ca08f711ae3f768a911eeacd93bfa6db3957da83c0fd945". - "a7e596b66530aa7347e04590fd31db6b49485a9ea8208c0aab4068f482b185aaed6ee69e32f9ff7b882763da34f6e3bce94c79353ef6849d47e6345d8727e076". - "f1aa0133c2399e4d777525fe9aa29e75d23df6e829f9058580413d5c24f85568beb1343430f393adee28ab54e220b4c884fa6ebc2825705f863ba7d82977f653". - "edb2088abd84ad52a1810a52abc6e7c3b5687f3bf4744941ce48c876205f2497b641e6e4bb565ab816425c348e1f034104efda9a21723b00cdadc6ed2af6b225". - "524ae512afba6bc19c471e14bbba042dba641424005a816f25aee44ee84cf2f729b79b1b9d58218f0274d92168c9bb1cd1c141b5f8341a3a4dc78c0ddf08dfd4". - "110b4eb0b71b265fe70aa5a4b2186cafad5ff94dafd5b4b4560bac45cb47c4c863274ac2d84af46b75bfde496d39984ff0af8ab7d98bc12c02ce782b23268d03". - "864826b0201d8d1e0c09c9ab229a2f7fe1504795bafa8b8ae13fb046a2f35233a49b772b57862ada835951742439693ed9f3a080aea7a1309de4ae04b1ce3d78". - "72cdd85a3544906afaf55aff8255bdb2367c7ecf184c91c8f4c60a1301b80f8bb9f0ff6d80ac6e1c9d6c9fafbc65199790e0a9c323e68b105f5c56eed2f60294". - "5ab59d79698829ba092cc97f37dd023595d3fa014e718cda23d6bdbbfd70c2c6cc1b9121d22eae0bde7b94277dc8e5e096d60351f2740ddb986c7e10e0af8a40". - "e9bd526f863cde028dd253e18013d3c76c2006a9ab9ec3e7b6b1aca865b2ace8c8debb50ae1efbc0e49dd69f128c28bd02d79f22717e2679d5142540733cb278". - "0969944106122d5f2baf97f7e09ef67b894cd191411126ad962e4b9c5a0bbe83215563662ce5f063ce2a76c2e09613539fbb094d389e739ca0a3fc34bd1692ba". - "f0601e2122a70fdf68ede6c431090896622362c59801000727718f4b551f32340fc5f740e15fc0a023791aa57a6cc97af3077f5d71d33cbc864049b30cb11ea5". - "23c15141ea5ac620aec5f81e6661bf8f01a3c817ac1ab592570b63764402e4934d776df03cadae448c5d9082c30c00737e4bbe5c184a1167507d9b99bdd05592". - "456ac25dadb5beafe282028611db969c44db7bfb2cad349c0ecbebc281a00ad4f70cfd889b3533833ab845f86403e6a1970da6b5c8b8e82e9f42a82c7c14e535". - "16b3d9efbaae6ca6b9c93977f17f58ec29a1a8bb188fb15f377bf50d37e84781ca1716052f657a361cbe44eb227002a57390873e54b8695f76fe0f84f873e021". - "c92945f3d7b54861be3c237701c140c3a4e1b84fa4bab910cd265393e0172293d6fc40fa1872e175d7d3f06153a9eca3f8db85c2166f68415eda3bf4aee35adc". - "0231cd6cfe5d3a23b51fb0105176b9cdadc28304d27fef698cf4155235d07ecfaf5a2c5f8610a63ee809b0e0260251c33873dceebdda1ec3725d1376031e45cc". - "731a870b39edc97b549b96624c891984acf7a422584bc56f2104256f15da552d0a8376a546b6966153728ca1f38514df0d458375e99bc01fa498b07abb33803f". - "da07c4149e6e5773f9ec65ac3c87ca7c515f263de3cda2d53edbc20c47486ee33f9810c8226bbc9c52fcadb1f01fe28bf099b8afb9f1798e0b9815210c559187". - "c562b5e45350a5d0708c2fb96bad405ef4b8b535066ed02da198e4a3a4eaf075450c87f6d9840c8e00b8e316bcc7a5c6113fefbd72b0c7f6860fcecc8a3f33fb". - "a2999e4f3f3e3da5d7bfcf5d22a93f4d16ae6dd053685dfc7223628f92086735d09551bd29e8d0f537d06f33536fce8360d7443f583e9079685efce0347c1ffa". - "fedd0b7d1125f0dfc9bb21460079f286abbbeb549bb744aeea0b7a6bc66a272c8af945621b57b8380d40fa067c3060b9d44b79bd4333ec96d47632124a9aad0a". - "2df287eda9312f70f12f544fd7bdef9e6cc5e110effb8dbdebb821571f0fa95301db9da0bb60b77af6d5b7de00ca26039f1dda92f7a777c75d02fc340f1b81b5". - "e7c5efc6aaa6ffe3b77db348b7a5973a9465cb1e01841fa10f398318bfb73a4f8f53a4bded656f35db0ef00685826d8eac3aa0941623b3401ffdaba927bc91f4". - "808818548a60f653e9f340f79e40d666525923c4847ac3c0a9b36f3069620b0aea677ee7afa2c333987d9a5afade1b0e1e22ef7470228b07c9f482a6c343a37c". - "462a749c02d4cc86447cc16c3c68955afa80e63a3a41aaa1375c7ca0cffa0335e96e599e1b6841ae5693b5fa6ff437c3c1dca20075b7a58aafa81845af0aa8f6". - "30520d89a362d667447045c2b39f88f573f6b76b95ea4a98950ad797570b841975e9841306223dbefd21a4f092d69452c4539c664e27e110622ae7a7db5073d6". - "17eb023b36f28a13eeeebdbd964df63dcb18762950b6bd3eeead2a25b9bba48060ac8b82af3f41ecafbb7134140ca8cc687b92eded8bdabd9567e50950ed617a". - "a114d3db8648f9ab48a622456aec56fe79cfa6225fc7fd3fb0607f9dbc1bd861b316600fc10163fe8098ea685bc3fe06435f51cb1ce7ffebae67b3114fadf8c8". - "808a4044bb06638d05bc9a73c44c5b1eb7c83cdb4bde51ffa85413a97fbd534ddb17dc899fc4e2ced6ed81eeb117b4c77f9ecd03251367649a5649ec58567907". - "4fc8c2702dc42a58308f4023fb2cd30c79ecb9a952cde77dfcf92d8ef234811c327112abd568c49d4bf693f611d07e433fcd0a396530c6a279eb3ba567d780b7". - "271b6bfc7f1683a6b9159e143788662e8c5f73dd25ab623633efe781edd647b32003c9f3eaf236d968244e4561bc855848b839bfb93af2ea3e230a30089230c4". - "2e593ed3b9be53d677a7c9da744ee1961aaccac237f9e0bc1f886a92d5f335c6c0b0250ea76fbdcd85ae9cf6afe7ab25fd6b4753be6505b986757b003b94a089". - "d6a42b1fb24d2249ec917bb0ad50c8bd31265f82071a0816c3f8985edf0311205f83eaf8ff5587a3c7c24938a3f0cf9ff438b567d71407a51292e6d7e3f939e6". - "cdbecd49e913793f73cb964406934907ca4d48f44bec301bdf0110986757fcac6c2cca84eb7c5fad1662d1a833d24fa356771d6b772759a4837d9872d23ff1ab". - "219597aadc062f317d6cbc044bf65dc5ddda95ddc34d68584b7db991c8441a43e0511f71b88dda141f36b7cb326650c3244b989f1b992d2baa318e2a76dd1c34". - "a946c843255f65c6896eac3a6774ceff50b6f66b752672f5ce8dc84149ba6b227da844254d01bf470f6c987e8b5df2168414bcee11ad8c131d16e43addbdd493". - "595117f4f211c5d6460ee1be41e72b42c21252ce6dcd9838e53b0e1fd8d1864c2d3d219b82d42d0446865848431658732a78f0d9348f8044fa7f576d11562d25". - "d7b681f714c4b43532543d27069a21d1d152e646c56d75229bb198f87676108306e68fa49751f3b1d678bbf1ea38b2e0712d896882b5ea1494136f23a7e1d528". - "ca456c6c2a2cfc8cb6b6e7e6526aaa1da082653492b624936213569892706d8f9c6496b1193ec5a4294e3c1da14b25c24337cf9bb3490ea3f8a54e0a5b9f77af". - "fc70fe8dcb7687a9f45c7ae3ee8f2a94fa58e6c920cce1f447fd60526fa71b6f1048a3dcc7680e3b20ac66d78290bfc3878e72d4876e014036b0b80b6be4bf2e". - "a358125bea811b51af76a0077b3a615750a9ca3368d1d17e060a0d37bfd3b13c91412ca83298b06aea3048607f718c04667dcfc7faa4ac5a594be1c1551140ba". - "9c1ea7cebc074b1fbd338eef831fa3eb1f39088bcf1cf13bf706b1d287e12b165f4fb3e6c4586067c5e2f461c4cc86400b456428e8767c1b57a7bc3e64a8abe6". - "d253646f8796763b2a33de35c6f1667d06f30bb12c0fd0e28e4859ebdc2f96236af4a895d9a7d6fb90cbb60084db28a0c628faf7653c316ec69b5c5103aea495". - "792efd58ec42bc950f8608d5fa6834aab7bd2aaece33b3e16756f518a5410e8957dd534437e8c152451d86beb20124e8fb9e672d13fb7e98e153c124fdb2eaf7". - "f94a23efffeea25ec31f821e492d9de00a6d056c67e565f734f864d425035bb13620b7a1f44ec02ab7a6b1c4a38511b6902cfcf199d3918eb07da11d634add44". - "0860d123fa2b8003f87270777c6415e32f1b34dd6e1e22df3a78684e1169fce84b61cf461544f4e891fcd9d1f5a1e5fef148aeddbfcc922f5d7bfd3bd2480e8a". - "3318c75ce0afc24ca179fc0e832ab64368c174407bf2cd45a72cd5c9e7dd0b9def7500cec54d4d692938a1bb18289189d4b2445640d8abc9a0b70c3ffc8ba3c8". - "d483119a4f63851a57cf30f48c88616785a5ee00cb9221db45dd8dff118ca33bb4ae254937891f2c971edc8614fa3fc43e56f297a44a234fb1737f23d44a15f0". - "6a9e364fe1daa8e28bf72927526296202713f76dc8342e3843483b479ff793697b11a934bdc206905dd020e2f321cf8d65c245a8e7c4275f87301211800f0751". - "4e9cb59b88540f5441e6b09b4b73112d855ba0dffd4affd670c4f76ec11ac07a6cc2201ac65c83b3b3e4dc10d991ef4424cd001d34f0393dc262957df641469a". - "e00f74c527f8c99f50432c5ff4c4260ec6998b7ef2a0223290762126542d8aa89bfd241ac59e3a9a6c6f13afc9d69a771d124d16359525e4b374605b699e32bd". - "fb393d9397767bce32ab2d5557d05c33fa54183b0d5facc73a097441aa34abf7d6ac36fb35d6be7f19d0c26c7ad564c06f8a4f616ff4819c53e8b29e782b8791". - "c4039e5d049bd36819ae6d01a113eae6260e25150b935ee364011558dea97e1ee0e7f2938b7368ad9a5a86bae4f89a9ffbd06638566a785cb6ad3982b133ce6a". - "3edb13aa2c4ad4db7052ac646fcf336b375efb6a360d448862f2b711db3d8e657a706c14013664beae06b1a067fd078b0a8800c01dd610d583bee4fa4634e4f3". - "5251372b8144a7194ed60dc2539283ce909e7d65338a9050b09b66b647f30b6d595d7e03d9a77029afce140df7717f64949ae1362f94602dc2e70840e3117ab1". - "a26cc8e8ffd068ec225f0b75b2de63e3511f4485c87fb0087e4421675f3754bc4bc9c0a38db6392661e8a59802d83f887cf81aa99ed13a10b4b8a176144f76ce". - "3a192cc77b09e3f8a087db488f3d304d048623f46a031ba9251896cd08ff601dd0b933f5110b4cc9d943b5705b2435fa1c0adaad6c3aed88022f57cc3d71048f". - "9d5f420cfaf737b8a9f2434601b296b14384618fa9b76e6acbf1b55ad7130f582f36920a5aff71e15d120b11d6e0dd374554803538f3b12305512cf24322ed52". - "cd7ce5f409efd2f2752684bc326bf4548fa17169028c819ba342ee672682860a6de09752f509caad897484160895dc712b70bd05d588fe218fd85718b9b833ff". - "2c18e2566416ce1e52c3d7dc696cca1ad02b9b99e2953f92d8fe7ac0e4d75bd2ae2834b9ad8e87f179cdaf5e75609abdf1236787fe366347c32991f20c7faf41". - "b65da4ed5edc3cab1134a4ee0a3b565cab7c6dcd6f93feb528ddf0a1e992f6ad4814e51d338433dc5b52fddd8e780a312d12c80c4dbdaf8818b1c84883d8be41". - "186de5fdeeb9c7b7542a8429e53645a313cd8c9a53c3790b9fcf0143421da3bb586762790c91b0110f68b5fd111338560437d7d77457fb5587efb40a90ed1c02". - "838ba4e83b0c6adb175d94b6e14767a4f4a127e80f79be7741f4dc446c520176fd5b0412cc4d7a8f3d293e438d50e4e79e52bbc2c3bc6707d97b6289f1b39733". - "48c9351b66be55b2152bee9b76c42dc057d12134180488f45aee9491fe72f8634e3beeda8006869a829d2d58614150ab489dca7af268c09dde668cc20428ff88". - "366a3c0119446bdba29c39b0723fcd639393d397d138ab241c187beac647d8f73e5e42b3468e3958e0e73908c081ce0b6c894f0409f3bd321807a1633860a8e7". - "49cb4a10875a65b3f0a073f48f141747c88afe9039ef0795752dbd07ef51a2dadb40bb09bb9d4fcb328f68af28f8d76085fccaef4afe848a93c4cac43f55863a". - "21b540e6d408eb55fdfbd2a0c13fbae6fdf68e51423737f6966105d1ed57570bb521adb9576b06988d7d5a6445fe77d177076d47ca45b437a9780b376d49689e". - "6b0be983d90f46dbf935e14b53f3bf7ac7aec7fc1b92c14f161e59ae2620f7552206f22a365c91476943b8b51e920661efc19d040070407ba1cf011d3a0e072e". - "68d10e064619aa2184d7e848729b254af6b83db15fca2134d0d54efc761fff25c1169d608ed2434de8ae3cafb8c3af0b5b23a16183b5ead5dc5d175c955f4db5". - "454623d611244c462776118992ba03e8e20e6e1d9d6101d2286d7e040d5a56f22d6e3ae86bd6a0605c8b34d7a385fee5f3c9b6d0cf550f7aa67f338d8a014dfd". - "639cade855e8d25df73ea01bc5635bb5e032269b2a10f6b2baea7c4a88ede42caf91d7c9d3b2802608fdc361e23ee8cdcc1c954da86f929e9721130ef6d74e99". - "180f8c8c2263b41f538e105bc5f411f8dd1c2d3e0dc4540ff9cbdb9a6c44524ebcdfe37d9427a43dc24fd28c2fc25baef96490ae847b435ef4eea87db030829d". - "06b4c5d9271c8ffda114c336f5d82f9e6ca0d140112f364b1613cfe84c6e924629cba51a7d21f92ce26802bda0651340a8aad0c1ef439acc5552634304321cf6". - "02851751630d671a8cce7028f1cc6fdbce64f762c8ed522c2a81c2886986999a85d41a87d2ba5281dcbc2dbd728559470017e12fd70a97a771de499d2953c49b". - "0e60abac5ced203dd26bb75df922938723b1341bb07b0250d7af1bf91788994f8ed193221dd829e6665b114763e490fd8482955b097ac3b5b124bf92ae8ce902". - "1897b67db820cbfd646fe2c61e63baa972651a47bb1aae56f5e623a1167beff84166ea78cc9854b21a9478ebf3a1429226213c20a7a9ce8031eced508b937263". - "1357591069d5c482c0f6f99e4a6084f34fdab7b26399b4efcb0e5217e4e9115d0f6011bcfe55e0f05d3d8850febab0a6100bab8142a3913662a568f9d32367bf". - "5db46b6572cb76bd6a49d84bd567e1f834bbd705dd395c1609e9eba7fe8b9c59f1c4cb2561461204805c25a384140314e515f84050949529050279393884f8d0"); - - $game_key = "c6mw4it2kg7sz5o0813d9qyufenhj\x00"; - - $buffer_length = strlen($buffer); - $game_key_length = strlen($game_key); - - // We want to encrpt the data - if ($encrypt) - { - for ($i=1; $i<$buffer_length; $i++) - { - $buffer[$i] = chr(ord($buffer[$i]) ^ ord($buffer[$i-1])); - } - - for ($i=0; $i<$buffer_length; $i++) - { - $buffer[$i] = chr(ord($buffer[$i]) ^ ord($game_key[($i % 128) % $game_key_length]) ^ ord($master_key[$i % 128]) ^ ord($master_key[$i])); - } - } - else // We need to decrypt the data - { - for ($i=0; $i<$buffer_length; $i++) - { - $buffer[$i] = chr(ord($buffer[$i]) ^ ord($master_key[$i]) ^ ord($master_key[$i%128]) ^ ord($game_key[($i%128) % $game_key_length])); - } - - for ($i=($buffer_length-1); $i>0; $i--) - { - $buffer[$i] = chr(ord($buffer[$i]) ^ ord($buffer[$i-1])); - } - } - - return $buffer; - } -} diff --git a/third_party/gameq_v2/gameq/protocols/alienswarm.php b/third_party/gameq_v2/gameq/protocols/alienswarm.php deleted file mode 100644 index 6d814448..00000000 --- a/third_party/gameq_v2/gameq/protocols/alienswarm.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Alien Swarm Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Alienswarm extends GameQ_Protocols_Source -{ - protected $name = "alienswarm"; - protected $name_long = "Alien Swarm"; -} diff --git a/third_party/gameq_v2/gameq/protocols/aoc.php b/third_party/gameq_v2/gameq/protocols/aoc.php deleted file mode 100644 index 009dc669..00000000 --- a/third_party/gameq_v2/gameq/protocols/aoc.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Age of Chivalry Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Aoc extends GameQ_Protocols_Source -{ - protected $name = "aoc"; - protected $name_long = "Age of Chivalry"; -} diff --git a/third_party/gameq_v2/gameq/protocols/armedassault.php b/third_party/gameq_v2/gameq/protocols/armedassault.php deleted file mode 100644 index 48655f60..00000000 --- a/third_party/gameq_v2/gameq/protocols/armedassault.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Armed Assault Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Armedassault extends GameQ_Protocols_Gamespy2 -{ - protected $name = "armedassault"; - protected $name_long = "Armed Assault"; - - protected $port = 2302; -} diff --git a/third_party/gameq_v2/gameq/protocols/armedassault2.php b/third_party/gameq_v2/gameq/protocols/armedassault2.php deleted file mode 100644 index 203ff1b6..00000000 --- a/third_party/gameq_v2/gameq/protocols/armedassault2.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -/** - * Armed Assault 2 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Armedassault2 extends GameQ_Protocols_Gamespy3 -{ - protected $name = "armedassault2"; - protected $name_long = "Armed Assault 2"; - - protected $port = 2302; - - protected function parsePlayerTeamInfoNew(GameQ_Buffer &$buf, GameQ_Result &$result) - { - // Read the buffer and replace the team_ sub-section under the players section becasue it is broke - $buf_fixed = preg_replace('/team_(.*)score_/m', 'score_', $buf->getBuffer()); - - // Replace the buffer with the "fixed" buffer - $buf = new GameQ_Buffer($buf_fixed); - - unset($buf_fixed); - - // Now we continue on with the parent - return parent::parsePlayerTeamInfo($buf, $result); - } -} diff --git a/third_party/gameq_v2/gameq/protocols/armedassault2oa.php b/third_party/gameq_v2/gameq/protocols/armedassault2oa.php index afef445e..e527a38d 100644 --- a/third_party/gameq_v2/gameq/protocols/armedassault2oa.php +++ b/third_party/gameq_v2/gameq/protocols/armedassault2oa.php @@ -3,28 +3,48 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Armed Assault 2: Operation Arrowhead Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Armedassault2oa extends GameQ_Protocols_Armedassault2 -{ - protected $name = "armedassault2oa"; - protected $name_long = "Armed Assault 2: Operation Arrowhead"; +namespace GameQ\Protocols; - protected $port = 2302; +/** + * Class Armedassault2oa + * + * @package GameQ\Protocols + * @author Austin Bischoff + */ +class Armedassault2oa extends Source +{ + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = "armedassault2oa"; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Armed Assault 2: Operation Arrowhead"; + + /** + * Query port = client_port + 1 + * + * @type int + */ + protected $port_diff = 1; } diff --git a/third_party/gameq_v2/gameq/protocols/armedassault3.php b/third_party/gameq_v2/gameq/protocols/armedassault3.php index 844bc05b..5bbca429 100644 --- a/third_party/gameq_v2/gameq/protocols/armedassault3.php +++ b/third_party/gameq_v2/gameq/protocols/armedassault3.php @@ -3,31 +3,30 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Armed Assault 2 Protocol Class - * - * Special thanks to firefly2442 for linking working python script that - * supported both GSv2&3 - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Armedassault3 extends GameQ_Protocols_Source -{ - protected $name = "armedassault3"; - protected $name_long = "Armed Assault 3"; +namespace GameQ\Protocols; - protected $port = 2302; +/** + * Armed assault 3 dummy Protocol Class + * + * Added for backward compatibility, please update to class arma3 + * + * @deprecated v3.0.10 + * @package GameQ\Protocols + * @author Austin Bischoff + */ +class Armedassault3 extends Arma3 +{ } diff --git a/third_party/gameq_v2/gameq/protocols/ase.php b/third_party/gameq_v2/gameq/protocols/ase.php index ef458661..abc47818 100644 --- a/third_party/gameq_v2/gameq/protocols/ase.php +++ b/third_party/gameq_v2/gameq/protocols/ase.php @@ -3,162 +3,215 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; + /** - * All-Seeing Eye Protocol Class - * - * This class is used as the basis for all game servers - * that use the All-Seeing Eye (ASE) protocol for querying - * server status. - * - * Most of the logic is taken from the original GameQ - * by Tom Buskens + * All-Seeing Eye Protocol class * * @author Marcel Bößendörfer * @author Austin Bischoff */ -abstract class GameQ_Protocols_ASE extends GameQ_Protocols +class Ase extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_ALL => "s", - ); - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_all", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_ALL => "s", + ]; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 1; // Default port, used if not set when instanced + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'ase'; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'ase'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'ase'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'ase'; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "All-Seeing Eye"; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "All-Seeing Eye"; + /** + * The client join link + * + * @type string + */ + protected $join_link = null; - /* + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'gametype' => 'gametype', + 'hostname' => 'servername', + 'mapname' => 'map', + 'maxplayers' => 'max_players', + 'mod' => 'game_dir', + 'numplayers' => 'num_players', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'score' => 'score', + 'team' => 'team', + 'ping' => 'ping', + 'time' => 'time', + ], + ]; + + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { + // Create a new buffer + $buffer = new Buffer(implode('', $this->packets_response)); + + // Check for valid response + if ($buffer->getLength() < 4) { + throw new \GameQ\Exception\Protocol(sprintf('%s The response from the server was empty.', __METHOD__)); + } + + // Read the header + $header = $buffer->read(4); + + // Verify header + if ($header !== 'EYE1') { + throw new \GameQ\Exception\Protocol(sprintf('%s The response header "%s" does not match expected "EYE1"', __METHOD__, $header)); + } + + // Create a new result + $result = new Result(); + + // Variables + $result->add('gamename', $buffer->readPascalString(1, true)); + $result->add('port', $buffer->readPascalString(1, true)); + $result->add('servername', $buffer->readPascalString(1, true)); + $result->add('gametype', $buffer->readPascalString(1, true)); + $result->add('map', $buffer->readPascalString(1, true)); + $result->add('version', $buffer->readPascalString(1, true)); + $result->add('password', $buffer->readPascalString(1, true)); + $result->add('num_players', $buffer->readPascalString(1, true)); + $result->add('max_players', $buffer->readPascalString(1, true)); + $result->add('dedicated', 1); + + // Offload the key/value pair processing + $this->processKeyValuePairs($buffer, $result); + + // Offload processing player and team info + $this->processPlayersAndTeams($buffer, $result); + + unset($buffer); + + return $result->fetch(); + } + + /* * Internal methods */ - protected function process_all() - { - if(!$this->hasValidResponse(self::PACKET_ALL)) - { - return array(); - } - $data = $this->packets_response[self::PACKET_ALL][0]; - - $buf = new GameQ_Buffer($data); - - $result = new GameQ_Result(); - - // Grab the header - $header = $buf->read(4); - - // Header does not match - if ($header !== 'EYE1') - { - throw new GameQException("Exepcted header to be 'EYE1' but got '{$header}' instead."); - } - - // Variables - $result->add('gamename', $buf->readPascalString(1, true)); - $result->add('port', $buf->readPascalString(1, true)); - $result->add('servername', $buf->readPascalString(1, true)); - $result->add('gametype', $buf->readPascalString(1, true)); - $result->add('map', $buf->readPascalString(1, true)); - $result->add('version', $buf->readPascalString(1, true)); - $result->add('password', $buf->readPascalString(1, true)); - $result->add('num_players', $buf->readPascalString(1, true)); - $result->add('max_players', $buf->readPascalString(1, true)); + /** + * Handles processing the extra key/value pairs for server settings + * + * @param \GameQ\Buffer $buffer + * @param \GameQ\Result $result + */ + protected function processKeyValuePairs(Buffer &$buffer, Result &$result) + { // Key / value pairs - while($buf->getLength()) - { - // If we have an empty key, we've reached the end - $key = $buf->readPascalString(1, true); + while ($buffer->getLength()) { + $key = $buffer->readPascalString(1, true); - if (empty($key)) - { + // If we have an empty key, we've reached the end + if (empty($key)) { break; } // Otherwise, add the pair $result->add( $key, - $buf->readPascalString(1, true) + $buffer->readPascalString(1, true) ); } - // Players - while ($buf->getLength()) - { + unset($key); + } + + /** + * Handles processing the player and team data into a usable format + * + * @param \GameQ\Buffer $buffer + * @param \GameQ\Result $result + */ + protected function processPlayersAndTeams(Buffer &$buffer, Result &$result) + { + + // Players and team info + while ($buffer->getLength()) { // Get the flags - $flags = $buf->readInt8(); + $flags = $buffer->readInt8(); // Get data according to the flags if ($flags & 1) { - $result->addPlayer('name', $buf->readPascalString(1, true)); + $result->addPlayer('name', $buffer->readPascalString(1, true)); } if ($flags & 2) { - $result->addPlayer('team', $buf->readPascalString(1, true)); + $result->addPlayer('team', $buffer->readPascalString(1, true)); } if ($flags & 4) { - $result->addPlayer('skin', $buf->readPascalString(1, true)); + $result->addPlayer('skin', $buffer->readPascalString(1, true)); } if ($flags & 8) { - $result->addPlayer('score', $buf->readPascalString(1, true)); + $result->addPlayer('score', $buffer->readPascalString(1, true)); } if ($flags & 16) { - $result->addPlayer('ping', $buf->readPascalString(1, true)); + $result->addPlayer('ping', $buffer->readPascalString(1, true)); } if ($flags & 32) { - $result->addPlayer('time', $buf->readPascalString(1, true)); + $result->addPlayer('time', $buffer->readPascalString(1, true)); } } - - return $result->fetch(); - } + } } diff --git a/third_party/gameq_v2/gameq/protocols/avp.php b/third_party/gameq_v2/gameq/protocols/avp.php deleted file mode 100644 index 5c0164f3..00000000 --- a/third_party/gameq_v2/gameq/protocols/avp.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Aliens vs Preadtor Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Avp extends GameQ_Protocols_Gamespy -{ - protected $name = "avp"; - protected $name_long = "Aliens vs Preadtor"; - - protected $port = 27888; -} diff --git a/third_party/gameq_v2/gameq/protocols/avp2.php b/third_party/gameq_v2/gameq/protocols/avp2.php deleted file mode 100644 index 00204073..00000000 --- a/third_party/gameq_v2/gameq/protocols/avp2.php +++ /dev/null @@ -1,32 +0,0 @@ -. - */ - -/** - * Aliens vs Predator 2 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Avp2 extends GameQ_Protocols_Gamespy -{ - protected $name = "avp2"; - protected $name_long = "Aliens vs Predator 2"; - - protected $state = self::STATE_TESTING; - - protected $port = 27888; -} diff --git a/third_party/gameq_v2/gameq/protocols/bf1942.php b/third_party/gameq_v2/gameq/protocols/bf1942.php index a9ce3ef3..4cf06c5e 100644 --- a/third_party/gameq_v2/gameq/protocols/bf1942.php +++ b/third_party/gameq_v2/gameq/protocols/bf1942.php @@ -3,28 +3,86 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Battlefield 1942 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Bf1942 extends GameQ_Protocols_Gamespy -{ - protected $name = "bf1942"; - protected $name_long = "Battlefield 1942"; +namespace GameQ\Protocols; - protected $port = 23000; +/** + * Class Battlefield 1942 + * + * @package GameQ\Protocols + * @author Austin Bischoff + */ +class Bf1942 extends Gamespy +{ + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'bf1942'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Battlefield 1942"; + + /** + * query_port = client_port + 8433 + * 23000 = 14567 + 8433 + * + * @type int + */ + protected $port_diff = 8433; + + /** + * The client join link + * + * @type string + */ + protected $join_link = "bf1942://%s:%d"; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'gametype' => 'gametype', + 'hostname' => 'hostname', + 'mapname' => 'mapname', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'playername', + 'kills' => 'kills', + 'deaths' => 'deaths', + 'ping' => 'ping', + 'score' => 'score', + ], + 'team' => [ + 'name' => 'teamname', + ], + ]; } diff --git a/third_party/gameq_v2/gameq/protocols/bf2.php b/third_party/gameq_v2/gameq/protocols/bf2.php index 42bcc724..0610f9d0 100644 --- a/third_party/gameq_v2/gameq/protocols/bf2.php +++ b/third_party/gameq_v2/gameq/protocols/bf2.php @@ -3,54 +3,96 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Battlefield 2 Protocol Class + * Class Battlefield 2 * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Bf2 extends GameQ_Protocols_Gamespy3 +class Bf2 extends Gamespy3 { - protected $name = "bf2"; - protected $name_long = "Battlefield 2"; - protected $port = 29900; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'bf2'; - /** - * Set the packet mode to multi, Gamespy v3 is by default a linear set of calls - * - * @var string - */ - protected $packet_mode = self::PACKET_MODE_MULTI; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Battlefield 2"; - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40\xFF\xFF\xFF\x01", - ); + /** + * query_port = client_port + 8433 + * 29900 = 16567 + 13333 + * + * @type int + */ + protected $port_diff = 13333; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_all", - ); + /** + * The client join link + * + * @type string + */ + protected $join_link = "bf2://%s:%d"; + + /** + * BF2 has a different query packet to send than "normal" Gamespy 3 + * + * @var array + */ + protected $packets = [ + self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40\xFF\xFF\xFF\x01", + ]; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'gametype' => 'gametype', + 'hostname' => 'hostname', + 'mapname' => 'mapname', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'player', + 'kills' => 'score', + 'deaths' => 'deaths', + 'ping' => 'ping', + 'score' => 'score', + ], + 'team' => [ + 'name' => 'team', + 'score' => 'score', + ], + ]; } diff --git a/third_party/gameq_v2/gameq/protocols/bf2142.php b/third_party/gameq_v2/gameq/protocols/bf2142.php deleted file mode 100644 index 05cd4030..00000000 --- a/third_party/gameq_v2/gameq/protocols/bf2142.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Battlefield 2142 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Bf2142 extends GameQ_Protocols_Gamespy3 -{ - protected $name = "bf2142"; - protected $name_long = "Battlefield 2142"; - - protected $port = 29900; -} diff --git a/third_party/gameq_v2/gameq/protocols/bf3.php b/third_party/gameq_v2/gameq/protocols/bf3.php index 40a79d5e..90845159 100644 --- a/third_party/gameq_v2/gameq/protocols/bf3.php +++ b/third_party/gameq_v2/gameq/protocols/bf3.php @@ -3,327 +3,346 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + /** * Battlefield 3 Protocol Class * * Good place for doc status and info is http://www.fpsadmin.com/forum/showthread.php?t=24134 * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Bf3 extends GameQ_Protocols +class Bf3 extends Protocol { - /** - * Normalization for this protocol class - * - * @var array - */ - protected $normalize = array( - // General - 'general' => array( - 'dedicated' => array('dedicated'), - 'hostname' => array('hostname'), - 'password' => array('password'), - 'numplayers' => array('numplayers'), - 'maxplayers' => array('maxplayers'), - 'mapname' => array('map'), - 'gametype' => array('gametype'), - 'players' => array('players'), - 'teams' => array('team'), - ), - // Player - 'player' => array( - 'score' => array('score'), - ), + /** + * Array of packets we want to query. + * + * @type array + */ + protected $packets = [ + self::PACKET_STATUS => "\x00\x00\x00\x21\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", + self::PACKET_VERSION => "\x00\x00\x00\x22\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00", + self::PACKET_PLAYERS => + "\x00\x00\x00\x23\x24\x00\x00\x00\x02\x00\x00\x00\x0b\x00\x00\x00listPlayers\x00\x03\x00\x00\x00\x61ll\x00", + ]; - // Team - 'team' => array( - 'score' => array('tickets'), - ), - ); + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + 1627389952 => "processDetails", // a + 1644167168 => "processVersion", // b + 1660944384 => "processPlayers", // c + ]; - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", - self::PACKET_VERSION => "\x00\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00", - self::PACKET_PLAYERS => "\x00\x00\x00\x00\x24\x00\x00\x00\x02\x00\x00\x00\x0b\x00\x00\x00listPlayers\x00\x03\x00\x00\x00\x61ll\x00", - ); + /** + * The transport mode for this protocol is TCP + * + * @type string + */ + protected $transport = self::TRANSPORT_TCP; - /** - * Set the transport to use TCP - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'bf3'; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - "process_version", - "process_players", - ); + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'bf3'; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 47200; // Default port, used if not set when instanced + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Battlefield 3"; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'bf3'; + /** + * The client join link + * + * @type string + */ + protected $join_link = null; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'bf3'; + /** + * query_port = client_port + 22000 + * 47200 = 25200 + 22000 + * + * @type int + */ + protected $port_diff = 22000; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Battlefield 3"; + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'hostname' => 'hostname', + 'mapname' => 'map', + 'maxplayers' => 'max_players', + 'numplayers' => 'num_players', + 'password' => 'password', + ], + 'player' => [ + 'name' => 'name', + 'score' => 'score', + 'ping' => 'ping', + ], + 'team' => [ + 'score' => 'tickets', + ], + ]; - /* - * Internal methods - */ - protected function preProcess_status($packets=array()) - { - // Implode and return - return implode('', $packets); - } - - protected function process_status() + /** + * Process the response for the StarMade server + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_status($this->packets_response[self::PACKET_STATUS])); + // Holds the results sent back + $results = []; - $buf->skip(8); /* skip header */ + // Holds the processed packets after having been reassembled + $processed = []; - // Decode the words into an array so we can use this data - $words = $this->decodeWords($buf); + // Start up the index for the processed + $sequence_id_last = 0; - // Make sure we got OK - if (!isset ($words[0]) || $words[0] != 'OK') - { - throw new GameQ_ProtocolsException('Packet Response was not OK! Buffer:'.$buf->getBuffer()); - } + foreach ($this->packets_response as $packet) { + // Create a new buffer + $buffer = new Buffer($packet); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Each "good" packet begins with sequence_id (32-bit) + $sequence_id = $buffer->readInt32(); - // Server is always dedicated - $result->add('dedicated', TRUE); + // Sequence id is a response + if (array_key_exists($sequence_id, $this->responses)) { + $processed[$sequence_id] = $buffer->getBuffer(); + $sequence_id_last = $sequence_id; + } else { + // This is a continuation of the previous packet, reset the buffer and append + $buffer->jumpto(0); - // No mods, as of yet - $result->add('mod', FALSE); + // Append + $processed[$sequence_id_last] .= $buffer->getBuffer(); + } + } - // These are the same no matter what mode the server is in - $result->add('hostname', $words[1]); - $result->add('numplayers', $words[2]); - $result->add('maxplayers', $words[3]); - $result->add('gametype', $words[4]); - $result->add('map', $words[5]); + unset($buffer, $sequence_id_last, $sequence_id); - $result->add('roundsplayed', $words[6]); - $result->add('roundstotal', $words[7]); + // Iterate over the combined packets and do some work + foreach ($processed as $sequence_id => $data) { + // Create a new buffer + $buffer = new Buffer($data); - // Figure out the number of teams - $num_teams = intval($words[8]); + // Get the length of the packet + $packetLength = $buffer->getLength(); - // Set the current index - $index_current = 9; + // Check to make sure the expected length matches the real length + // Subtract 4 for the sequence_id pulled out earlier + if ($packetLength != ($buffer->readInt32() - 4)) { + throw new Exception(__METHOD__ . " packet length does not match expected length!"); + } - // Loop for the number of teams found, increment along the way - for($id=1; $id<=$num_teams; $id++) - { - $result->addSub('teams', 'tickets', $words[$index_current]); - $result->addSub('teams', 'id', $id); + // Now we need to call the proper method + $results = array_merge( + $results, + call_user_func_array([$this, $this->responses[$sequence_id]], [$buffer]) + ); + } - // Increment - $index_current++; - } - - // Get and set the rest of the data points. - $result->add('targetscore', $words[$index_current]); - $result->add('online', TRUE); // Forced TRUE, it seems $words[$index_current + 1] is always empty - $result->add('ranked', $words[$index_current + 2] === 'true'); - $result->add('punkbuster', $words[$index_current + 3] === 'true'); - $result->add('password', $words[$index_current + 4] === 'true'); - $result->add('uptime', $words[$index_current + 5]); - $result->add('roundtime', $words[$index_current + 6]); - - // Added in R9 - $result->add('ip_port', $words[$index_current + 7]); - $result->add('punkbuster_version', $words[$index_current + 8]); - $result->add('join_queue', $words[$index_current + 9] === 'true'); - $result->add('region', $words[$index_current + 10]); - $result->add('pingsite', $words[$index_current + 11]); - $result->add('country', $words[$index_current + 12]); - - // Added in R29, No docs as of yet - $result->add('quickmatch', $words[$index_current + 13] === 'true'); // Guessed from research - - unset($buf, $words); - - return $result->fetch(); + return $results; } - protected function preProcess_version($packets=array()) + /* + * Internal Methods + */ + + /** + * Decode the buffer into a usable format + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function decode(Buffer $buffer) { - // Implode and return - return implode('', $packets); - } - protected function process_version() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_VERSION)) - { - return array(); - } + $items = []; - // Set the result to a new result instance - $result = new GameQ_Result(); + // Get the number of words in this buffer + $itemCount = $buffer->readInt32(); - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_version($this->packets_response[self::PACKET_VERSION])); + // Loop over the number of items + for ($i = 0; $i < $itemCount; $i++) { + // Length of the string + $buffer->readInt32(); - $buf->skip(8); /* skip header */ + // Just read the string + $items[$i] = $buffer->readString(); + } - $words = $this->decodeWords($buf); - - // Not too important if version is missing - if (!isset ($words[0]) || $words[0] != 'OK') - { - return array(); - } - - $result->add('version', $words[2]); - - unset($buf, $words); - - return $result->fetch(); - } - - protected function preProcess_players($packets=array()) - { - // Implode and return - return implode('', $packets); - } - - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_players($this->packets_response[self::PACKET_PLAYERS])); - - $buf->skip(8); /* skip header */ - - $words = $this->decodeWords($buf); - - // Not too important if players are missing. - if (!isset ($words[0]) || $words[0] != 'OK') - { - return array(); - } - - // Count the number of words and figure out the highest index. - $words_total = count($words)-1; - - // The number of player info points - $num_tags = $words[1]; - - // Pull out the tags, they start at index=3, length of num_tags - $tags = array_slice($words, 2, $num_tags); - - // Just incase this changed between calls. - $result->add('numplayers', $words[9]); - - // Loop until we run out of positions - for($pos=(3+$num_tags);$pos<=$words_total;$pos+=$num_tags) - { - // Pull out this player - $player = array_slice($words, $pos, $num_tags); - - // Loop the tags and add the proper value for the tag. - foreach($tags AS $tag_index => $tag) - { - $result->addPlayer($tag, $player[$tag_index]); - } - - // No pings in this game - $result->addPlayer('ping', FALSE); - } - - // @todo: Add some team definition stuff - - unset($buf, $tags, $words, $player); - - return $result->fetch(); + return $items; } /** - * Decode words from the response + * Process the server details * - * @param GameQ_Buffer $buf + * @param \GameQ\Buffer $buffer + * + * @return array */ - protected function decodeWords(GameQ_Buffer &$buf) + protected function processDetails(Buffer $buffer) { - $result = array(); - $num_words = $buf->readInt32(); + // Decode into items + $items = $this->decode($buffer); - for ($i = 0; $i < $num_words; $i++) - { - $len = $buf->readInt32(); - $result[] = $buf->read($len); - $buf->read(1); /* 0x00 string ending */ - } + // Set the result to a new result instance + $result = new Result(); - return $result; + // Server is always dedicated + $result->add('dedicated', 1); + + // These are the same no matter what mode the server is in + $result->add('hostname', $items[1]); + $result->add('num_players', (int)$items[2]); + $result->add('max_players', (int)$items[3]); + $result->add('gametype', $items[4]); + $result->add('map', $items[5]); + $result->add('roundsplayed', (int)$items[6]); + $result->add('roundstotal', (int)$items[7]); + $result->add('num_teams', (int)$items[8]); + + // Set the current index + $index_current = 9; + + // Pull the team count + $teamCount = $result->get('num_teams'); + + // Loop for the number of teams found, increment along the way + for ($id = 1; $id <= $teamCount; $id++, $index_current++) { + // Shows the tickets + $result->addTeam('tickets', $items[$index_current]); + // We add an id so we know which team this is + $result->addTeam('id', $id); + } + + // Get and set the rest of the data points. + $result->add('targetscore', (int)$items[$index_current]); + $result->add('online', 1); // Forced true, it seems $words[$index_current + 1] is always empty + $result->add('ranked', (int)$items[$index_current + 2]); + $result->add('punkbuster', (int)$items[$index_current + 3]); + $result->add('password', (int)$items[$index_current + 4]); + $result->add('uptime', (int)$items[$index_current + 5]); + $result->add('roundtime', (int)$items[$index_current + 6]); + // Added in R9 + $result->add('ip_port', $items[$index_current + 7]); + $result->add('punkbuster_version', $items[$index_current + 8]); + $result->add('join_queue', (int)$items[$index_current + 9]); + $result->add('region', $items[$index_current + 10]); + $result->add('pingsite', $items[$index_current + 11]); + $result->add('country', $items[$index_current + 12]); + // Added in R29, No docs as of yet + $result->add('quickmatch', (int)$items[$index_current + 13]); // Guessed from research + + unset($items, $index_current, $teamCount, $buffer); + + return $result->fetch(); + } + + /** + * Process the server version + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function processVersion(Buffer $buffer) + { + + // Decode into items + $items = $this->decode($buffer); + + // Set the result to a new result instance + $result = new Result(); + + $result->add('version', $items[2]); + + unset($buffer, $items); + + return $result->fetch(); + } + + /** + * Process the players + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function processPlayers(Buffer $buffer) + { + + // Decode into items + $items = $this->decode($buffer); + + // Set the result to a new result instance + $result = new Result(); + + // Number of data points per player + $numTags = $items[1]; + + // Grab the tags for each player + $tags = array_slice($items, 2, $numTags); + + // Get the player count + $playerCount = $items[$numTags + 2]; + + // Iterate over the index until we run out of players + for ($i = 0, $x = $numTags + 3; $i < $playerCount; $i++, $x += $numTags) { + // Loop over the player tags and extract the info for that tag + foreach ($tags as $index => $tag) { + $result->addPlayer($tag, $items[($x + $index)]); + } + } + + return $result->fetch(); } } diff --git a/third_party/gameq_v2/gameq/protocols/bf4.php b/third_party/gameq_v2/gameq/protocols/bf4.php index 012c0336..69517529 100644 --- a/third_party/gameq_v2/gameq/protocols/bf4.php +++ b/third_party/gameq_v2/gameq/protocols/bf4.php @@ -3,187 +3,112 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Buffer; +use GameQ\Result; + /** - * Battlefield 4 Protocol Class + * Battlefield 4 Protocol class * * Good place for doc status and info is http://battlelog.battlefield.com/bf4/forum/view/2955064768683911198/ * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Bf4 extends GameQ_Protocols_Bf3 +class Bf4 extends Bf3 { - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'bf4'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'bf4'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'bf4'; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Battlefield 4"; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Battlefield 4"; - /* - * Internal Methods - */ - protected function process_status() + /** + * Handle processing details since they are different than BF3 + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function processDetails(Buffer $buffer) { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_status($this->packets_response[self::PACKET_STATUS])); + // Decode into items + $items = $this->decode($buffer); - $buf->skip(8); /* skip header */ + // Set the result to a new result instance + $result = new Result(); - // Decode the words into an array so we can use this data - $words = $this->decodeWords($buf); + // Server is always dedicated + $result->add('dedicated', 1); - // Make sure we got OK - if (!isset ($words[0]) || $words[0] != 'OK') - { - throw new GameQ_ProtocolsException('Packet Response was not OK! Buffer:'.$buf->getBuffer()); - } + // These are the same no matter what mode the server is in + $result->add('hostname', $items[1]); + $result->add('num_players', (int) $items[2]); + $result->add('max_players', (int) $items[3]); + $result->add('gametype', $items[4]); + $result->add('map', $items[5]); + $result->add('roundsplayed', (int) $items[6]); + $result->add('roundstotal', (int) $items[7]); + $result->add('num_teams', (int) $items[8]); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Set the current index + $index_current = 9; - // Server is always dedicated - $result->add('dedicated', TRUE); + // Pull the team count + $teamCount = $result->get('num_teams'); - // No mods, as of yet - $result->add('mod', FALSE); + // Loop for the number of teams found, increment along the way + for ($id = 1; $id <= $teamCount; $id++, $index_current++) { + // Shows the tickets + $result->addTeam('tickets', $items[$index_current]); + // We add an id so we know which team this is + $result->addTeam('id', $id); + } - // These are the same no matter what mode the server is in - $result->add('hostname', $words[1]); - $result->add('numplayers', $words[2]); - $result->add('maxplayers', $words[3]); - $result->add('gametype', $words[4]); - $result->add('map', $words[5]); + // Get and set the rest of the data points. + $result->add('targetscore', (int) $items[$index_current]); + $result->add('online', 1); // Forced true, it seems $words[$index_current + 1] is always empty + $result->add('ranked', (int) $items[$index_current + 2]); + $result->add('punkbuster', (int) $items[$index_current + 3]); + $result->add('password', (int) $items[$index_current + 4]); + $result->add('uptime', (int) $items[$index_current + 5]); + $result->add('roundtime', (int) $items[$index_current + 6]); + $result->add('ip_port', $items[$index_current + 7]); + $result->add('punkbuster_version', $items[$index_current + 8]); + $result->add('join_queue', (int) $items[$index_current + 9]); + $result->add('region', $items[$index_current + 10]); + $result->add('pingsite', $items[$index_current + 11]); + $result->add('country', $items[$index_current + 12]); + //$result->add('quickmatch', (int) $items[$index_current + 13]); Supposed to be here according to R42 but is not + $result->add('blaze_player_count', (int) $items[$index_current + 13]); + $result->add('blaze_game_state', (int) $items[$index_current + 14]); - $result->add('roundsplayed', $words[6]); - $result->add('roundstotal', $words[7]); + unset($items, $index_current, $teamCount, $buffer); - // Figure out the number of teams - $num_teams = intval($words[8]); - - // Set the current index - $index_current = 9; - - // Loop for the number of teams found, increment along the way - for($id=1; $id<=$num_teams; $id++) - { - $result->addSub('teams', 'tickets', $words[$index_current]); - $result->addSub('teams', 'id', $id); - - // Increment - $index_current++; - } - - // Get and set the rest of the data points. - $result->add('targetscore', $words[$index_current]); - $result->add('online', TRUE); // Forced TRUE, it seems $words[$index_current + 1] is always empty - $result->add('ranked', $words[$index_current + 2] === 'true'); - $result->add('punkbuster', $words[$index_current + 3] === 'true'); - $result->add('password', $words[$index_current + 4] === 'true'); - $result->add('uptime', $words[$index_current + 5]); - $result->add('roundtime', $words[$index_current + 6]); - - $result->add('ip_port', $words[$index_current + 7]); - $result->add('punkbuster_version', $words[$index_current + 8]); - $result->add('join_queue', $words[$index_current + 9] === 'true'); - $result->add('region', $words[$index_current + 10]); - $result->add('pingsite', $words[$index_current + 11]); - $result->add('country', $words[$index_current + 12]); - - // @todo: Supposed to be a field here , its in R13 docs but doesnt return in response - $result->add('blaze_player_count', $words[$index_current + 13]); - $result->add('blaze_game_state', $words[$index_current + 14]); - - unset($buf, $words); - - return $result->fetch(); - } - - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_players($this->packets_response[self::PACKET_PLAYERS])); - - $buf->skip(8); /* skip header */ - - $words = $this->decodeWords($buf); - - // Not too important if players are missing. - if (!isset ($words[0]) || $words[0] != 'OK') - { - return array(); - } - - // Count the number of words and figure out the highest index. - $words_total = count($words)-1; - - // The number of player info points - $num_tags = $words[1]; - - // Pull out the tags, they start at index=3, length of num_tags - $tags = array_slice($words, 2, $num_tags); - - // Just incase this changed between calls. - $result->add('numplayers', $words[($num_tags+2)]); - - // Loop until we run out of positions - for($pos=(3+$num_tags);$pos<=$words_total;$pos+=$num_tags) - { - // Pull out this player - $player = array_slice($words, $pos, $num_tags); - - // Loop the tags and add the proper value for the tag. - foreach($tags AS $tag_index => $tag) - { - $result->addPlayer($tag, $player[$tag_index]); - } - } - - // @todo: Add some team definition stuff - - unset($buf, $tags, $words, $player); - - return $result->fetch(); + return $result->fetch(); } } diff --git a/third_party/gameq_v2/gameq/protocols/bfbc2.php b/third_party/gameq_v2/gameq/protocols/bfbc2.php index 54bc9c69..b7167a02 100644 --- a/third_party/gameq_v2/gameq/protocols/bfbc2.php +++ b/third_party/gameq_v2/gameq/protocols/bfbc2.php @@ -3,247 +3,324 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + /** * Battlefield Bad Company 2 Protocol Class * - * @author Austin Bischoff + * NOTE: There are no qualifiers to the response packets sent back from the server as to which response packet + * belongs to which query request. For now this class assumes the responses are in the same order as the order in + * which the packets were sent to the server. If this assumption turns out to be wrong there is easy way to tell which + * response belongs to which query. Hopefully this assumption will hold true as it has in my testing. + * + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Bfbc2 extends GameQ_Protocols +class Bfbc2 extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", - self::PACKET_VERSION => "\x00\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00", - self::PACKET_PLAYERS => "\x00\x00\x00\x00\x24\x00\x00\x00\x02\x00\x00\x00\x0b\x00\x00\x00listPlayers\x00\x03\x00\x00\x00\x61ll\x00", - ); - /** - * Set the transport to use TCP - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; + /** + * Array of packets we want to query. + * + * @type array + */ + protected $packets = [ + self::PACKET_VERSION => "\x00\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00", + self::PACKET_STATUS => "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", + self::PACKET_PLAYERS => "\x00\x00\x00\x00\x24\x00\x00\x00\x02\x00\x00\x00\x0b\x00\x00\x00listPlayers\x00\x03\x00\x00\x00\x61ll\x00", + ]; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - "process_version", - "process_players", - ); + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "processVersion", + "processDetails", + "processPlayers", + ]; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 48888; // Default port, used if not set when instanced + /** + * The transport mode for this protocol is TCP + * + * @type string + */ + protected $transport = self::TRANSPORT_TCP; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'bfbc2'; + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'bfbc2'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'bfbc2'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'bfbc2'; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Battlefield Bad Company 2"; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Battlefield Bad Company 2"; + /** + * The client join link + * + * @type string + */ + protected $join_link = null; - /* - * Internal methods - */ + /** + * query_port = client_port + 29321 + * 48888 = 19567 + 29321 + * + * @type int + */ + protected $port_diff = 29321; - protected function preProcess_status($packets=array()) - { - // Implode and return - return implode('', $packets); - } + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'hostname' => 'hostname', + 'mapname' => 'map', + 'maxplayers' => 'max_players', + 'numplayers' => 'num_players', + 'password' => 'password', + ], + 'player' => [ + 'name' => 'name', + 'score' => 'score', + 'ping' => 'ping', + ], + 'team' => [ + 'score' => 'tickets', + ], + ]; - protected function process_status() + /** + * Process the response for the StarMade server + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - // Set the result to a new result instance - $result = new GameQ_Result(); + //print_r($this->packets_response); - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_status($this->packets_response[self::PACKET_STATUS])); + // Holds the results sent back + $results = []; - $buf->skip(8); /* skip header */ + // Iterate over the response packets + // @todo: This protocol has no packet ordering, ids or anyway to identify which packet coming back belongs to which initial call. + foreach ($this->packets_response as $i => $packet) { + // Create a new buffer + $buffer = new Buffer($packet); - $words = $this->decodeWords($buf); + // Burn first 4 bytes, same across all packets + $buffer->skip(4); - if (!isset ($words[0]) || $words[0] != 'OK') - { - throw new GameQ_ProtocolsException('Packet Response was not OK! Buffer:'.$buf->getBuffer()); - } + // Get the packet length + $packetLength = $buffer->getLength(); - $result->add('hostname', $words[1]); - $result->add('numplayers', $words[2]); - $result->add('maxplayers', $words[3]); - $result->add('gametype', $words[4]); - $result->add('map', $words[5]); + // Check to make sure the expected length matches the real length + // Subtract 4 for the header burn + if ($packetLength != ($buffer->readInt32() - 4)) { + throw new Exception(__METHOD__ . " packet length does not match expected length!"); + } - // @todo: Add some team definition stuff + // We assume the packets are coming back in the same order as sent, this maybe incorrect... + $results = array_merge( + $results, + call_user_func_array([$this, $this->responses[$i]], [$buffer]) + ); + } - unset($buf); + unset($buffer, $packetLength); - return $result->fetch(); + return $results; } - protected function preProcess_version($packets=array()) + /* + * Internal Methods + */ + + /** + * Decode the buffer into a usable format + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function decode(Buffer $buffer) { - // Implode and return - return implode('', $packets); - } - protected function process_version() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_VERSION)) - { - return array(); - } + $items = []; - // Set the result to a new result instance - $result = new GameQ_Result(); + // Get the number of words in this buffer + $itemCount = $buffer->readInt32(); - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_version($this->packets_response[self::PACKET_VERSION])); + // Loop over the number of items + for ($i = 0; $i < $itemCount; $i++) { + // Length of the string + $buffer->readInt32(); - $buf->skip(8); /* skip header */ + // Just read the string + $items[$i] = $buffer->readString(); + } - $words = $this->decodeWords($buf); - - // Not too important if version is missing - if (!isset ($words[0]) || $words[0] != 'OK') - { - return array(); - } - - $result->add('version', $words[2]); - - unset($buf); - - return $result->fetch(); - } - - protected function preProcess_players($packets=array()) - { - // Implode and return - return implode('', $packets); - } - - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_players($this->packets_response[self::PACKET_PLAYERS])); - - $buf->skip(8); /* skip header */ - - $words = $this->decodeWords($buf); - - // Not too important if players are missing. - if (!isset ($words[0]) || $words[0] != 'OK') - { - return array(); - } - - // The number of player info points - $num_tags = $words[1]; - $position = 2; - $tags = array(); - - for (; $position < $num_tags + 2 ; $position++) - { - $tags[] = $words[$position]; - } - - $num_players = $words[$position]; - $position++; - $start_position = $position; - - for (; $position < $num_players * $num_tags + $start_position; - $position += $num_tags) - { - for ($a = $position, $b = 0; $a < $position + $num_tags; - $a++, $b++) - { - $result->addPlayer($tags[$b], $words[$a]); - } - } - - // @todo: Add some team definition stuff - - unset($buf); - - return $result->fetch(); + return $items; } /** - * Decode words from the response + * Process the server details * - * @param GameQ_Buffer $buf + * @param \GameQ\Buffer $buffer + * + * @return array */ - protected function decodeWords(GameQ_Buffer &$buf) + protected function processDetails(Buffer $buffer) { - $result = array(); - $num_words = $buf->readInt32(); + // Decode into items + $items = $this->decode($buffer); - for ($i = 0; $i < $num_words; $i++) - { - $len = $buf->readInt32(); - $result[] = $buf->read($len); - $buf->read(1); /* 0x00 string ending */ - } + // Set the result to a new result instance + $result = new Result(); - return $result; + // Server is always dedicated + $result->add('dedicated', 1); + + // These are the same no matter what mode the server is in + $result->add('hostname', $items[1]); + $result->add('num_players', (int)$items[2]); + $result->add('max_players', (int)$items[3]); + $result->add('gametype', $items[4]); + $result->add('map', $items[5]); + $result->add('roundsplayed', (int)$items[6]); + $result->add('roundstotal', (int)$items[7]); + $result->add('num_teams', (int)$items[8]); + + // Set the current index + $index_current = 9; + + // Pull the team count + $teamCount = $result->get('num_teams'); + + // Loop for the number of teams found, increment along the way + for ($id = 1; $id <= $teamCount; $id++, $index_current++) { + // Shows the tickets + $result->addTeam('tickets', $items[$index_current]); + // We add an id so we know which team this is + $result->addTeam('id', $id); + } + + // Get and set the rest of the data points. + $result->add('targetscore', (int)$items[$index_current]); + $result->add('online', 1); // Forced true, shows accepting players + $result->add('ranked', (($items[$index_current + 2] == 'true') ? 1 : 0)); + $result->add('punkbuster', (($items[$index_current + 3] == 'true') ? 1 : 0)); + $result->add('password', (($items[$index_current + 4] == 'true') ? 1 : 0)); + $result->add('uptime', (int)$items[$index_current + 5]); + $result->add('roundtime', (int)$items[$index_current + 6]); + $result->add('mod', $items[$index_current + 7]); + + $result->add('ip_port', $items[$index_current + 9]); + $result->add('punkbuster_version', $items[$index_current + 10]); + $result->add('join_queue', (($items[$index_current + 11] == 'true') ? 1 : 0)); + $result->add('region', $items[$index_current + 12]); + + unset($items, $index_current, $teamCount, $buffer); + + return $result->fetch(); + } + + /** + * Process the server version + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function processVersion(Buffer $buffer) + { + // Decode into items + $items = $this->decode($buffer); + + // Set the result to a new result instance + $result = new Result(); + + $result->add('version', $items[2]); + + unset($buffer, $items); + + return $result->fetch(); + } + + /** + * Process the players + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function processPlayers(Buffer $buffer) + { + + // Decode into items + $items = $this->decode($buffer); + + // Set the result to a new result instance + $result = new Result(); + + // Number of data points per player + $numTags = $items[1]; + + // Grab the tags for each player + $tags = array_slice($items, 2, $numTags); + + // Get the player count + $playerCount = $items[$numTags + 2]; + + // Iterate over the index until we run out of players + for ($i = 0, $x = $numTags + 3; $i < $playerCount; $i++, $x += $numTags) { + // Loop over the player tags and extract the info for that tag + foreach ($tags as $index => $tag) { + $result->addPlayer($tag, $items[($x + $index)]); + } + } + + return $result->fetch(); } } diff --git a/third_party/gameq_v2/gameq/protocols/bfv.php b/third_party/gameq_v2/gameq/protocols/bfv.php deleted file mode 100644 index 73df1007..00000000 --- a/third_party/gameq_v2/gameq/protocols/bfv.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Battlefield Vietnam Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Bfv extends GameQ_Protocols_Gamespy2 -{ - protected $name = "bfv"; - protected $name_long = "Battlefield Vietnam"; - - protected $port = 23000; -} diff --git a/third_party/gameq_v2/gameq/protocols/brink.php b/third_party/gameq_v2/gameq/protocols/brink.php index ab5c038f..20226525 100644 --- a/third_party/gameq_v2/gameq/protocols/brink.php +++ b/third_party/gameq_v2/gameq/protocols/brink.php @@ -3,26 +3,48 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Brink Protocol Class + * Class Brink * - * @author Austin Bischoff + * @package GameQ\Protocols + * + * @author Wilson Jesus <> */ -class GameQ_Protocols_Brink extends GameQ_Protocols_Source +class Brink extends Source { - protected $name = "brink"; - protected $name_long = "Brink"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'brink'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Brink"; + + /** + * query_port = client_port + 1 + * + * @type int + */ + protected $port_diff = 1; } diff --git a/third_party/gameq_v2/gameq/protocols/cod.php b/third_party/gameq_v2/gameq/protocols/cod.php index 6ad6f1c3..2425ea67 100644 --- a/third_party/gameq_v2/gameq/protocols/cod.php +++ b/third_party/gameq_v2/gameq/protocols/cod.php @@ -3,28 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** * Call of Duty Protocol Class * - * @author Austin Bischoff + * @package GameQ\Protocols + * + * @author Wilson Jesus <> */ -class GameQ_Protocols_Cod extends GameQ_Protocols_Quake3 +class Cod extends Quake3 { - protected $name = "cod"; - protected $name_long = "Call of Duty"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'cod'; - protected $port = 28960; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Call of Duty"; } diff --git a/third_party/gameq_v2/gameq/protocols/cod2.php b/third_party/gameq_v2/gameq/protocols/cod2.php index 144b4675..79be7ca2 100644 --- a/third_party/gameq_v2/gameq/protocols/cod2.php +++ b/third_party/gameq_v2/gameq/protocols/cod2.php @@ -3,28 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** * Call of Duty 2 Protocol Class * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Cod2 extends GameQ_Protocols_Quake3 +class Cod2 extends Quake3 { - protected $name = "cod2"; - protected $name_long = "Call of Duty 2"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'cod2'; - protected $port = 28960; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Call of Duty 2"; } diff --git a/third_party/gameq_v2/gameq/protocols/cod4.php b/third_party/gameq_v2/gameq/protocols/cod4.php index 5cd49752..9838d9cb 100644 --- a/third_party/gameq_v2/gameq/protocols/cod4.php +++ b/third_party/gameq_v2/gameq/protocols/cod4.php @@ -3,28 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** * Call of Duty 4 Protocol Class * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Cod4 extends GameQ_Protocols_Quake3 +class Cod4 extends Quake3 { - protected $name = "cod4"; - protected $name_long = "Call of Duty 4"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'cod4'; - protected $port = 28960; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Call of Duty 4"; } diff --git a/third_party/gameq_v2/gameq/protocols/codmw3.php b/third_party/gameq_v2/gameq/protocols/codmw3.php index 2fcecedb..1049b602 100644 --- a/third_party/gameq_v2/gameq/protocols/codmw3.php +++ b/third_party/gameq_v2/gameq/protocols/codmw3.php @@ -3,28 +3,48 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Call of Duty: Modern Warfare 3 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Codmw3 extends GameQ_Protocols_Source -{ - protected $name = "codmw3"; - protected $name_long = "Call of Duty: Modern Warfare 3"; +namespace GameQ\Protocols; - protected $port = 27015; +/** + * Class Codmw3 + * + * @package GameQ\Protocols + * @author Austin Bischoff + */ +class Codmw3 extends Source +{ + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'codmw3'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Call of Duty: Modern Warfare 3"; + + /** + * query_port = client_port + 2 + * + * @type int + */ + protected $port_diff = 2; } diff --git a/third_party/gameq_v2/gameq/protocols/coduo.php b/third_party/gameq_v2/gameq/protocols/coduo.php index 2d180461..2dd9a182 100644 --- a/third_party/gameq_v2/gameq/protocols/coduo.php +++ b/third_party/gameq_v2/gameq/protocols/coduo.php @@ -3,28 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Call of Duty: United Offensive Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Coduo extends GameQ_Protocols_Quake3 -{ - protected $name = "coduo"; - protected $name_long = "Call of Duty: United Offensive"; +namespace GameQ\Protocols; - protected $port = 28960; +/** + * Call of Duty United Offensive Class + * + * @package GameQ\Protocols + * + * @author Wilson Jesus <> + */ +class Coduo extends Quake3 +{ + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'coduo'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Call of Duty: United Offensive"; } diff --git a/third_party/gameq_v2/gameq/protocols/codwaw.php b/third_party/gameq_v2/gameq/protocols/codwaw.php index fcc1a819..f730678e 100644 --- a/third_party/gameq_v2/gameq/protocols/codwaw.php +++ b/third_party/gameq_v2/gameq/protocols/codwaw.php @@ -3,28 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Call of Duty: World at War Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Codwaw extends GameQ_Protocols_Quake3 -{ - protected $name = "codwaw"; - protected $name_long = "Call of Duty: World at War"; +namespace GameQ\Protocols; - protected $port = 28960; +/** + * Call of Duty World at War Class + * + * @package GameQ\Protocols + * @author naXe + * @author Austin Bischoff + */ +class Codwaw extends Quake3 +{ + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'codwaw'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Call of Duty: World at War"; } diff --git a/third_party/gameq_v2/gameq/protocols/core.php b/third_party/gameq_v2/gameq/protocols/core.php deleted file mode 100644 index 2473b3fc..00000000 --- a/third_party/gameq_v2/gameq/protocols/core.php +++ /dev/null @@ -1,708 +0,0 @@ -. - * - * - */ - -/** - * Handles the core functionality for the protocols - * - * @author Austin Bischoff - */ -abstract class GameQ_Protocols_Core -{ - /* - * Constants for class states - */ - const STATE_TESTING = 1; - const STATE_BETA = 2; - const STATE_STABLE = 3; - const STATE_DEPRECATED = 4; - - /* - * Constants for packet keys - */ - const PACKET_ALL = 'all'; // Some protocols allow all data to be sent back in one call. - const PACKET_BASIC = 'basic'; - const PACKET_CHALLENGE = 'challenge'; - const PACKET_CHANNELS = 'channels'; // Voice servers - const PACKET_DETAILS = 'details'; - const PACKET_INFO = 'info'; - const PACKET_PLAYERS = 'players'; - const PACKET_STATUS = 'status'; - const PACKET_RULES = 'rules'; - const PACKET_VERSION = 'version'; - - /* - * Transport constants - */ - const TRANSPORT_UDP = 'udp'; - const TRANSPORT_TCP = 'tcp'; - - /** - * Can only send one packet at a time, slower - * - * @var string - */ - const PACKET_MODE_LINEAR = 'linear'; - - /** - * Can send multiple packets at once and get responses, after challenge request (if required) - * - * @var string - */ - const PACKET_MODE_MULTI = 'multi'; - - /** - * Current version of this class - * - * @var string - */ - protected $version = '2.0'; - - /** - * Short name of the protocol - * - * @var string - */ - protected $name = 'unnamed'; - - /** - * The longer, fancier name for the protocol - * - * @var string - */ - protected $name_long = 'unnamed'; - - /** - * IP address of the server we are querying. - * - * @var string - */ - protected $ip = '127.0.0.1'; - - /** - * Port of the server we are querying. - * - * @var mixed FALSE|int - */ - protected $port = NULL; - - /** - * The port the client can connect on, usually the same as self::$port - * but not always. - * - * @var integer - */ - protected $port_client = NULL; - - /** - * The trasport method to use to actually send the data - * Default is UDP - * - * @var string UDP|TCP - */ - protected $transport = self::TRANSPORT_UDP; - - /** - * The protocol type used when querying the server - * - * @var string - */ - protected $protocol = 'unknown'; - - /** - * Packets Mode is multi by default since most games support it - * - * @var string - */ - protected $packet_mode = self::PACKET_MODE_MULTI; - - /** - * Holds the valid packet types this protocol has available. - * - * @var array - */ - protected $packets = array(); - - /** - * Holds the list of methods to run when parsing the packet response(s) data. These - * methods should provide all the return information. - * - * @var array() - */ - protected $process_methods = array(); - - /** - * The packet responses received - * - * @var array - */ - protected $packets_response = array(); - - /** - * Holds the instance of the result class - * - * @var GameQ_Result - */ - protected $result = NULL; - - /** - * Options for this protocol - * - * @var array - */ - protected $options = array(); - - /** - * Holds the challenge response, if there is a challenge needed. - * - * @var array - */ - protected $challenge_response = NULL; - - /** - * Holds the challenge buffer. - * - * @var GameQ_Buffer - */ - protected $challenge_buffer = NULL; - - /** - * Holds the result of the challenge, if any - * Will hold the error here - * - * @var mixed - */ - protected $challenge_result = TRUE; - - /** - * Define the state of this class - * - * @var int - */ - protected $state = self::STATE_STABLE; - - /** - * Holds and changes we want to make to the normailze filter - * - * @var array - */ - protected $normalize = FALSE; - - /** - * Quick join link for specific games - * - * @var string - */ - protected $join_link = NULL; - - /** - * Create the instance. - * - * @param string $ip - * @param mixed $port false|int - * @param array $options - */ - public function __construct($ip = FALSE, $port = FALSE, $options = array()) - { - // Set the ip - $this->ip($ip); - - // We have a specific port set so let's set it. - if($port !== FALSE) - { - // Set the port - $this->port($port); - - /* - * By default we set the client port = to the query port. Note that - * this is not always the case - */ - $this->port_client($port); - } - - // We have passed options so let's set them - if(!empty($options)) - { - // Set the passed options - $this->options($options); - - // We have an option passed for client connect port - if(isset($options['client_connect_port']) && !empty($options['client_connect_port'])) - { - // Overwrite the default connect port - $this->port_client($options['client_connect_port']); - } - } - } - - /** - * String name of this class - */ - public function __toString() - { - return $this->name; - } - - /** - * Get an option's value - * - * @param string $option - * @return mixed - */ - public function __get($option) - { - return isset($this->options[$option]) ? $this->options[$option] : NULL; - } - - /** - * Set an option's value - * - * @param string $option - * @param mixed $value - * @return boolean - */ - public function __set($option, $value) - { - $this->options[$option] = $value; - - return TRUE; - } - - /** - * Short (callable) name of this class - * - * @return string - */ - public function name() - { - return $this->name; - } - - /** - * Long name of this class - */ - public function name_long() - { - return $this->name_long; - } - - /** - * Return the status of this Protocol Class - */ - public function state() - { - return $this->state; - } - - /** - * Return the packet mode for this protocol - */ - public function packet_mode() - { - return $this->packet_mode; - } - - /** - * Return the protocol property - * - */ - public function protocol() - { - return $this->protocol; - } - - /** - * Get/set the ip address of the server - * - * @param string $ip - */ - public function ip($ip = FALSE) - { - // Act as setter - if($ip !== FALSE) - { - $this->ip = $ip; - } - - return $this->ip; - } - - /** - * Get/set the port of the server - * - * @param int $port - */ - public function port($port = FALSE) - { - // Act as setter - if($port !== FALSE) - { - $this->port = $port; - } - - return $this->port; - } - - /** - * Get/set the client port of the server - * - * @param integer $port - */ - public function port_client($port = FALSE) - { - // Act as setter - if($port !== FALSE) - { - $this->port_client = $port; - } - - return $this->port_client; - } - - /** - * Get/set the transport type for this protocol - * - * @param string $type - */ - public function transport($type = FALSE) - { - // Act as setter - if($type !== FALSE) - { - $this->transport = $type; - } - - return $this->transport; - } - - /** - * Set the options for the protocol call - * - * @param array $options - */ - public function options($options = Array()) - { - // Act as setter - if(!empty($options)) - { - $this->options = $options; - } - - return $this->options; - } - - /** - * Determine whether or not this protocol has some kind of challenge - */ - public function hasChallenge() - { - return (isset($this->packets[self::PACKET_CHALLENGE]) && !empty($this->packets[self::PACKET_CHALLENGE])); - } - - /** - * See if the challenge was ok - */ - public function challengeOK() - { - return ($this->challenge_result === TRUE); - } - - /** - * Get/set the challenge response - * - * @param array $response - */ - public function challengeResponse($response = Array()) - { - // Act as setter - if(!empty($response)) - { - $this->challenge_response = $response; - } - - return $this->challenge_response; - } - - /** - * Get/set the challenge result - * - * @param string $result - */ - public function challengeResult($result = FALSE) - { - // Act as setter - if(!empty($result)) - { - $this->challenge_result = $result; - } - - return $this->challenge_result; - } - - /** - * Get/set the challenge buffer - * - * @param GameQ_Buffer $buffer - */ - public function challengeBuffer($buffer = NULL) - { - // Act as setter - if(!empty($buffer)) - { - $this->challenge_buffer = $buffer; - } - - return $this->challenge_buffer; - } - - /** - * Verify the challenge response and parse it - */ - public function challengeVerifyAndParse() - { - // Check to make sure the response exists - if(!isset($this->challenge_response[0])) - { - // Set error and skip - $this->challenge_result = 'Challenge Response Empty'; - return FALSE; - } - - // Challenge is good to go - $this->challenge_result = TRUE; - - // Now let's create a new buffer with this response - $this->challenge_buffer = new GameQ_Buffer($this->challenge_response[0]); - - // Now parse the challenge and apply it - return $this->parseChallengeAndApply(); - } - - /** - * Get/set the packet response - * - * @param string $packet_type - * @param array $response - */ - public function packetResponse($packet_type, $response = Array()) - { - // Act as setter - if(!empty($response)) - { - $this->packets_response[$packet_type] = $response; - } - - return $this->packets_response[$packet_type]; - } - - /** - * Return specific packet(s) - * - * @param mixed $type array|string - */ - public function getPacket($type = array()) - { - // We want an array of packets back - if(is_array($type) && !empty($type)) - { - $packets = array(); - - // Loop the packets - foreach($this->packets AS $packet_type => $packet_data) - { - // We want this packet - if(in_array($packet_type, $type)) - { - $packets[$packet_type] = $packet_data; - } - } - - return $packets; - } - elseif($type == '!challenge') - { - $packets = array(); - - // Loop the packets - foreach($this->packets AS $packet_type => $packet_data) - { - // Dont want challenge packets - if($packet_type == self::PACKET_CHALLENGE) - { - continue; - } - - $packets[$packet_type] = $packet_data; - } - - return $packets; - } - elseif(is_string($type)) - { - return $this->packets[$type]; - } - - // Return all the packets - return $this->packets; - } - - /* Begin working methods */ - - /** - * Process the response and return the raw data as an array. - * - * @throws GameQException - */ - public function processResponse() - { - // Init the array - $results = array(); - - // Let's loop all the requred methods to get all the data we want/need. - foreach ($this->process_methods AS $method) - { - // Lets make sure the data method defined exists. - if(!method_exists($this, $method)) - { - // We should never get here in a production environment - throw new GameQException('Unable to load method '.__CLASS__.'::'.$method); - return FALSE; - } - - // Setup a catch for protocol level errors - try - { - // Call the proper process method. All methods should return an array of data. - // Preprocessing should be handled by these methods internally as well. - // Merge in the results when done. - $results = array_merge($results, call_user_func_array(array($this, $method), array())); - - } - catch (GameQ_ProtocolsException $e) - { - // Check to see if we are in debug, if so bubble up the exception - if($this->debug) - { - throw new GameQException($e->getMessage(), $e->getCode(), $e); - return FALSE; - } - - // We ignore this and continue - continue; - } - - } - - // Now add some default stuff - $results['gq_online'] = (count($results) > 0); - $results['gq_address'] = $this->ip; - $results['gq_port'] = $this->port; - $results['gq_protocol'] = $this->protocol; - $results['gq_type'] = (string) $this; - $results['gq_transport'] = $this->transport; - - // Process the join link - if(!isset($results['gq_joinlink']) || empty($results['gq_joinlink'])) - { - $results['gq_joinlink'] = $this->getJoinLink(); - } - - // Return the raw results - return $results; - } - - /** - * This method is called before the actual query packets are sent to the server. This allows - * the class to modify any changes before being sent. - * - * @return boolean - */ - public function beforeSend() - { - return TRUE; - } - - /** - * Get the normalize property - */ - public function getNormalize() - { - return $this->normalize; - } - - /** - * Apply the challenge string to all the packets that need it. - * - * @param string $challenge_string - */ - protected function challengeApply($challenge_string) - { - // Let's loop thru all the packets and append the challenge where it is needed - foreach($this->packets AS $packet_type => $packet) - { - $this->packets[$packet_type] = sprintf($packet, $challenge_string); - } - - return TRUE; - } - - /** - * Parse the challenge buffer and get the proper challenge string out - */ - protected function parseChallengeAndApply() - { - return TRUE; - } - - /** - * Determine whether or not the response is valid for a specific packet type - * - * @param string $packet_type - */ - protected function hasValidResponse($packet_type) - { - // Check for valid packet. All packet responses should have atleast 1 array key (0). - if(isset($this->packets_response[$packet_type][0]) - && !empty($this->packets_response[$packet_type][0]) - ) - { - return TRUE; - } - - return FALSE; - } - - /** - * Create a server join link based on the server information - * - * @return string - */ - protected function getJoinLink() - { - $link = ''; - - // We have a join_link defined - if(!empty($this->join_link)) - { - $link = sprintf($this->join_link, $this->ip, $this->port_client); - } - - return $link; - } -} diff --git a/third_party/gameq_v2/gameq/protocols/crysis.php b/third_party/gameq_v2/gameq/protocols/crysis.php index dcbe6094..e09a673d 100644 --- a/third_party/gameq_v2/gameq/protocols/crysis.php +++ b/third_party/gameq_v2/gameq/protocols/crysis.php @@ -3,28 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Crysis Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Crysis extends GameQ_Protocols_Gamespy3 -{ - protected $name = "crysis"; - protected $name_long = "Crysis"; +namespace GameQ\Protocols; - protected $port = 64087; +/** + * Class Crysis + * + * @package GameQ\Protocols + * + * @author Wilson Jesus <> + */ +class Crysis extends Gamespy3 +{ + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'crysis'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Crysis"; } diff --git a/third_party/gameq_v2/gameq/protocols/crysis2.php b/third_party/gameq_v2/gameq/protocols/crysis2.php index 9aa06162..75c6614a 100644 --- a/third_party/gameq_v2/gameq/protocols/crysis2.php +++ b/third_party/gameq_v2/gameq/protocols/crysis2.php @@ -3,28 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Crysis 2 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Crysis2 extends GameQ_Protocols_Gamespy3 -{ - protected $name = "crysis2"; - protected $name_long = "Crysis 2"; +namespace GameQ\Protocols; - protected $port = 64000; +/** + * Class Crysis2 + * + * @package GameQ\Protocols + * + * @author Wilson Jesus <> + */ +class Crysis2 extends Gamespy3 +{ + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'crysis2'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Crysis 2"; } diff --git a/third_party/gameq_v2/gameq/protocols/crysiswarhead.php b/third_party/gameq_v2/gameq/protocols/crysiswarhead.php deleted file mode 100644 index c3b42299..00000000 --- a/third_party/gameq_v2/gameq/protocols/crysiswarhead.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Crysis Warhead Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Crysiswarhead extends GameQ_Protocols_Gamespy3 -{ - protected $name = "crysiswarhead"; - protected $name_long = "Crysis Warhead"; - - protected $port = 64100; -} diff --git a/third_party/gameq_v2/gameq/protocols/crysiswars.php b/third_party/gameq_v2/gameq/protocols/crysiswars.php index 871dab4a..44dcdcf1 100644 --- a/third_party/gameq_v2/gameq/protocols/crysiswars.php +++ b/third_party/gameq_v2/gameq/protocols/crysiswars.php @@ -3,28 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Crysis Wars Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Crysiswars extends GameQ_Protocols_Gamespy3 -{ - protected $name = "crysiswars"; - protected $name_long = "Crysis Wars"; +namespace GameQ\Protocols; - protected $port = 64100; +/** + * Class Crysiswars + * + * @package GameQ\Protocols + * + * @author Austin Bischoff + */ +class Crysiswars extends Gamespy3 +{ + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'crysiswars'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Crysis Wars"; } diff --git a/third_party/gameq_v2/gameq/protocols/cs16.php b/third_party/gameq_v2/gameq/protocols/cs16.php index dc4f820b..25a66029 100644 --- a/third_party/gameq_v2/gameq/protocols/cs16.php +++ b/third_party/gameq_v2/gameq/protocols/cs16.php @@ -16,34 +16,54 @@ * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Counter-Strike 1.6 Protocol Class + * Class Cs16 * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Cs16 extends GameQ_Protocols_Source +class Cs16 extends Source { - protected $name = "cs16"; - protected $name_long = "Counter-Strike 1.6"; - /** - * We have to overload this function to cheat the rules processing because of some wierdness, old ass game! - * - * @see GameQ_Protocols_Source::preProcess_rules() - */ - protected function preProcess_rules($packets) - { - $engine_orig = $this->source_engine; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'cs16'; - // Override the engine type for rules, not sure why its like that - $this->source_engine = self::GOLDSOURCE_ENGINE; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Counter-Strike 1.6"; - // Now process the rules - $ret = parent::preProcess_rules($packets); + /** + * In the case of cs 1.6 we offload split packets here because the split packet response for rules is in + * the old gold source format + * + * @param $packet_id + * @param array $packets + * + * @return string + * @throws \GameQ\Exception\Protocol + */ + protected function processPackets($packet_id, array $packets = []) + { - // Reset the engine type - $this->source_engine = $engine_orig; + // The response is gold source if the packets are split + $this->source_engine = self::GOLDSOURCE_ENGINE; - return $ret; - } + // Offload to the parent + $packs = parent::processPackets($packet_id, $packets); + + // Reset the engine + $this->source_engine = self::SOURCE_ENGINE; + + // Return the result + return $packs; + } } diff --git a/third_party/gameq_v2/gameq/protocols/cscz.php b/third_party/gameq_v2/gameq/protocols/cscz.php index 822e6fe3..b539128f 100644 --- a/third_party/gameq_v2/gameq/protocols/cscz.php +++ b/third_party/gameq_v2/gameq/protocols/cscz.php @@ -3,47 +3,43 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Counter-Strike: Condition Zero Protocol Class + * Class Cscz * - * @author Austin Bischoff + * Based off of CS 1.6 + * + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Cscz extends GameQ_Protocols_Source +class Cscz extends Cs16 { - protected $name = "cscz"; - protected $name_long = "Counter-Strike: Condition Zero"; - /** - * We have to overload this function to cheat the rules processing because of some wierdness, old ass game! - * - * @see GameQ_Protocols_Source::preProcess_rules() - */ - protected function preProcess_rules($packets) - { - $engine_orig = $this->source_engine; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'cscz'; - // Override the engine type for rules, not sure why its like that - $this->source_engine = self::GOLDSOURCE_ENGINE; - - // Now process the rules - $ret = parent::preProcess_rules($packets); - - // Reset the engine type - $this->source_engine = $engine_orig; - - return $ret; - } + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Counter-Strike: Condition Zero"; } diff --git a/third_party/gameq_v2/gameq/protocols/csgo.php b/third_party/gameq_v2/gameq/protocols/csgo.php index 8360f28a..41af7352 100644 --- a/third_party/gameq_v2/gameq/protocols/csgo.php +++ b/third_party/gameq_v2/gameq/protocols/csgo.php @@ -3,26 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Counter-Strike: Global Offensive Protocol Class + * Class Csgo * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Csgo extends GameQ_Protocols_Source +class Csgo extends Source { - protected $name = "csgo"; - protected $name_long = "Counter-Strike: Global Offensive"; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'csgo'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Counter-Strike: Global Offensive"; } diff --git a/third_party/gameq_v2/gameq/protocols/css.php b/third_party/gameq_v2/gameq/protocols/css.php index b1d70e89..be75da3d 100644 --- a/third_party/gameq_v2/gameq/protocols/css.php +++ b/third_party/gameq_v2/gameq/protocols/css.php @@ -3,26 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Counter-Strike: Source Protocol Class + * Class Css * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_Css extends GameQ_Protocols_Source +class Css extends Source { - protected $name = "css"; - protected $name_long = "Counter-Strike: Source"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'css'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Counter-Strike: Source"; } diff --git a/third_party/gameq_v2/gameq/protocols/cube2.php b/third_party/gameq_v2/gameq/protocols/cube2.php deleted file mode 100644 index afbaa71e..00000000 --- a/third_party/gameq_v2/gameq/protocols/cube2.php +++ /dev/null @@ -1,175 +0,0 @@ -. - */ - -/** - * Cube 2: Sauerbraten Protocol Class - * - * References: - * https://qstat.svn.sourceforge.net/svnroot/qstat/trunk/qstat2/cube2.c - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Cube2 extends GameQ_Protocols -{ - protected $state = self::STATE_BETA; - - protected $normalize = array( - // General - 'general' => array( - 'hostname' => array('servername'), - 'numplayers' => array('num_players'), - 'maxplayers' => array('max_players'), - 'mapname' => array('map'), - 'gametype' => array('gametype'), - ), - ); - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "server", - ); - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); - - /** - * Default port for this server type - * - * @var int - */ - protected $port = 28802; // Default port, used if not set when instanced - - /** - * The query protocol used to make the call - * - * @var string - */ - protected $protocol = 'cube2'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'cube2'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Cube 2: Sauerbraten"; - - /** - * Pre-process the server status data that was returned. - * - * @param array $packets - */ - protected function preProcess_status($packets) - { - // Process the packets - return implode('', $packets); - } - - /** - * Handles processing the status data into a usable format - * - * @throws GameQ_ProtocolsException - */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Let's preprocess the rules - $data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]); - - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Check the header, should be the same response as the packet we sent - if($buf->read(6) != $this->packets[self::PACKET_STATUS]) - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header type (should be {$this->packets[self::PACKET_STATUS]})."); - return array(); - } - - // NOTE: the following items were figured out using some source and trial and error - - $result->add('num_players', $this->readInt($buf)); - $result->add('version', $this->readInt($buf)); - $result->add('protocol', $this->readInt($buf)); - $result->add('mode', $this->readInt($buf)); - $result->add('time_remaining', $this->readInt($buf)); - $result->add('max_players', $this->readInt($buf)); - $result->add('mastermode', $this->readInt($buf)); - - // @todo: Sometimes there is an extra char here before the map string. Not sure what causes it or how - // to even check for its existance. - - $result->add('map', $buf->readString()); - $result->add('servername', $buf->readString()); - - unset($buf, $data); - - return $result->fetch(); - } - - /** - * Function to check for varying int values in the responses. Makes life a little easier - * - * @param GameQ_Buffer $buf - * @return number - */ - protected function readInt(GameQ_Buffer &$buf) - { - // Look ahead and see if 32-bit int - if($buf->lookAhead(1) == "\x81") - { - $buf->skip(1); - return $buf->readInt32(); - } - // Look ahead and see if 16-bit int - elseif($buf->lookAhead(1) == "\x80") - { - $buf->skip(1); - return $buf->readInt16(); - } - else // 8-bit - { - return $buf->readInt8(); - } - } -} diff --git a/third_party/gameq_v2/gameq/protocols/dayz.php b/third_party/gameq_v2/gameq/protocols/dayz.php index aa3f92e1..01c7c28d 100644 --- a/third_party/gameq_v2/gameq/protocols/dayz.php +++ b/third_party/gameq_v2/gameq/protocols/dayz.php @@ -3,28 +3,64 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * DayZ Standalone Protocol Class + * Class Dayz * - * Note that this is not DayZ Mod but a standalone game in Steam - * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Dayz extends GameQ_Protocols_Source +class Dayz extends Source { - protected $name = "dayz"; - protected $name_long = "DayZ Standalone"; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'dayz'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "DayZ Standalone"; + + /** + * Overload the math used to guess at the Query Port + * + * @param int $clientPort + * + * @return int + */ + public function findQueryPort($clientPort) + { + + /* + * Port layout: + * 2302 - 27016 + * 2402 - 27017 + * 2502 - 27018 + * 2602 - 27019 + * 2702 - 27020 + * ... + */ + + return 27016 + (($clientPort - 2302) / 100); + } } diff --git a/third_party/gameq_v2/gameq/protocols/dayzmod.php b/third_party/gameq_v2/gameq/protocols/dayzmod.php index 3c2e3fc3..2ce1076d 100644 --- a/third_party/gameq_v2/gameq/protocols/dayzmod.php +++ b/third_party/gameq_v2/gameq/protocols/dayzmod.php @@ -3,27 +3,42 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * DayZ Mod Protocol Class + * Class Dayzmod * - * @author Marcel Bößendörfer - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Marcel Bößendörfer + * @author Austin Bischoff */ -class GameQ_Protocols_Dayzmod extends GameQ_Protocols_Armedassault2 +class Dayzmod extends Armedassault2oa { - protected $name = "dayzmod"; - protected $name_long = "DayZ Mod"; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'dayzmod'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "DayZ Mod"; } diff --git a/third_party/gameq_v2/gameq/protocols/dod.php b/third_party/gameq_v2/gameq/protocols/dod.php index 844bedaf..0c7baf69 100644 --- a/third_party/gameq_v2/gameq/protocols/dod.php +++ b/third_party/gameq_v2/gameq/protocols/dod.php @@ -3,26 +3,43 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Day of Defeat Protocol Class + * Class Dod * - * @author Austin Bischoff + * Based off of CS 1.6 + * + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Dod extends GameQ_Protocols_Source +class Dod extends Cs16 { - protected $name = "dod"; - protected $name_long = "Day of Defeat"; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'dod'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Day of Defeat"; } diff --git a/third_party/gameq_v2/gameq/protocols/dods.php b/third_party/gameq_v2/gameq/protocols/dods.php index 0aeff64b..898d75b9 100644 --- a/third_party/gameq_v2/gameq/protocols/dods.php +++ b/third_party/gameq_v2/gameq/protocols/dods.php @@ -3,26 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Day of Defeat: Source Protocol Class + * Class Dods * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_Dods extends GameQ_Protocols_Source +class Dods extends Source { - protected $name = "dods"; - protected $name_long = "Day of Defeat: Source"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'dods'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Day of Defeat: Source"; } diff --git a/third_party/gameq_v2/gameq/protocols/doom3.php b/third_party/gameq_v2/gameq/protocols/doom3.php index 3fdeec01..2e00f5f1 100644 --- a/third_party/gameq_v2/gameq/protocols/doom3.php +++ b/third_party/gameq_v2/gameq/protocols/doom3.php @@ -3,161 +3,219 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + /** * Doom3 Protocol Class * - * @author Austin Bischoff + * Handles processing DOOM 3 servers + * + * @package GameQ\Protocols + * @author Wilson Jesus <> */ -class GameQ_Protocols_Doom3 extends GameQ_Protocols +class Doom3 extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_ALL => "\xFF\xFFgetInfo\x00PiNGPoNG\x00", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_ALL => "\xFF\xFFgetInfo\x00PiNGPoNG\x00", + ]; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_all", - ); + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\xFF\xFFinfoResponse" => 'processStatus', + ]; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 27666; // Default port, used if not set when instanced + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'doom3'; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'doom3'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'doom3'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'doom3'; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Doom 3"; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Doom 3"; + /** + * The client join link + * + * @type string + */ + protected $join_link = null; + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'hostname' => 'si_name', + 'gametype' => 'gamename', + 'mapname' => 'si_map', + 'maxplayers' => 'si_maxPlayers', + 'numplayers' => 'clients', + 'password' => 'si_usepass', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'ping' => 'ping', + ], + ]; - /* - * Internal methods - */ + /** + * Handle response from the server + * + * @return mixed + * @throws Exception + */ + public function processResponse() + { + // Make a buffer + $buffer = new Buffer(implode('', $this->packets_response)); - protected function preProcess_all($packets=array()) - { - // Implode and return - return implode('', $packets); - } + // Grab the header + $header = $buffer->readString(); - protected function process_all() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_ALL)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Parse the response - $data = $this->preProcess_all($this->packets_response[self::PACKET_ALL]); - - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Header - if ($buf->readInt16() !== 65535 or $buf->readString() !== 'infoResponse') - { - throw new GameQ_ProtocolsException('Header for response does not match. Buffer:'.$this->packets_response[self::PACKET_ALL]); - return array(); + // Header + // Figure out which packet response this is + if (empty($header) || !array_key_exists($header, $this->responses)) { + throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); } - $result->add('version', $buf->readInt8() . '.' . $buf->readInt8()); + return call_user_func_array([$this, $this->responses[$header]], [$buffer]); + } - // Var / value pairs, delimited by an empty pair - while ($buf->getLength()) - { - $var = $buf->readString(); - $val = $buf->readString(); + /** + * Process the status response + * + * @param Buffer $buffer + * + * @return array + */ + protected function processStatus(Buffer $buffer) + { + // We need to split the data and offload + $results = $this->processServerInfo($buffer); + + $results = array_merge_recursive( + $results, + $this->processPlayers($buffer) + ); + + unset($buffer); + + // Return results + return $results; + } + + /** + * Handle processing the server information + * + * @param Buffer $buffer + * + * @return array + */ + protected function processServerInfo(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); + + $result->add('version', $buffer->readInt8() . '.' . $buffer->readInt8()); + + // Key / value pairs, delimited by an empty pair + while ($buffer->getLength()) { + $key = trim($buffer->readString()); + $val = utf8_encode(trim($buffer->readString())); // Something is empty so we are done - if (empty($var) && empty($val)) - { - break; + if (empty($key) && empty($val)) { + break; } - $result->add($var, $val); + $result->add($key, $val); } - // Now lets parse the players - $this->parsePlayers($buf, $result); + unset($buffer); - unset($buf, $data); + return $result->fetch(); + } - // Return the result - return $result->fetch(); - } + /** + * Handle processing of player data + * + * @param Buffer $buffer + * + * @return array + */ + protected function processPlayers(Buffer $buffer) + { + // Some games do not have a number of current players + $playerCount = 0; - /** - * Parse the players. Set as its own method so it can be overloaded. - * - * @param GameQ_Buffer $buf - * @param GameQ_Result $result - */ - protected function parsePlayers(GameQ_Buffer &$buf, GameQ_Result &$result) - { - // There is no way to see the number of players so we have to increment - // a variable and do it that way. - $players = 0; - - - // Loop thru the buffer until we run out of data - while (($id = $buf->readInt8()) != 32) - { - $result->addPlayer('id', $id); - $result->addPlayer('ping', $buf->readInt16()); - $result->addPlayer('rate', $buf->readInt32()); - $result->addPlayer('name', $buf->readString()); - - $players++; - } - - // Add the number of players to the result - $result->add('numplayers', $players); - - return TRUE; - } + // Set the result to a new result instance + $result = new Result(); + + // Parse players + // Loop thru the buffer until we run out of data + while (($id = $buffer->readInt8()) != 32) { + // Add player info results + $result->addPlayer('id', $id); + $result->addPlayer('ping', $buffer->readInt16()); + $result->addPlayer('rate', $buffer->readInt32()); + // Add player name, encoded + $result->addPlayer('name', utf8_encode(trim($buffer->readString()))); + + // Increment + $playerCount++; + } + + // Add the number of players to the result + $result->add('clients', $playerCount); + + // Clear + unset($buffer, $playerCount); + + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/et.php b/third_party/gameq_v2/gameq/protocols/et.php index 9ffd29c0..63b5beb7 100644 --- a/third_party/gameq_v2/gameq/protocols/et.php +++ b/third_party/gameq_v2/gameq/protocols/et.php @@ -3,28 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** * Wolfenstein Enemy Territory Protocol Class * - * @author Austin Bischoff + * @package GameQ\Protocols + * + * @author Wilson Jesus <> */ -class GameQ_Protocols_Et extends GameQ_Protocols_Quake3 +class Et extends Quake3 { - protected $name = "et"; - protected $name_long = "Wolfenstein Enemy Territory"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'et'; - protected $port = 27960; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Wolfenstein Enemy Territory"; } diff --git a/third_party/gameq_v2/gameq/protocols/etqw.php b/third_party/gameq_v2/gameq/protocols/etqw.php index 25bc34e6..1f3a446c 100644 --- a/third_party/gameq_v2/gameq/protocols/etqw.php +++ b/third_party/gameq_v2/gameq/protocols/etqw.php @@ -3,223 +3,232 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Buffer; +use GameQ\Exception\Protocol as Exception; +use GameQ\Protocol; +use GameQ\Result; + /** - * Enemy Territory: Quake Wars Protocol Class + * Enemy Territory Quake Wars Protocol Class * * @author Austin Bischoff */ -class GameQ_Protocols_Etqw extends GameQ_Protocols +class Etqw extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "\xFF\xFFgetInfoEx\x00\x00\x00\x00", - //self::PACKET_STATUS => "\xFF\xFFgetInfo\x00\x00\x00\x00\x00", - ); - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_STATUS => "\xFF\xFFgetInfoEx\x00\x00\x00\x00", + //self::PACKET_STATUS => "\xFF\xFFgetInfo\x00\x00\x00\x00\x00", + ]; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 27733; // Default port, used if not set when instanced + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\xFF\xFFinfoExResponse" => "processStatus", + ]; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'etqw'; + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'etqw'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'etqw'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'etqw'; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Enemy Territory: Quake Wars"; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Enemy Territory Quake Wars"; - /* - * Internal methods - */ + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'gametype' => 'campaign', + 'hostname' => 'name', + 'mapname' => 'map', + 'maxplayers' => 'maxPlayers', + 'mod' => 'gamename', + 'numplayers' => 'numplayers', + 'password' => 'privateClients', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'score' => 'score', + 'time' => 'time', + ], + ]; - protected function preProcess_status($packets) - { - // Should only be one packet - if (count($packets) > 1) - { - throw new GameQ_ProtocolsException('Enemy Territor: Quake Wars status has more than 1 packet'); - } + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { + // In case it comes back as multiple packets (it shouldn't) + $buffer = new Buffer(implode('', $this->packets_response)); - // Make buffer so we can check this out - $buf = new GameQ_Buffer($packets[0]); + // Figure out what packet response this is for + $response_type = $buffer->readString(); - // Grab the header - $header = $buf->readString(); + // Figure out which packet response this is + if (!array_key_exists($response_type, $this->responses)) { + throw new Exception(__METHOD__ . " response type '{$response_type}' is not valid"); + } - // Now lets verify the header - if(!strstr($header, 'infoExResponse')) - { - throw new GameQ_ProtocolsException('Unable to match Enemy Territor: Quake Wars response header. Header: '. $header); - return FALSE; - } + // Offload the call + $results = call_user_func_array([$this, $this->responses[$response_type]], [$buffer]); - // Return the data with the header stripped, ready to go. - return $buf->getBuffer(); - } + return $results; + } - /** - * Process the server status - * - * @throws GameQ_ProtocolsException - */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } + /* + * Internal methods + */ - // Set the result to a new result instance - $result = new GameQ_Result(); + /** + * Handle processing the status response + * + * @param Buffer $buffer + * + * @return array + */ + protected function processStatus(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); - // Lets pre process and make sure these things are in the proper order by id - $data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]); + // Defaults + $result->add('dedicated', 1); - // Make buffer - $buf = new GameQ_Buffer($data); + // Now burn the challenge, version and size + $buffer->skip(16); - // Now burn the challenge, version and size - $buf->skip(16); + // Key / value pairs + while ($buffer->getLength()) { + $var = str_replace('si_', '', $buffer->readString()); + $val = $buffer->readString(); + if (empty($var) && empty($val)) { + break; + } + // Add the server prop + $result->add($var, $val); + } + // Now let's do the basic player info + $this->parsePlayers($buffer, $result); - // Key / value pairs - while ($buf->getLength()) - { - $var = str_replace('si_', '', $buf->readString()); - $val = $buf->readString(); + // Now grab the rest of the server info + $result->add('osmask', $buffer->readInt32()); + $result->add('ranked', $buffer->readInt8()); + $result->add('timeleft', $buffer->readInt32()); + $result->add('gamestate', $buffer->readInt8()); + $result->add('servertype', $buffer->readInt8()); - if (empty($var) && empty($val)) - { - break; - } + // 0: regular server + if ($result->get('servertype') == 0) { + $result->add('interested_clients', $buffer->readInt8()); + } else { + // 1: tv server + $result->add('connected_clients', $buffer->readInt32()); + $result->add('max_clients', $buffer->readInt32()); + } - // Add the server prop - $result->add($var, $val); - } + // Now let's parse the extended player info + $this->parsePlayersExtra($buffer, $result); - // Now let's do the basic player info - $this->parsePlayers($buf, $result); + unset($buffer); - // Now grab the rest of the server info - $result->add('osmask', $buf->readInt32()); - $result->add('ranked', $buf->readInt8()); - $result->add('timeleft', $buf->readInt32()); - $result->add('gamestate', $buf->readInt8()); - $result->add('servertype', $buf->readInt8()); + return $result->fetch(); + } - // 0: regular server - if ($result->get('servertype') == 0) - { - $result->add('interested_clients', $buf->readInt8()); - } - // 1: tv server - else - { - $result->add('connected_clients', $buf->readInt32()); - $result->add('max_clients', $buf->readInt32()); - } + /** + * Parse players out of the status ex response + * + * @param Buffer $buffer + * @param Result $result + */ + protected function parsePlayers(Buffer &$buffer, Result &$result) + { + // By default there are 0 players + $players = 0; - // Now let's parse the extended player info - $this->parsePlayersExtra($buf, $result); + // Iterate over the players until we run out + while (($id = $buffer->readInt8()) != 32) { + $result->addPlayer('id', $id); + $result->addPlayer('ping', $buffer->readInt16()); + $result->addPlayer('name', $buffer->readString()); + $result->addPlayer('clantag_pos', $buffer->readInt8()); + $result->addPlayer('clantag', $buffer->readString()); + $result->addPlayer('bot', $buffer->readInt8()); + $players++; + } - // Free some memory - unset($sections, $buf, $data); + // Let's add in the current players as a result + $result->add('numplayers', $players); - // Return the result - return $result->fetch(); - } + // Free some memory + unset($id); + } - /** - * Parse the players and add them to the return. - * - * @param GameQ_Buffer $buf - * @param GameQ_Result $result - */ - protected function parsePlayers(GameQ_Buffer &$buf, GameQ_Result &$result) - { - $players = 0; + /** + * Handle parsing extra player data + * + * @param Buffer $buffer + * @param Result $result + */ + protected function parsePlayersExtra(Buffer &$buffer, Result &$result) + { + // Iterate over the extra player info + while (($id = $buffer->readInt8()) != 32) { + $result->addPlayer('total_xp', $buffer->readFloat32()); + $result->addPlayer('teamname', $buffer->readString()); + $result->addPlayer('total_kills', $buffer->readInt32()); + $result->addPlayer('total_deaths', $buffer->readInt32()); + } - while (($id = $buf->readInt8()) != 32) - { - $result->addPlayer('id', $id); - $result->addPlayer('ping', $buf->readInt16()); - $result->addPlayer('name', $buf->readString()); - $result->addPlayer('clantag_pos', $buf->readInt8()); - $result->addPlayer('clantag', $buf->readString()); - $result->addPlayer('bot', $buf->readInt8()); + // @todo: Add team stuff - $players++; - } - - // Let's add in the current players as a result - $result->add('numplayers', $players); - - // Free some memory - unset($id); - } - - /** - * Parse the players extra info and add them to the return. - * - * @param GameQ_Buffer $buf - * @param GameQ_Result $result - */ - protected function parsePlayersExtra(GameQ_Buffer &$buf, GameQ_Result &$result) - { - while (($id = $buf->readInt8()) != 32) - { - $result->addPlayer('total_xp', $buf->readFloat32()); - $result->addPlayer('teamname', $buf->readString()); - $result->addPlayer('total_kills', $buf->readInt32()); - $result->addPlayer('total_deaths', $buf->readInt32()); - } - - // @todo: Add team stuff - - // Free some memory - unset($id); - } + // Free some memory + unset($id); + } } diff --git a/third_party/gameq_v2/gameq/protocols/fear.php b/third_party/gameq_v2/gameq/protocols/fear.php deleted file mode 100644 index 74482392..00000000 --- a/third_party/gameq_v2/gameq/protocols/fear.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * F.E.A.R. Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Fear extends GameQ_Protocols_Gamespy2 -{ - protected $name = "fear"; - protected $name_long = "F.E.A.R."; - - protected $port = 27888; -} diff --git a/third_party/gameq_v2/gameq/protocols/ffe.php b/third_party/gameq_v2/gameq/protocols/ffe.php index f28cb241..c0947bdc 100644 --- a/third_party/gameq_v2/gameq/protocols/ffe.php +++ b/third_party/gameq_v2/gameq/protocols/ffe.php @@ -3,26 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Fortress Forever Protocol Class + * Class Ffe - Fortress Forever * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Ffe extends GameQ_Protocols_Source +class Ffe extends Source { - protected $name = "ffe"; - protected $name_long = "Fortress Forever"; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'ffe'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Fortress Forever"; } diff --git a/third_party/gameq_v2/gameq/protocols/ffow.php b/third_party/gameq_v2/gameq/protocols/ffow.php index 068259b2..00c33d47 100644 --- a/third_party/gameq_v2/gameq/protocols/ffow.php +++ b/third_party/gameq_v2/gameq/protocols/ffow.php @@ -1,246 +1,243 @@ . - */ + + +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; /** - * Frontlines: Fuel of War Protocol Class + * Frontlines Fuel of War Protocol Class * - * Class is incomplete due to the lack of servers with players active. + * Handles processing ffow servers * + * Class is incomplete due to lack of players to test against. * http://wiki.hlsw.net/index.php/FFOW_Protocol * - * @author Austin Bischoff + * @package GameQ\Protocols */ -class GameQ_Protocols_Ffow extends GameQ_Protocols +class Ffow extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x57", - self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s", - //self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s", - self::PACKET_INFO => "\xFF\xFF\xFF\xFF\x46\x4C\x53\x51", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x57", + self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s", + self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s", + self::PACKET_INFO => "\xFF\xFF\xFF\xFF\x46\x4C\x53\x51", + ]; - protected $state = self::STATE_TESTING; + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\xFF\xFF\xFF\xFF\x49\x02" => 'processInfo', // I + "\xFF\xFF\xFF\xFF\x45\x00" => 'processRules', // E + "\xFF\xFF\xFF\xFF\x44\x00" => 'processPlayers', // D + ]; - /** - * Set the packet mode to linear - * - * @var string - */ - protected $packet_mode = self::PACKET_MODE_LINEAR; + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'ffow'; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_info", - "process_rules", - //"process_players", - ); + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'ffow'; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 5478; // Default port, used if not set when instanced + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Frontlines Fuel of War"; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'ffow'; + /** + * The client join link + * + * @type string + */ + protected $join_link = null; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'ffow'; + /** + * query_port = client_port + 2 + * + * @type int + */ + protected $port_diff = 2; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Frontlines: Fuel of War"; + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'gametype' => 'gamemode', + 'hostname' => 'servername', + 'mapname' => 'mapname', + 'maxplayers' => 'max_players', + 'mod' => 'modname', + 'numplayers' => 'num_players', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'ping' => 'ping', + 'score' => 'frags', + ], + ]; - /* - * Internal methods - */ + /** + * Parse the challenge response and apply it to all the packet types + * + * @param \GameQ\Buffer $challenge_buffer + * + * @return bool + * @throws \GameQ\Exception\Protocol + */ + public function challengeParseAndApply(Buffer $challenge_buffer) + { + // Burn padding + $challenge_buffer->skip(5); - /** - * Parse the challenge response and apply it to all the packet types - * that require it. - * - * @see GameQ_Protocols_Core::parseChallengeAndApply() - */ - protected function parseChallengeAndApply() - { - // Skip the header - $this->challenge_buffer->skip(5); + // Apply the challenge and return + return $this->challengeApply($challenge_buffer->read(4)); + } - // Apply the challenge and return - return $this->challengeApply($this->challenge_buffer->read(4)); - } + /** + * Handle response from the server + * + * @return mixed + * @throws Exception + */ + public function processResponse() + { + // Init results + $results = []; - /** - * Preprocess the server info packet(s) - * - * @param unknown_type $packets - */ - protected function preProcess_info($packets=array()) - { - // Implode and return - return implode('', $packets); - } + foreach ($this->packets_response as $response) { + $buffer = new Buffer($response); - protected function process_info() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_INFO)) - { - return array(); - } + // Figure out what packet response this is for + $response_type = $buffer->read(6); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Figure out which packet response this is + if (!array_key_exists($response_type, $this->responses)) { + throw new Exception(__METHOD__ . " response type '" . bin2hex($response_type) . "' is not valid"); + } - // Parse the response - $data = $this->preProcess_info($this->packets_response[self::PACKET_INFO]); + // Now we need to call the proper method + $results = array_merge( + $results, + call_user_func_array([$this, $this->responses[$response_type]], [$buffer]) + ); - // Create a new buffer - $buf = new GameQ_Buffer($data); + unset($buffer); + } - // Skip Header - $buf->skip(6); + return $results; + } - $result->add('servername', $buf->readString()); - $result->add('mapname', $buf->readString()); - $result->add('modname', $buf->readString()); - $result->add('gamemode', $buf->readString()); - $result->add('description', $buf->readString()); - $result->add('version', $buf->readString()); - $result->add('port', $buf->readInt16()); - $result->add('num_players', $buf->readInt8()); - $result->add('max_players', $buf->readInt8()); - $result->add('dedicated', $buf->readInt8()); - $result->add('os', $buf->readInt8()); - $result->add('password', $buf->readInt8()); - $result->add('anticheat', $buf->readInt8()); - $result->add('average_fps', $buf->readInt8()); - $result->add('round', $buf->readInt8()); - $result->add('max_rounds', $buf->readInt8()); - $result->add('time_left', $buf->readInt16()); + /** + * Handle processing the server information + * + * @param Buffer $buffer + * + * @return array + */ + protected function processInfo(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); - unset($buf, $data); + $result->add('servername', $buffer->readString()); + $result->add('mapname', $buffer->readString()); + $result->add('modname', $buffer->readString()); + $result->add('gamemode', $buffer->readString()); + $result->add('description', $buffer->readString()); + $result->add('version', $buffer->readString()); + $result->add('port', $buffer->readInt16()); + $result->add('num_players', $buffer->readInt8()); + $result->add('max_players', $buffer->readInt8()); + $result->add('dedicated', $buffer->readInt8()); + $result->add('os', $buffer->readInt8()); + $result->add('password', $buffer->readInt8()); + $result->add('anticheat', $buffer->readInt8()); + $result->add('average_fps', $buffer->readInt8()); + $result->add('round', $buffer->readInt8()); + $result->add('max_rounds', $buffer->readInt8()); + $result->add('time_left', $buffer->readInt16()); - // Return the result - return $result->fetch(); - } + unset($buffer); - /** - * Preprocess the rule packets returned. Not sure if this is final, need server to test against. - * - * @param array $packets - */ - protected function preProcess_rules($packets=array()) - { - // Implode and return - return implode('', $packets); - } + return $result->fetch(); + } - /** - * Process the rules and return the data result - */ - protected function process_rules() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_RULES)) - { - return array(); - } + /** + * Handle processing the server rules + * + * @param Buffer $buffer + * + * @return array + */ + protected function processRules(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Burn extra header + $buffer->skip(1); - // Parse the response - $data = $this->preProcess_rules($this->packets_response[self::PACKET_RULES]); + // Read rules until we run out of buffer + while ($buffer->getLength()) { + $key = $buffer->readString(); + // Check for map + if (strstr($key, "Map:")) { + $result->addSub("maplist", "name", $buffer->readString()); + } else // Regular rule + { + $result->add($key, $buffer->readString()); + } + } - // Create a new buffer - $buf = new GameQ_Buffer($data); + unset($buffer); - // Skip Header - $buf->skip(6); + return $result->fetch(); + } - while($buf->getLength()) - { - $key = $buf->readString(); + /** + * Handle processing of player data + * + * @todo: Build this out when there is a server with players to test against + * + * @param Buffer $buffer + * + * @return array + */ + protected function processPlayers(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); - if(strlen($key) == 0) - { - break; - } + unset($buffer); - // Check for map - if(strstr($key, "Map:")) - { - $result->addSub("maplist", "name", $buf->readString()); - } - else // Regular rule - { - $result->add($key, $buf->readString()); - } - } - - unset($buf, $data); - - // Return the result - return $result->fetch(); - } - - /** - * Pre process the player packets, Not final. Need server to test against - * - * @param array $packets - */ - protected function preProcess_players($packets=array()) - { - // Implode and return - return implode('', $packets); - } - - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } - - return array(); - } + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/fof.php b/third_party/gameq_v2/gameq/protocols/fof.php index 6ed33f3f..a35c4c0a 100644 --- a/third_party/gameq_v2/gameq/protocols/fof.php +++ b/third_party/gameq_v2/gameq/protocols/fof.php @@ -3,27 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Fistful of Frags Protocol Class - * - * @author Austin Bischoff edited by FV-Hosting - */ +namespace GameQ\Protocols; -class GameQ_Protocols_FoF extends GameQ_Protocols_Source +/** + * Class Fistful of Frags + * + * @package GameQ\Protocols + * @author Austin Bischoff + * @author Jesse Lukas +*/ +class Fof extends Source { - protected $name = "fof"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'fof'; + + /** + * Longer string name of this protocol class + * + * @type string + */ protected $name_long = "Fistful of Frags"; -} \ No newline at end of file +} diff --git a/third_party/gameq_v2/gameq/protocols/gamespy.php b/third_party/gameq_v2/gameq/protocols/gamespy.php index cd7a85a1..b1a1e4fa 100644 --- a/third_party/gameq_v2/gameq/protocols/gamespy.php +++ b/third_party/gameq_v2/gameq/protocols/gamespy.php @@ -3,214 +3,179 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use \GameQ\Exception\Protocol as Exception; + /** - * GameSpy Protocol Class - * - * This class is used as the basis for all game servers - * that use the GameSpy protocol for querying - * server status. + * GameSpy Protocol class * * @author Austin Bischoff */ -class GameQ_Protocols_Gamespy extends GameQ_Protocols +class Gamespy extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * Note: We only send the status packet since that has all the information we ever need. - * The other packets are left for reference purposes - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "\x5C\x73\x74\x61\x74\x75\x73\x5C", - //self::PACKET_PLAYERS => "\x5C\x70\x6C\x61\x79\x65\x72\x73\x5C", - //self::PACKET_DETAILS => "\x5C\x69\x6E\x66\x6F\x5C", - //self::PACKET_BASIC => "\x5C\x62\x61\x73\x69\x63\x5C", - //self::PACKET_RULES => "\x5C\x72\x75\x6C\x65\x73\x5C", - ); - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_STATUS => "\x5C\x73\x74\x61\x74\x75\x73\x5C", + ]; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 1; // Default port, used if not set when instanced + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'gamespy'; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'gamespy'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'gamespy'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'gamespy'; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "GameSpy Server"; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Gamespy"; + /** + * The client join link + * + * @type string + */ + protected $join_link = null; + + /** + * Process the response for this protocol + * + * @return array + * @throws Exception + */ + public function processResponse() + { + // Holds the processed packets so we can sort them in case they come in an unordered + $processed = []; + + // Iterate over the packets + foreach ($this->packets_response as $response) { + // Check to see if we had a preg_match error + if (($match = preg_match("#^(.*)\\\\queryid\\\\([^\\\\]+)(\\\\|$)#", $response, $matches)) === false + || $match != 1 + ) { + throw new Exception(__METHOD__ . " An error occurred while parsing the packets for 'queryid'"); + } + + // Multiply so we move the decimal point out of the way, if there is one + $key = (int)(floatval($matches[2]) * 1000); + + // Add this packet to the processed + $processed[$key] = $matches[1]; + } + + // Sort the new array to make sure the keys (query ids) are in the proper order + ksort($processed, SORT_NUMERIC); + + // Create buffer and offload processing + return $this->processStatus(new Buffer(implode('', $processed))); + } /* * Internal methods */ - protected function preProcess($packets) + /** + * Handle processing the status buffer + * + * @param Buffer $buffer + * + * @return array + */ + protected function processStatus(Buffer $buffer) { - // Only one packet so its in order - if (count($packets) == 1) - { - return $packets[0]; - } + // Set the result to a new result instance + $result = new Result(); - // Holds the new list of packets, which will be stripped of queryid and ordered properly. - $packets_ordered = array(); + // By default dedicted + $result->add('dedicated', 1); - // Loop thru the packets - foreach ($packets as $packet) - { - // Check to see if we had a preg_match error - if(preg_match("#^(.*)\\\\queryid\\\\([^\\\\]+)(\\\\|$)#", $packet, $matches) === FALSE) - { - throw new GameQ_ProtocolsException('An error occured while parsing the status packets'); - return $packets_ordered; - } - - // Lets make the key proper incase of decimal points - if(strstr($matches[2], '.')) - { - list($req_id, $req_num) = explode('.', $matches[2]); - - // Now lets put back the number but make sure we pad the req_num so it is correct - // Should make sure the length is always 4 digits past the decimal point - // For some reason the req_num is 1->12.. instead of 01->12 ... so it doesnt ksort properly - $key = $req_id . sprintf(".%04s", $req_num); - } - else - { - $key = $matches[2]; - } - - // Add this stripped queryid to the new array with the id as the key - $packets_ordered[$key] = $matches[1]; + // Lets peek and see if the data starts with a \ + if ($buffer->lookAhead(1) == '\\') { + // Burn the first one + $buffer->skip(1); } - // Sort the new array to make sure the keys (query ids) are in the proper order - ksort($packets_ordered, SORT_NUMERIC); + // Explode the data + $data = explode('\\', $buffer->getBuffer()); - // Implode and return only the values as we dont care about the keys anymore - return implode('', array_values($packets_ordered)); - } + // No longer needed + unset($buffer); - /** - * Process the server status - * - * @throws GameQ_ProtocolsException - */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } + // Init some vars + $numPlayers = 0; + $numTeams = 0; - // Set the result to a new result instance - $result = new GameQ_Result(); + $itemCount = count($data); - // Lets pre process and make sure these things are in the proper order by id - $data = $this->preProcess($this->packets_response[self::PACKET_STATUS]); + // Check to make sure we have more than 1 item in the array before trying to loop + if (count($data) > 1) { + // Now lets loop the array since we have items + for ($x = 0; $x < $itemCount; $x += 2) { + // Set some local vars + $key = $data[$x]; + $val = $data[$x + 1]; - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Lets peek and see if the data starts with a \ - if($buf->lookAhead(1) == '\\') - { - // Burn the first one - $buf->skip(1); - } - - // Explode the data - $data = explode('\\', $buf->getBuffer()); - - // Remove the last 2 "items" as it should be final\ - array_pop($data); - array_pop($data); - - // Init some vars - $num_players = 0; - $num_teams = 0; - - // Now lets loop the array - for($x=0;$x_ variable (i.e players) - if(($suffix = strrpos($key, '_')) !== FALSE && is_numeric(substr($key, $suffix+1))) - { - // See if this is a team designation - if(substr($key, 0, $suffix) == 'teamname') - { - $result->addTeam('teamname', $val); - $num_teams++; - } - else // Its a player - { - if(substr($key, 0, $suffix) == 'playername') - { - $num_players++; - } - - $result->addPlayer(substr($key, 0, $suffix), $val); - - } + // Check for _ variable (i.e players) + if (($suffix = strrpos($key, '_')) !== false && is_numeric(substr($key, $suffix + 1))) { + // See if this is a team designation + if (substr($key, 0, $suffix) == 'teamname') { + $result->addTeam('teamname', $val); + $numTeams++; + } else { + // Its a player + if (substr($key, 0, $suffix) == 'playername') { + $numPlayers++; + } + $result->addPlayer(substr($key, 0, $suffix), utf8_encode($val)); + } + } else { + // Regular variable so just add the value. + $result->add($key, $val); + } } - else // Regular variable so just add the value. - { - $result->add($key, $val); - } - } + } - // Add the player and team count - $result->add('num_players', $num_players); - $result->add('num_teams', $num_teams); + // Add the player and team count + $result->add('num_players', $numPlayers); + $result->add('num_teams', $numTeams); - unset($buf, $data, $key, $val, $suffix, $x); + // Unset some stuff to free up memory + unset($data, $key, $val, $suffix, $x, $itemCount); + // Return the result return $result->fetch(); - } + } } diff --git a/third_party/gameq_v2/gameq/protocols/gamespy2.php b/third_party/gameq_v2/gameq/protocols/gamespy2.php index a8ddb3da..c7788d9e 100644 --- a/third_party/gameq_v2/gameq/protocols/gamespy2.php +++ b/third_party/gameq_v2/gameq/protocols/gamespy2.php @@ -3,259 +3,267 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Exception\Protocol as Exception; +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; + /** - * GameSpy2 Protocol Class + * GameSpy2 Protocol class * - * This class is used as the basis for all game servers - * that use the GameSpy2 protocol for querying - * server status. + * Given the ability for non utf-8 characters to be used as hostnames, player names, etc... this + * version returns all strings utf-8 encoded (utf8_encode). To access the proper version of a + * string response you must use utf8_decode() on the specific response. * * @author Austin Bischoff */ -class GameQ_Protocols_Gamespy2 extends GameQ_Protocols +class Gamespy2 extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_DETAILS => "\xFE\xFD\x00\x43\x4F\x52\x59\xFF\x00\x00", - self::PACKET_PLAYERS => "\xFE\xFD\x00\x43\x4F\x52\x59\x00\xFF\xFF", - ); - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_details", - "process_players", - ); + /** + * Define the state of this class + * + * @type int + */ + protected $state = self::STATE_BETA; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 1; // Default port, used if not set when instanced + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_DETAILS => "\xFE\xFD\x00\x43\x4F\x52\x59\xFF\x00\x00", + self::PACKET_PLAYERS => "\xFE\xFD\x00\x43\x4F\x52\x58\x00\xFF\xFF", + ]; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'gamespy2'; + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\x00\x43\x4F\x52\x59" => "processDetails", + "\x00\x43\x4F\x52\x58" => "processPlayers", + ]; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'gamespy2'; + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'gamespy2'; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Gamespy2"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'gamespy2'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "GameSpy2 Server"; + + /** + * The client join link + * + * @type string + */ + protected $join_link = null; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'gametype' => 'gametype', + 'hostname' => 'hostname', + 'mapname' => 'mapname', + 'maxplayers' => 'maxplayers', + 'mod' => 'mod', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + ]; + + + /** + * Process the response + * + * @return array + * @throws Exception + */ + public function processResponse() + { + + // Will hold the packets after sorting + $packets = []; + + // We need to pre-sort these for split packets so we can do extra work where needed + foreach ($this->packets_response as $response) { + $buffer = new Buffer($response); + + // Pull out the header + $header = $buffer->read(5); + + // Add the packet to the proper section, we will combine later + $packets[$header][] = $buffer->getBuffer(); + } + + unset($buffer); + + $results = []; + + // Now let's iterate and process + foreach ($packets as $header => $packetGroup) { + // Figure out which packet response this is + if (!array_key_exists($header, $this->responses)) { + throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); + } + + // Now we need to call the proper method + $results = array_merge( + $results, + call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))]) + ); + } + + unset($packets); + + return $results; + } /* * Internal methods */ - /** - * Pre-process the server details data that was returned. - * - * @param array $packets - */ - protected function preProcess_details($packets) - { - return $packets[0]; - } - /** - * Process the server details + * Handles processing the details data into a usable format * - * @throws GameQ_ProtocolsException + * @param \GameQ\Buffer $buffer + * + * @return array + * @throws Exception */ - protected function process_details() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_DETAILS)) - { - return array(); - } + protected function processDetails(Buffer $buffer) + { - // Set the result to a new result instance - $result = new GameQ_Result(); + // Set the result to a new result instance + $result = new Result(); - // Let's preprocess the rules - $data = $this->preProcess_details($this->packets_response[self::PACKET_DETAILS]); - - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Make sure the data is formatted properly - if($buf->lookAhead(5) != "\x00\x43\x4F\x52\x59") - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header. Header: ".$buf->lookAhead(5)); - return false; - } - - // Now verify the end of the data is correct - if($buf->readLast() !== "\x00") - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper ending. Ending: ".$buf->readLast()); - return false; - } - - // Skip the header - $buf->skip(5); - - // Loop thru all of the settings and add them - while ($buf->getLength()) - { - // Temp vars - $key = $buf->readString(); - $val = $buf->readString(); - - // Check to make sure there is a valid pair - if(!empty($key)) - { - $result->add($key, $val); - } + // We go until we hit an empty key + while ($buffer->getLength()) { + $key = $buffer->readString(); + if (strlen($key) == 0) { + break; + } + $result->add($key, utf8_encode($buffer->readString())); } - unset($buf, $data, $key, $var); + unset($buffer); return $result->fetch(); - } - - /** - * Pre-process the player data that was returned. - * - * @param array $packets - */ - protected function preProcess_players($packets) - { - return $packets[0]; } /** - * Process the player data + * Handles processing the players data into a usable format * - * @throws GameQ_ProtocolsException + * @param \GameQ\Buffer $buffer + * + * @return array + * @throws Exception */ - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } + protected function processPlayers(Buffer $buffer) + { - // Set the result to a new result instance - $result = new GameQ_Result(); + // Set the result to a new result instance + $result = new Result(); - // Let's preprocess the rules - $data = $this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]); + // Skip the header + $buffer->skip(1); - // Create a new buffer - $buf = new GameQ_Buffer($data); + // Players are first + $this->parsePlayerTeam('players', $buffer, $result); - // Make sure the data is formatted properly - if($buf->lookAhead(6) != "\x00\x43\x4F\x52\x59\x00") - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header. Header: ".$buf->lookAhead(6)); - return false; - } + // Teams are next + $this->parsePlayerTeam('teams', $buffer, $result); - // Now verify the end of the data is correct - if($buf->readLast() !== "\x00") - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper ending. Ending: ".$buf->readLast()); - return false; - } - - // Skip the header - $buf->skip(6); - - // Players are first - $this->parse_playerteam('players', $buf, $result); - - // Teams are next - $this->parse_playerteam('teams', $buf, $result); - - unset($buf, $data); + unset($buffer); return $result->fetch(); - } + } - /** - * Parse the player/team info returned from the player call - * - * @param string $type - * @param GameQ_Buffer $buf - * @param GameQ_Result $result - */ - protected function parse_playerteam($type, &$buf, &$result) - { - // Do count - $result->add('num_'.$type, $buf->readInt8()); + /** + * Parse the player/team info returned from the player call + * + * @param string $dataType + * @param \GameQ\Buffer $buffer + * @param \GameQ\Result $result + * + * @throws Exception + */ + protected function parsePlayerTeam($dataType, Buffer &$buffer, Result &$result) + { - // Variable names - $varnames = array(); + // Do count + $result->add('num_' . $dataType, $buffer->readInt8()); + + // Variable names + $varNames = []; // Loop until we run out of length - while ($buf->getLength()) - { - $varnames[] = str_replace('_', '', $buf->readString()); + while ($buffer->getLength()) { + $varNames[] = str_replace('_', '', $buffer->readString()); - if ($buf->lookAhead() === "\x00") - { - $buf->skip(); + if ($buffer->lookAhead() === "\x00") { + $buffer->skip(); break; } } // Check if there are any value entries - if ($buf->lookAhead() == "\x00") - { - $buf->skip(); + if ($buffer->lookAhead() == "\x00") { + $buffer->skip(); + return; } // Get the values - while ($buf->getLength() > 4) - { - foreach ($varnames as $varname) - { - $result->addSub($type, $varname, $buf->readString()); + while ($buffer->getLength() > 4) { + foreach ($varNames as $varName) { + $result->addSub($dataType, utf8_encode($varName), utf8_encode($buffer->readString())); } - if ($buf->lookAhead() === "\x00") - { - $buf->skip(); + if ($buffer->lookAhead() === "\x00") { + $buffer->skip(); break; } } - return; - } + return; + } } diff --git a/third_party/gameq_v2/gameq/protocols/gamespy3.php b/third_party/gameq_v2/gameq/protocols/gamespy3.php index ae86a2b0..2df0a4bd 100644 --- a/third_party/gameq_v2/gameq/protocols/gamespy3.php +++ b/third_party/gameq_v2/gameq/protocols/gamespy3.php @@ -3,444 +3,338 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; + /** - * GameSpy3 Protocol Class + * GameSpy3 Protocol class * - * This class is used as the basis for all game servers - * that use the GameSpy3 protocol for querying - * server status. - * - * Note: UT3 and Crysis2 have known issues with GSv3 responses + * Given the ability for non utf-8 characters to be used as hostnames, player names, etc... this + * version returns all strings utf-8 encoded (utf8_encode). To access the proper version of a + * string response you must use utf8_decode() on the specific response. * * @author Austin Bischoff */ -class GameQ_Protocols_Gamespy3 extends GameQ_Protocols +class Gamespy3 extends Protocol { - /** - * Set the packet mode to linear - * - * @var string - */ - protected $packet_mode = self::PACKET_MODE_LINEAR; - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_CHALLENGE => "\xFE\xFD\x09\x10\x20\x30\x40", - self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40%s\xFF\xFF\xFF\x01", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_CHALLENGE => "\xFE\xFD\x09\x10\x20\x30\x40", + self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40%s\xFF\xFF\xFF\x01", + ]; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_all", - ); + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'gamespy3'; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 1; // Default port, used if not set when instanced + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'gamespy3'; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'gamespy3'; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "GameSpy3 Server"; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'gamespy3'; + /** + * The client join link + * + * @type string + */ + protected $join_link = null; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Gamespy3"; + /** + * This defines the split between the server info and player/team info. + * This value can vary by game. This value is the default split. + * + * @var string + */ + protected $packetSplit = "/\\x00\\x00\\x01/m"; - /** - * Parse the challenge response and apply it to all the packet types - * that require it. - * - * @see GameQ_Protocols_Core::parseChallengeAndApply() - */ - protected function parseChallengeAndApply() + /** + * Parse the challenge response and apply it to all the packet types + * + * @param \GameQ\Buffer $challenge_buffer + * + * @return bool + * @throws \GameQ\Exception\Protocol + */ + public function challengeParseAndApply(Buffer $challenge_buffer) { - // Pull out the challenge - $challenge = substr(preg_replace( "/[^0-9\-]/si", "", $this->challenge_buffer->getBuffer()), 1); + // Pull out the challenge + $challenge = substr(preg_replace("/[^0-9\-]/si", "", $challenge_buffer->getBuffer()), 1); - $challenge_result = sprintf( - "%c%c%c%c", - ( $challenge >> 24 ), - ( $challenge >> 16 ), - ( $challenge >> 8 ), - ( $challenge >> 0 ) - ); + // By default, no challenge result (see #197) + $challenge_result = ''; - // Apply the challenge and return - return $this->challengeApply($challenge_result); + // Check for valid challenge (see #197) + if ($challenge) { + // Encode chellenge result + $challenge_result = sprintf( + "%c%c%c%c", + ($challenge >> 24), + ($challenge >> 16), + ($challenge >> 8), + ($challenge >> 0) + ); + } + + // Apply the challenge and return + return $this->challengeApply($challenge_result); + } + + /** + * Process the response + * + * @return array + */ + public function processResponse() + { + + // Holds the processed packets + $processed = []; + + // Iterate over the packets + foreach ($this->packets_response as $response) { + // Make a buffer + $buffer = new Buffer($response, Buffer::NUMBER_TYPE_BIGENDIAN); + + // Packet type = 0 + $buffer->readInt8(); + + // Session Id + $buffer->readInt32(); + + // We need to burn the splitnum\0 because it is not used + $buffer->skip(9); + + // Get the id + $id = $buffer->readInt8(); + + // Burn next byte not sure what it is used for + $buffer->skip(1); + + // Add this packet to the processed + $processed[$id] = $buffer->getBuffer(); + + unset($buffer, $id); + } + + // Sort packets, reset index + ksort($processed); + + // Offload cleaning up the packets if they happen to be split + $packets = $this->cleanPackets(array_values($processed)); + + // Split the packets by type general and the rest (i.e. players & teams) + $split = preg_split($this->packetSplit, implode('', $packets)); + + // Create a new result + $result = new Result(); + + // Assign variable due to pass by reference in PHP 7+ + $buffer = new Buffer($split[0], Buffer::NUMBER_TYPE_BIGENDIAN); + + // First key should be server details and rules + $this->processDetails($buffer, $result); + + // The rest should be the player and team information, if it exists + if (array_key_exists(1, $split)) { + $buffer = new Buffer($split[1], Buffer::NUMBER_TYPE_BIGENDIAN); + $this->processPlayersAndTeams($buffer, $result); + } + + unset($buffer); + + return $result->fetch(); } /* * Internal methods */ - protected function preProcess_all($packets) + + /** + * Handles cleaning up packets since the responses can be a bit "dirty" + * + * @param array $packets + * + * @return array + */ + protected function cleanPackets(array $packets = []) { - $return = array(); - // Get packet index, remove header - foreach ($packets as $index => $packet) - { - // Make new buffer - $buf = new GameQ_Buffer($packet); - - // Skip the header - $buf->skip(14); - - // Get the current packet and make a new index in the array - $return[$buf->readInt16()] = $buf->getBuffer(); - } - - unset($buf); - - // Sort packets, reset index - ksort($return); - - // Grab just the values - $return = array_values($return); + // Get the number of packets + $packetCount = count($packets); // Compare last var of current packet with first var of next packet // On a partial match, remove last var from current packet, // variable header from next packet - for ($i = 0, $x = count($return); $i < $x - 1; $i++) - { + for ($i = 0, $x = $packetCount; $i < $x - 1; $i++) { // First packet - $fst = substr($return[$i], 0, -1); - + $fst = substr($packets[$i], 0, -1); // Second packet - $snd = $return[$i+1]; - + $snd = $packets[$i + 1]; // Get last variable from first packet - $fstvar = substr($fst, strrpos($fst, "\x00")+1); - + $fstvar = substr($fst, strrpos($fst, "\x00") + 1); // Get first variable from last packet - $snd = substr($snd, strpos($snd, "\x00")+2); + $snd = substr($snd, strpos($snd, "\x00") + 2); $sndvar = substr($snd, 0, strpos($snd, "\x00")); - // Check if fstvar is a substring of sndvar // If so, remove it from the first string - if (strpos($sndvar, $fstvar) !== false) - { - $return[$i] = preg_replace("#(\\x00[^\\x00]+\\x00)$#", "\x00", $return[$i]); + if (!empty($fstvar) && strpos($sndvar, $fstvar) !== false) { + $packets[$i] = preg_replace("#(\\x00[^\\x00]+\\x00)$#", "\x00", $packets[$i]); } } // Now let's loop the return and remove any dupe prefixes - for($x = 1; $x < count($return); $x++) - { - $buf = new GameQ_Buffer($return[$x]); + for ($x = 1; $x < $packetCount; $x++) { + $buffer = new Buffer($packets[$x], Buffer::NUMBER_TYPE_BIGENDIAN); - $prefix = $buf->readString(); + $prefix = $buffer->readString(); - // Check to see if the return before has the same prefix present - if($prefix != null && strstr($return[($x-1)], $prefix)) - { - // Update the return by removing the prefix plus 2 chars - $return[$x] = substr(str_replace($prefix, '', $return[$x]), 2); - } + // Check to see if the return before has the same prefix present + if ($prefix != null && strstr($packets[($x - 1)], $prefix)) { + // Update the return by removing the prefix plus 2 chars + $packets[$x] = substr(str_replace($prefix, '', $packets[$x]), 2); + } - unset($buf); + unset($buffer); } unset($x, $i, $snd, $sndvar, $fst, $fstvar); - // Implode into a string and return - return implode("", $return); - } - - protected function process_all() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_ALL)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Parse the response - $data = $this->preProcess_all($this->packets_response[self::PACKET_ALL]); - - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // We go until we hit an empty key - while($buf->getLength()) - { - $key = $buf->readString(); - - if (strlen($key) == 0) - { - break; - } - - $result->add($key, $buf->readString()); - } - - // Now we need to offload to parse the remaining data, player and team information - $this->parsePlayerTeamInfo($buf, $result); - - // Return the result - return $result->fetch(); - } - - protected function delete_result(&$result, $array) - { - foreach($array as $key) - { - unset($result[$key]); - } - - return TRUE; - } - - protected function move_result(&$result, $old, $new) - { - if (isset($result[$old])) - { - $result[$new] = $result[$old]; - unset($result[$old]); - } - - return TRUE; + // Return cleaned packets + return $packets; } /** - * Parse the player and team information but do it smartly. Update to the old parseSub method. + * Handles processing the details data into a usable format * - * @param GameQ_Buffer $buf - * @param GameQ_Result $result + * @param \GameQ\Buffer $buffer + * @param \GameQ\Result $result */ - protected function parsePlayerTeamInfo(GameQ_Buffer &$buf, GameQ_Result &$result) + protected function processDetails(Buffer &$buffer, Result &$result) { - /* - * Explode the data into groups. First is player, next is team (item_t) - * - * Each group should be as follows: - * - * [0] => item_ - * [1] => information for item_ - * ... - */ - $data = explode("\x00\x00", $buf->getBuffer()); - // By default item_group is blank, this will be set for each loop thru the data - $item_group = ''; - - // By default the item_type is blank, this will be set on each loop - $item_type = ''; - - // Loop through all of the $data for information and pull it out into the result - for($x=0; $x < count($data)-1; $x++) - { - // Pull out the item - $item = $data[$x]; - - // If this is an empty item, move on - if($item == '' || $item == "\x00") - { - continue; - } - - /* - * Left as reference: - * - * Each block of player_ and team_t have preceeding junk chars - * - * player_ is actually \x01player_ - * team_t is actually \x00\x02team_t - * - * Probably a by-product of the change to exploding the data from the original. - * - * For now we just strip out these characters - */ - - // Check to see if $item has a _ at the end, this is player info - if(substr($item, -1) == '_') - { - // Set the item group - $item_group = 'players'; - - // Set the item type, rip off any trailing stuff and bad chars - $item_type = rtrim(str_replace("\x01", '', $item), '_'); - } - // Check to see if $item has a _t at the end, this is team info - elseif(substr($item, -2) == '_t') - { - // Set the item group - $item_group = 'teams'; - - // Set the item type, rip off any trailing stuff and bad chars - $item_type = rtrim(str_replace(array("\x00", "\x02"), '', $item), '_t'); - } - // We can assume it is data belonging to a previously defined item - else - { - // Make a temp buffer so we have easier access to the data - $buf_temp = new GameQ_Buffer($item); - - // Get the values - while ($buf_temp->getLength()) - { - // No value so break the loop, end of string - if (($val = $buf_temp->readString()) === '') - { - break; - } - - // Add the value to the proper item in the correct group - $result->addSub($item_group, $item_type, trim($val)); - } - - // Unset out buffer - unset($buf_temp); - } - } - - // Free up some memory - unset($data, $item, $item_group, $item_type, $val); - } - - /** - * Parse the player and team info - * - * @param GameQ_Buffer $buf - * @param GameQ_Result $result - * @throws GameQ_ProtocolsException - * @return boolean - */ - protected function parsePlayerTeamInfoNew(GameQ_Buffer &$buf, GameQ_Result &$result) - { - /** - * Player info is always first, team info (if defined) is second. - * - * Reference: - * - * Player info is preceeded by a hex code of \x01 - * Team info is preceeded by a hex code of \x02 - */ - - // Check the header to make sure the player data is proper - if($buf->read(1) != "\x01") - { - //throw new GameQ_ProtocolsException("First character in player buffer != '\x01'"); - return FALSE; - } - - // Offload the player parsing - $this->parseSubInfo('players', $buf->readString("\x00\x00\x00"), $result); - - // Check to make sure we have team information - if($buf->getLength() >= 6) - { - // Burn chars - $buf->skip(2); - - // Check the header to make sure the data is proper - if($buf->read(1) != "\x02") - { - //throw new GameQ_ProtocolsException("First character in team buffer != '\x02'"); - return FALSE; + // We go until we hit an empty key + while ($buffer->getLength()) { + $key = $buffer->readString(); + if (strlen($key) == 0) { + break; } - - // Offload the team parsing - $this->parseSubInfo('teams', $buf->readString("\x00\x00\x00"), $result); + $result->add($key, utf8_encode($buffer->readString())); } - - return TRUE; } /** - * Parse the sub-item information for players and teams + * Handles processing the player and team data into a usable format * - * @param string $section - * @param string $data - * @param GameQ_Result $result - * @return boolean + * @param \GameQ\Buffer $buffer + * @param \GameQ\Result $result */ - protected function parseSubInfo($section, $data, GameQ_Result &$result) + protected function processPlayersAndTeams(Buffer &$buffer, Result &$result) { + /* - * Explode the items so we can iterate easier - * - * Items should split up as follows: + * Explode the data into groups. First is player, next is team (item_t) + * Each group should be as follows: * * [0] => item_ - * [1] => data for item_ - * [2] => item2_ - * [3] => data for item2_ + * [1] => information for item_ * ... */ - $items = explode("\x00\x00", $data); + $data = explode("\x00\x00", $buffer->getBuffer()); - print_r($items); + // By default item_group is blank, this will be set for each loop thru the data + $item_group = ''; - // Loop through all of the items - for($x = 0; $x < count($items); $x += 2) - { - // $x is always the key for the item (i.e. player_, ping_, team_, score_, etc...) - $item_type = rtrim($items[$x], '_,_t'); + // By default the item_type is blank, this will be set on each loop + $item_type = ''; - // $x+1 is always the data for the above item - // Make a temp buffer so we have easier access to the data - $buf_temp = new GameQ_Buffer($items[$x+1]); + // Save count as variable + $count = count($data); - // Get the values - while ($buf_temp->getLength()) - { - // No value so break the loop, end of string - if (($val = $buf_temp->readString()) === '') - { - break; - } - - // Add the value to the proper item in the correct group - $result->addSub($section, $item_type, trim($val)); + // Loop through all of the $data for information and pull it out into the result + for ($x = 0; $x < $count - 1; $x++) { + // Pull out the item + $item = $data[$x]; + // If this is an empty item, move on + if ($item == '' || $item == "\x00") { + continue; } + /* + * Left as reference: + * + * Each block of player_ and team_t have preceding junk chars + * + * player_ is actually \x01player_ + * team_t is actually \x00\x02team_t + * + * Probably a by-product of the change to exploding the data from the original. + * + * For now we just strip out these characters + */ + // Check to see if $item has a _ at the end, this is player info + if (substr($item, -1) == '_') { + // Set the item group + $item_group = 'players'; + // Set the item type, rip off any trailing stuff and bad chars + $item_type = rtrim(str_replace("\x01", '', $item), '_'); + } elseif (substr($item, -2) == '_t') { + // Check to see if $item has a _t at the end, this is team info + // Set the item group + $item_group = 'teams'; + // Set the item type, rip off any trailing stuff and bad chars + $item_type = rtrim(str_replace(["\x00", "\x02"], '', $item), '_t'); + } else { + // We can assume it is data belonging to a previously defined item - // Unset out buffer - unset($buf_temp, $val); + // Make a temp buffer so we have easier access to the data + $buf_temp = new Buffer($item, Buffer::NUMBER_TYPE_BIGENDIAN); + // Get the values + while ($buf_temp->getLength()) { + // No value so break the loop, end of string + if (($val = $buf_temp->readString()) === '') { + break; + } + // Add the value to the proper item in the correct group + $result->addSub($item_group, $item_type, utf8_encode(trim($val))); + } + // Unset our buffer + unset($buf_temp); + } } - - unset($x, $items, $item_type); - - return TRUE; + // Free up some memory + unset($count, $data, $item, $item_group, $item_type, $val); } } diff --git a/third_party/gameq_v2/gameq/protocols/gamespy4.php b/third_party/gameq_v2/gameq/protocols/gamespy4.php index 838ecfb1..e28755f1 100644 --- a/third_party/gameq_v2/gameq/protocols/gamespy4.php +++ b/third_party/gameq_v2/gameq/protocols/gamespy4.php @@ -3,19 +3,21 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** * GameSpy4 Protocol Class * @@ -27,4 +29,6 @@ * * @author Austin Bischoff */ -class GameQ_Protocols_Gamespy4 extends GameQ_Protocols_Gamespy3 {} +class Gamespy4 extends Gamespy3 +{ +} diff --git a/third_party/gameq_v2/gameq/protocols/gmod.php b/third_party/gameq_v2/gameq/protocols/gmod.php index f732e9c0..65967247 100644 --- a/third_party/gameq_v2/gameq/protocols/gmod.php +++ b/third_party/gameq_v2/gameq/protocols/gmod.php @@ -3,26 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Garry's Mod Protocol Class + * Class Gmod * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_Gmod extends GameQ_Protocols_Source +class Gmod extends Source { - protected $name = "gmod"; - protected $name_long = "Garry's Mod"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'gmod'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Garry's Mod"; } diff --git a/third_party/gameq_v2/gameq/protocols/gore.php b/third_party/gameq_v2/gameq/protocols/gore.php deleted file mode 100644 index cecd0359..00000000 --- a/third_party/gameq_v2/gameq/protocols/gore.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Gore Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Gore extends GameQ_Protocols_Gamespy -{ - protected $name = "gore"; - protected $name_long = "Gore"; - - protected $port = 27778; -} diff --git a/third_party/gameq_v2/gameq/protocols/graw.php b/third_party/gameq_v2/gameq/protocols/graw.php deleted file mode 100644 index bfff2f0e..00000000 --- a/third_party/gameq_v2/gameq/protocols/graw.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Ghost Recon: Advanced Warfighter Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Graw extends GameQ_Protocols_Gamespy2 -{ - protected $name = "graw"; - protected $name_long = "Ghost Recon: Advanced Warfighter"; - - protected $port = 15250; -} diff --git a/third_party/gameq_v2/gameq/protocols/graw2.php b/third_party/gameq_v2/gameq/protocols/graw2.php deleted file mode 100644 index 662d4814..00000000 --- a/third_party/gameq_v2/gameq/protocols/graw2.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Ghost Recon: Advanced Warfighter 2 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Graw2 extends GameQ_Protocols_Gamespy2 -{ - protected $name = "graw2"; - protected $name_long = "Ghost Recon: Advanced Warfighter 2"; - - protected $port = 16250; -} diff --git a/third_party/gameq_v2/gameq/protocols/hl2dm.php b/third_party/gameq_v2/gameq/protocols/hl2dm.php index 0adec40b..15f881aa 100644 --- a/third_party/gameq_v2/gameq/protocols/hl2dm.php +++ b/third_party/gameq_v2/gameq/protocols/hl2dm.php @@ -3,26 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Half Life 2: Deathmatch Protocol Class + * Class Hl2dm * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_Hl2dm extends GameQ_Protocols_Source +class Hl2dm extends Source { - protected $name = "hl2dm"; - protected $name_long = "Half Life 2: Deathmatch"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'hl2dm'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Half Life 2: Deathmatch"; } diff --git a/third_party/gameq_v2/gameq/protocols/hldm.php b/third_party/gameq_v2/gameq/protocols/hldm.php deleted file mode 100644 index 7eb6d0aa..00000000 --- a/third_party/gameq_v2/gameq/protocols/hldm.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Half Life Deathmatch Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Hldm extends GameQ_Protocols_Source -{ - protected $name = "hldm"; - protected $name_long = "Half Life: Deathmatch"; -} diff --git a/third_party/gameq_v2/gameq/protocols/homefront.php b/third_party/gameq_v2/gameq/protocols/homefront.php deleted file mode 100644 index 7887d4ae..00000000 --- a/third_party/gameq_v2/gameq/protocols/homefront.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Homefront Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Homefront extends GameQ_Protocols_Source -{ - protected $name = "homefront"; - protected $name_long = "Homefront"; -} diff --git a/third_party/gameq_v2/gameq/protocols/http.php b/third_party/gameq_v2/gameq/protocols/http.php index 5a03983f..2a86d8d1 100644 --- a/third_party/gameq_v2/gameq/protocols/http.php +++ b/third_party/gameq_v2/gameq/protocols/http.php @@ -3,40 +3,65 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; + /** - * Http Protocol Class + * Class Http * - * Used for making actual http requests to servers for information + * Generic HTTP protocol class. Useful for making http based requests * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -abstract class GameQ_Protocols_Http extends GameQ_Protocols +abstract class Http extends Protocol { /** - * Set the transport to use TCP + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'http'; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'http'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Generic HTTP protocol"; + + /** + * Http protocol is TCP * * @var string */ protected $transport = self::TRANSPORT_TCP; /** - * Default port for this server type + * The client join link * - * @var int + * @type string */ - protected $port = 80; // Default port, used if not set when instanced - -} \ No newline at end of file + protected $join_link = null; +} diff --git a/third_party/gameq_v2/gameq/protocols/insurgency.php b/third_party/gameq_v2/gameq/protocols/insurgency.php index cf74ed67..77b8329e 100644 --- a/third_party/gameq_v2/gameq/protocols/insurgency.php +++ b/third_party/gameq_v2/gameq/protocols/insurgency.php @@ -3,26 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Insurgency Mod Protocol Class + * Class Insurgency * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_Insurgency extends GameQ_Protocols_Source +class Insurgency extends Source { - protected $name = "insurgency"; - protected $name_long = "Insurgency"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'insurgency'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Insurgency"; } diff --git a/third_party/gameq_v2/gameq/protocols/jc2.php b/third_party/gameq_v2/gameq/protocols/jc2.php deleted file mode 100644 index 4642ac40..00000000 --- a/third_party/gameq_v2/gameq/protocols/jc2.php +++ /dev/null @@ -1,60 +0,0 @@ -. - */ - -/** - * Just Cause 2 Multiplayer Protocol Class - * - * Special thanks to Woet for some insight on packing - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Jc2 extends GameQ_Protocols_Gamespy4 -{ - protected $name = "jc2"; - protected $name_long = "Just Cause 2 Multiplayer"; - - protected $port = 7777; - - public function __construct($ip = FALSE, $port = FALSE, $options = array()) - { - // Setup the parent first - parent::__construct($ip, $port, $options); - - // Tweak the packet used - $this->packets[self::PACKET_ALL] = "\xFE\xFD\x00\x10\x20\x30\x40%s\xFF\xFF\xFF\x02"; - } - - /** - * Override the parent, this protocol is returned differently - * - * @see GameQ_Protocols_Gamespy3::parsePlayerTeamInfo() - */ - protected function parsePlayerTeamInfo(GameQ_Buffer &$buf, GameQ_Result &$result) - { - // First is the number of players, let's use this. Should have actual players, not connecting - $result->add('numplayers', $buf->readInt16BE()); - - // Loop until we run out of data - while($buf->getLength()) - { - $result->addPlayer('name', $buf->readString()); - $result->addPlayer('steamid', $buf->readString()); - $result->addPlayer('ping', $buf->readInt16BE()); - } - } -} diff --git a/third_party/gameq_v2/gameq/protocols/killingfloor.php b/third_party/gameq_v2/gameq/protocols/killingfloor.php index 08336846..9cc19643 100644 --- a/third_party/gameq_v2/gameq/protocols/killingfloor.php +++ b/third_party/gameq_v2/gameq/protocols/killingfloor.php @@ -3,76 +3,94 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Buffer; +use GameQ\Result; + /** - * Killing floor Protocol Class + * Class Killing floor * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Killingfloor extends GameQ_Protocols_Unreal2 +class Killingfloor extends Unreal2 { - protected $name = "killingfloor"; - protected $name_long = "Killing Floor"; - protected $port = 7708; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'killing floor'; - /** - * Overloaded for Killing Floor servername issue, could be all unreal2 games though - * - * @see GameQ_Protocols_Unreal2::process_details() - */ - protected function process_details() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_DETAILS)) - { - return array(); - } + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Killing Floor"; - // Set the result to a new result instance - $result = new GameQ_Result(); + /** + * query_port = client_port + 1 + * + * @type int + */ + protected $port_diff = 1; - // Let's preprocess the rules - $data = $this->preProcess_details($this->packets_response[self::PACKET_DETAILS]); + /** + * The client join link + * + * @type string + */ + protected $join_link = "steam://connect/%s:%d/"; - // Create a buffer - $buf = new GameQ_Buffer($data); + /** + * Overload the default detail process since this version is different + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function processDetails(Buffer $buffer) + { - $result->add('serverid', $buf->readInt32()); // 0 - $result->add('serverip', $buf->readPascalString(1)); // empty - $result->add('gameport', $buf->readInt32()); - $result->add('queryport', $buf->readInt32()); // 0 + // Set the result to a new result instance + $result = new Result(); - // We burn the first char since it is not always correct with the hostname - $buf->skip(1); + $result->add('serverid', $buffer->readInt32()); // 0 + $result->add('serverip', $buffer->readPascalString(1)); // empty + $result->add('gameport', $buffer->readInt32()); + $result->add('queryport', $buffer->readInt32()); // 0 - // Read as a regular string since the length is incorrect (what we skipped earlier) - $result->add('servername', $buf->readString()); + // We burn the first char since it is not always correct with the hostname + $buffer->skip(1); + + // Read as a regular string since the length is incorrect (what we skipped earlier) + $result->add('servername', utf8_encode($buffer->readString())); // The rest is read as normal - $result->add('mapname', $buf->readPascalString(1)); - $result->add('gametype', $buf->readPascalString(1)); - $result->add('playercount', $buf->readInt32()); - $result->add('maxplayers', $buf->readInt32()); - $result->add('ping', $buf->readInt32()); // 0 + $result->add('mapname', utf8_encode($buffer->readPascalString(1))); + $result->add('gametype', $buffer->readPascalString(1)); + $result->add('numplayers', $buffer->readInt32()); + $result->add('maxplayers', $buffer->readInt32()); + $result->add('currentwave', $buffer->readInt32()); - // @todo: There is extra data after this point (~9 bytes), cant find any reference on what it is + unset($buffer); - unset($buf); - - // Return the result - return $result->fetch(); - } + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/l4d.php b/third_party/gameq_v2/gameq/protocols/l4d.php index e1370055..596452a7 100644 --- a/third_party/gameq_v2/gameq/protocols/l4d.php +++ b/third_party/gameq_v2/gameq/protocols/l4d.php @@ -3,26 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Left 4 Dead Protocol Class + * Class L4d * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_L4d extends GameQ_Protocols_Source +class L4d extends Source { - protected $name = "l4d"; - protected $name_long = "Left 4 Dead"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'l4d'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Left 4 Dead"; } diff --git a/third_party/gameq_v2/gameq/protocols/l4d2.php b/third_party/gameq_v2/gameq/protocols/l4d2.php index a7aebdcf..475514c9 100644 --- a/third_party/gameq_v2/gameq/protocols/l4d2.php +++ b/third_party/gameq_v2/gameq/protocols/l4d2.php @@ -3,26 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Left 4 Dead 2 Protocol Class + * Class L4d2 * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_L4d2 extends GameQ_Protocols_Source +class L4d2 extends Source { - protected $name = "l4d2"; - protected $name_long = "Left 4 Dead 2"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'l4d2'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Left 4 Dead 2"; } diff --git a/third_party/gameq_v2/gameq/protocols/m2mp.php b/third_party/gameq_v2/gameq/protocols/m2mp.php index 6b905959..a6076e3a 100644 --- a/third_party/gameq_v2/gameq/protocols/m2mp.php +++ b/third_party/gameq_v2/gameq/protocols/m2mp.php @@ -3,19 +3,26 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + /** * Mafia 2 Multiplayer Protocol Class * @@ -23,132 +30,190 @@ * * Query port = server port + 1 * - * Thanks to rststeam for example protocol information + * Handles processing Mafia 2 Multiplayer servers * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Wilson Jesus <> */ -class GameQ_Protocols_M2mp extends GameQ_Protocols +class M2mp extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_ALL => "M2MP", - ); - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_all", - ); - - /** - * Default port for this server type - * - * @var int - */ - protected $port = 27016; // Default port, used if not set when instanced - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'm2mp'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'm2mp'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Mafia 2 Multiplayer"; - - /* - * Internal methods - */ - - /** - * Pre-process the server details data that was returned. + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class * - * @param array $packets + * @type array */ - protected function preProcess($packets) + protected $packets = [ + self::PACKET_ALL => "M2MP", + ]; + + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "M2MP" => 'processStatus', + ]; + + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'm2mp'; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'm2mp'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Mafia 2 Multiplayer"; + + /** + * The client join link + * + * @type string + */ + protected $join_link = null; + + /** + * The difference between the client port and query port + * + * @type int + */ + protected $port_diff = 1; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'hostname' => 'servername', + 'gametype' => 'gamemode', + 'maxplayers' => 'max_players', + 'numplayers' => 'num_players', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'name', + ], + ]; + + /** + * Handle response from the server + * + * @return mixed + * @throws Exception + */ + public function processResponse() { - // Make buffer so we can check this out - $buf = new GameQ_Buffer(implode('', $packets)); + // Make a buffer + $buffer = new Buffer(implode('', $this->packets_response)); - // Grab the header - $header = $buf->read(4); + // Grab the header + $header = $buffer->read(4); - // Now lets verify the header - if($header != "M2MP") - { - throw new GameQ_ProtocolsException('Unable to match M2MP response header. Header: '. $header); - return FALSE; - } + // Header + // Figure out which packet response this is + if ($header != "M2MP") { + throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); + } - // Return the data with the header stripped, ready to go. - return $buf->getBuffer(); + return call_user_func_array([$this, $this->responses[$header]], [$buffer]); } /** - * Process the server details + * Process the status response * - * @throws GameQ_ProtocolsException + * @param Buffer $buffer + * + * @return array */ - protected function process_all() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_ALL)) - { - return array(); - } + protected function processStatus(Buffer $buffer) + { + // We need to split the data and offload + $results = $this->processServerInfo($buffer); - // Set the result to a new result instance - $result = new GameQ_Result(); + $results = array_merge_recursive( + $results, + $this->processPlayers($buffer) + ); - // Always dedicated - $result->add('dedicated', TRUE); + unset($buffer); - // Preprocess and make buffer - $buf = new GameQ_Buffer($this->preProcess($this->packets_response[self::PACKET_ALL])); + // Return results + return $results; + } - // Pull out the server information - // Note the length information is incorrect, we correct using offset options in pascal method - $result->add('servername', $buf->readPascalString(1, TRUE)); - $result->add('num_players', $buf->readPascalString(1, TRUE)); - $result->add('max_players', $buf->readPascalString(1, TRUE)); - $result->add('gamemode', $buf->readPascalString(1, TRUE)); - $result->add('password', (bool) $buf->readInt8()); + /** + * Handle processing the server information + * + * @param Buffer $buffer + * + * @return array + */ + protected function processServerInfo(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); - // Read the player info, it's in the same query response for some odd reason. - while($buf->getLength()) - { - // Check to see if we ran out of info - if($buf->getLength() <= 1) - { - break; - } + // Always dedicated + $result->add('dedicated', 1); - // Only player information is available - $result->addPlayer('name', $buf->readPascalString(1, TRUE)); - } + // Pull out the server information + // Note the length information is incorrect, we correct using offset options in pascal method + $result->add('servername', $buffer->readPascalString(1, true)); + $result->add('num_players', $buffer->readPascalString(1, true)); + $result->add('max_players', $buffer->readPascalString(1, true)); + $result->add('gamemode', $buffer->readPascalString(1, true)); + $result->add('password', (bool) $buffer->readInt8()); - unset($buf); + unset($buffer); return $result->fetch(); - } + } + + /** + * Handle processing of player data + * + * @param Buffer $buffer + * + * @return array + */ + protected function processPlayers(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); + + // Parse players + // Read the player info, it's in the same query response for some odd reason. + while ($buffer->getLength()) { + // Check to see if we ran out of info, length bug from response + if ($buffer->getLength() <= 1) { + break; + } + + // Only player name information is available + // Add player name, encoded + $result->addPlayer('name', utf8_encode(trim($buffer->readPascalString(1, true)))); + } + + // Clear + unset($buffer); + + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/minecraft.php b/third_party/gameq_v2/gameq/protocols/minecraft.php index 39cf7e5e..a895cb87 100644 --- a/third_party/gameq_v2/gameq/protocols/minecraft.php +++ b/third_party/gameq_v2/gameq/protocols/minecraft.php @@ -3,21 +3,23 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Mincraft Protocol Class + * Minecraft Protocol Class * * Thanks to https://github.com/xPaw/PHP-Minecraft-Query for helping me realize this is * Gamespy 3 Protocol. Make sure you enable the items below for it to work. @@ -29,15 +31,57 @@ * * Look for those settings in server.properties: * - * enable-query=true - * query.port=25565 + * enable-query=true + * query.port=25565 * - * @author Austin Bischoff + * @package GameQ\Protocols + * + * @author Austin Bischoff */ -class GameQ_Protocols_Minecraft extends GameQ_Protocols_Gamespy4 +class Minecraft extends Gamespy3 { - protected $name = "minecraft"; - protected $name_long = "Minecraft"; - protected $port = 25565; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'minecraft'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Minecraft"; + + /** + * The client join link + * + * @type string + */ + protected $join_link = "minecraft://%s:%d/"; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'gametype' => 'game_id', + 'hostname' => 'hostname', + 'mapname' => 'map', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'player', + ], + ]; } diff --git a/third_party/gameq_v2/gameq/protocols/minequery.php b/third_party/gameq_v2/gameq/protocols/minequery.php deleted file mode 100644 index 88d6a9b1..00000000 --- a/third_party/gameq_v2/gameq/protocols/minequery.php +++ /dev/null @@ -1,133 +0,0 @@ -. - */ - -/** - * Minequery Protocol Class - * - * This class is used as the basis for all game servers - * that use the Minequery protocol for querying - * server status. - * - * Make sure you have Minequery running. Check the GameQ github wiki for specifics. - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Minequery extends GameQ_Protocols -{ - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "QUERY_JSON\n", - ); - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); - - /** - * Set the transport to use TCP - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * Default port for this server type - * - * @var int - */ - protected $port = 25566; // Default port, used if not set when instanced - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'minequery'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'minequery'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Minequery"; - - /* - * Internal methods - */ - - /** - * Process the server status - * - * @throws GameQ_ProtocolsException - */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - - // The response should be a single string so just combine all the packets into a single string - $response = implode('', $this->packets_response[self::PACKET_STATUS]); - - // Check to see if this is valid JSON. - if(($data = json_decode($response)) === NULL) - { - throw new GameQ_ProtocolsException('Unable to decode the JSON data for Minequery'); - return FALSE; - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Server is always dedicated - $result->add('dedicated', TRUE); - - // Add the address and port info - $result->add('serverport', $data->serverPort); - - $result->add('numplayers', $data->playerCount); - $result->add('maxplayers', $data->maxPlayers); - - // Do the players - foreach($data->playerList AS $i => $name) - { - $result->addPlayer('name', $name); - } - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v2/gameq/protocols/mohaa.php b/third_party/gameq_v2/gameq/protocols/mohaa.php index b4e47f39..66ddd7e7 100644 --- a/third_party/gameq_v2/gameq/protocols/mohaa.php +++ b/third_party/gameq_v2/gameq/protocols/mohaa.php @@ -3,28 +3,77 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Medal of Honor: Allied Assault Protocol Class - * - * @author Marcel Bößendörfer - */ -class GameQ_Protocols_Mohaa extends GameQ_Protocols_Gamespy -{ - protected $name = "mohaa"; - protected $name_long = "Medal of Honor: Allied Assault"; +namespace GameQ\Protocols; - protected $port = 12300; +/** + * Medal of honor: Allied Assault Protocol Class + * + * @package GameQ\Protocols + * @author Bram + * @author Austin Bischoff + */ +class Mohaa extends Gamespy +{ + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'mohaa'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Medal of honor: Allied Assault"; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'gametype' => 'gametype', + 'hostname' => 'hostname', + 'mapname' => 'mapname', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'player', + 'score' => 'frags', + 'ping' => 'ping', + ], + ]; + + /** + * Query port is always the client port + 97 in MOHAA + * + * @param int $clientPort + * + * @return int + */ + public function findQueryPort($clientPort) + { + return $clientPort + 97; + } } diff --git a/third_party/gameq_v2/gameq/protocols/mohsh.php b/third_party/gameq_v2/gameq/protocols/mohsh.php deleted file mode 100644 index ba3234f9..00000000 --- a/third_party/gameq_v2/gameq/protocols/mohsh.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Medal of Honor: Spearhead Protocol Class - * - * @author Marcel Bößendörfer - */ -class GameQ_Protocols_Mohsh extends GameQ_Protocols_Gamespy -{ - protected $name = "mohsh"; - protected $name_long = "Medal of Honor: Spearhead"; - - protected $port = 12300; -} diff --git a/third_party/gameq_v2/gameq/protocols/mohwf.php b/third_party/gameq_v2/gameq/protocols/mohwf.php deleted file mode 100644 index c9f2846f..00000000 --- a/third_party/gameq_v2/gameq/protocols/mohwf.php +++ /dev/null @@ -1,131 +0,0 @@ -. - */ - -/** - * Medal of Honor Warfighter Protocol Class - * - * MOHWF is the same as BF3 minus some quirks in the status query hence the extension - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Mohwf extends GameQ_Protocols_Bf3 -{ - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'mohwf'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'mohwf'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Medal of Honor Warfighter"; - - /* - * Internal Methods - */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - - // Make buffer for data - $buf = new GameQ_Buffer($this->preProcess_status($this->packets_response[self::PACKET_STATUS])); - - $buf->skip(8); /* skip header */ - - // Decode the words into an array so we can use this data - $words = $this->decodeWords($buf); - - // Make sure we got OK - if (!isset ($words[0]) || $words[0] != 'OK') - { - throw new GameQ_ProtocolsException('Packet Response was not OK! Buffer:'.$buf->getBuffer()); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Server is always dedicated - $result->add('dedicated', TRUE); - - // No mods, as of yet - $result->add('mod', FALSE); - - // These are the same no matter what mode the server is in - $result->add('hostname', $words[1]); - $result->add('numplayers', $words[2]); - $result->add('maxplayers', $words[3]); - $result->add('gametype', $words[4]); - $result->add('map', $words[5]); - - $result->add('roundsplayed', $words[6]); - $result->add('roundstotal', $words[7]); - - // Figure out the number of teams - $num_teams = intval($words[8]); - - // Set the current index - $index_current = 9; - - // Loop for the number of teams found, increment along the way - for($id=1; $id<=$num_teams; $id++) - { - $result->addSub('teams', 'tickets', $words[$index_current]); - $result->addSub('teams', 'id', $id); - - // Increment - $index_current++; - } - - // Get and set the rest of the data points. - $result->add('targetscore', $words[$index_current]); - $result->add('online', TRUE); // Forced TRUE, it seems $words[$index_current + 1] is always empty - $result->add('ranked', $words[$index_current + 2] === 'true'); - $result->add('punkbuster', $words[$index_current + 3] === 'true'); - $result->add('password', $words[$index_current + 4] === 'true'); - $result->add('uptime', $words[$index_current + 5]); - $result->add('roundtime', $words[$index_current + 6]); - - // The next 3 are empty in MOHWF, kept incase they start to work some day - $result->add('ip_port', $words[$index_current + 7]); - $result->add('punkbuster_version', $words[$index_current + 8]); - $result->add('join_queue', $words[$index_current + 9] === 'true'); - - $result->add('region', $words[$index_current + 10]); - $result->add('pingsite', $words[$index_current + 11]); - $result->add('country', $words[$index_current + 12]); - - unset($buf, $words); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v2/gameq/protocols/mta.php b/third_party/gameq_v2/gameq/protocols/mta.php index 4d276520..b95dc4c8 100644 --- a/third_party/gameq_v2/gameq/protocols/mta.php +++ b/third_party/gameq_v2/gameq/protocols/mta.php @@ -3,28 +3,57 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Multi Theft Auto Protocol Class - * - * @author Marcel Bößendörfer - */ -class GameQ_Protocols_Mta extends GameQ_Protocols_ASE -{ - protected $name = "mta"; - protected $name_long = "Multi Theft Auto"; +namespace GameQ\Protocols; - protected $port = 22126; +/** + * Class Multi Theft Auto + * + * @package GameQ\Protocols + * + * @author Marcel Bößendörfer + * @author Austin Bischoff + */ +class Mta extends Ase +{ + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'mta'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Multi Theft Auto"; + + /** + * query_port = client_port + 123 + * + * @type int + */ + protected $port_diff = 123; + + /** + * The client join link + * + * @type string + */ + protected $join_link = "mtasa://%s:%d/"; } diff --git a/third_party/gameq_v2/gameq/protocols/mumble.php b/third_party/gameq_v2/gameq/protocols/mumble.php index eb018213..299389cf 100644 --- a/third_party/gameq_v2/gameq/protocols/mumble.php +++ b/third_party/gameq_v2/gameq/protocols/mumble.php @@ -3,193 +3,192 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + /** - * Mumble Protocol Class + * Mumble Protocol class * * References: * https://github.com/edmundask/MurmurQuery - Thanks to skylord123 * * @author Austin Bischoff */ -class GameQ_Protocols_Mumble extends GameQ_Protocols +class Mumble extends Protocol { + /** - * Normalization for this protocol class + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class * - * @var array + * @type array */ - protected $normalize = array( - // General - 'general' => array( - 'dedicated' => array('dedicated'), - 'numplayers' => array(), - 'maxplayers' => array('xgtmurmurmaxusers'), - 'joinlink' => array('xconnecturl'), - 'players' => array('players'), - 'teams' => array('teams'), - ), + protected $packets = [ + self::PACKET_ALL => "\x6A\x73\x6F\x6E", // JSON packet + ]; - // Player - 'player' => array( - 'ping' => array('tcpPing'), - 'team' => array('channel'), - ), - ); + /** + * The transport mode for this protocol is TCP + * + * @type string + */ + protected $transport = self::TRANSPORT_TCP; - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_ALL => "\x6A\x73\x6F\x6E", // JSON packet - ); + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'mumble'; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_all", - ); + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'mumble'; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 27800; // Default port, used if not set when instanced + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Mumble Server"; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'mumble'; + /** + * The client join link + * + * @type string + */ + protected $join_link = "mumble://%s:%d/"; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'mumble'; + /** + * 27800 = 64738 - 36938 + * + * @type int + */ + protected $port_diff = -36938; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Mumble"; + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + 'dedicated' => 'dedicated', + 'gametype' => 'gametype', + 'hostname' => 'name', + 'numplayers' => 'numplayers', + 'maxplayers' => 'x_gtmurmur_max_users', + ], + // Player + 'player' => [ + 'name' => 'name', + 'ping' => 'tcpPing', + 'team' => 'channel', + 'time' => 'onlinesecs', + ], + // Team + 'team' => [ + 'name' => 'name', + ], + ]; - /** - * Transport protocol - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { - /* + // Try to json_decode, make it into an array + if (($data = json_decode(implode('', $this->packets_response), true)) === null) { + throw new Exception(__METHOD__ . " Unable to decode JSON data."); + } + + // Set the result to a new result instance + $result = new Result(); + + // Always dedicated + $result->add('dedicated', 1); + + // Let's iterate over the response items, there are a lot + foreach ($data as $key => $value) { + // Ignore root for now, that is where all of the channel/player info is housed + if (in_array($key, ['root'])) { + continue; + } + + // Add them as is + $result->add($key, $value); + } + + // Offload the channel and user parsing + $this->processChannelsAndUsers($data['root'], $result); + + unset($data); + + // Manually set the number of players + $result->add('numplayers', count($result->get('players'))); + + return $result->fetch(); + } + + /* * Internal methods */ - public function preProcess_all($packets=array()) - { - return implode('', $packets); - } + /** + * Handles processing the the channels and user info + * + * @param array $data + * @param \GameQ\Result $result + */ + protected function processChannelsAndUsers(array $data, Result &$result) + { - protected function process_all() - { - if(!$this->hasValidResponse(self::PACKET_ALL)) - { - return array(); - } + // Let's add all of the channel information + foreach ($data as $key => $value) { + // We will handle these later + if (in_array($key, ['channels', 'users'])) { + // skip + continue; + } - // Let's preprocess the status, JSON is the response - $json = $this->preProcess_all($this->packets_response[self::PACKET_ALL]); + // Add the channel property as a team + $result->addTeam($key, $value); + } - // Try to json_decode, make it into an array - if(($data = json_decode($json, TRUE)) === NULL) - { - throw new GameQ_ProtocolsException("Unable to decode JSON data."); - } + // Itereate over the users in this channel + foreach ($data['users'] as $user) { + foreach ($user as $key => $value) { + $result->addPlayer($key, $value); + } + } - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Always dedicated - $result->add('dedicated', TRUE); - - $result->add('maxplayers', 0); - - // Let's iterate over the response items, there are alot - foreach($data AS $key => $value) - { - // Ignore root for now, that is where all of the channel/player info is housed - if(in_array($key, array('root'))) - { - continue; - } - - // Add them as is - $result->add($key, $value); - } - - // Now let's parse the channel/user info - $this->process_channels_users($result, $data['root']); - - return $result->fetch(); - } - - /** - * Process the channel and user information - * - * @param GameQ_Result $result - * @param array $item - */ - protected function process_channels_users(GameQ_Result &$result, $item) - { - // Let's add all of the channel information - foreach($item AS $key => $value) - { - // We will handle these later - if(in_array($key, array('channels', 'users'))) - { - // skip - continue; - } - - // Add the channel property as a team - $result->addTeam($key, $value); - } - - // Itereate over the users in this channel - foreach($item['users'] AS $user) - { - foreach($user AS $key => $value) - { - $result->addPlayer($key, $value); - } - } - - // Offload more channels to parse - foreach($item['channels'] AS $channel) - { - $this->process_channels_users($result, $channel); - } - } + // Offload more channels to parse + foreach ($data['channels'] as $channel) { + $this->processChannelsAndUsers($channel, $result); + } + } } diff --git a/third_party/gameq_v2/gameq/protocols/nmrih.php b/third_party/gameq_v2/gameq/protocols/nmrih.php index df88d8f1..acae3b6e 100644 --- a/third_party/gameq_v2/gameq/protocols/nmrih.php +++ b/third_party/gameq_v2/gameq/protocols/nmrih.php @@ -3,27 +3,41 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Counter-Strike: Source Protocol Class + * Class No More Room in Hell * + * @package GameQ\Protocols * @author Austin Bischoff + * @author Jesse Lukas */ -class GameQ_Protocols_Nmrih extends GameQ_Protocols_Source +class Nmrih extends Source { - protected $name = "nmrih"; + /** + * No More Room in Hell protocol class + * + * @type string + */ + protected $name = 'nmrih'; + + /** + * Longer string name of this protocol class + * + * @type string + */ protected $name_long = "No More Room in Hell"; } - diff --git a/third_party/gameq_v2/gameq/protocols/ns.php b/third_party/gameq_v2/gameq/protocols/ns.php deleted file mode 100644 index 2b246f36..00000000 --- a/third_party/gameq_v2/gameq/protocols/ns.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Natural Selection Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Ns extends GameQ_Protocols_Source -{ - protected $name = "ns"; - protected $name_long = "Natural Selection"; -} diff --git a/third_party/gameq_v2/gameq/protocols/ns2.php b/third_party/gameq_v2/gameq/protocols/ns2.php index f57f5cc0..4c323929 100644 --- a/third_party/gameq_v2/gameq/protocols/ns2.php +++ b/third_party/gameq_v2/gameq/protocols/ns2.php @@ -3,35 +3,47 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Natural Selection 2 Protocol Class - * - * Note that the query port is the server connect port + 1 + * Class Ns2 * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_Ns2 extends GameQ_Protocols_Source +class Ns2 extends Source { - protected $name = "ns2"; - protected $name_long = "Natural Selection 2"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'ns2'; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 27016; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Natural Selection 2"; + + /** + * query_port = client_port + 1 + * + * @type int + */ + protected $port_diff = 1; } diff --git a/third_party/gameq_v2/gameq/protocols/projectcars.php b/third_party/gameq_v2/gameq/protocols/projectcars.php deleted file mode 100644 index 03a581ff..00000000 --- a/third_party/gameq_v2/gameq/protocols/projectcars.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Half Life 2: Deathmatch Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_ProjectCars extends GameQ_Protocols_Source -{ - protected $name = "projectcars"; - protected $name_long = "Project Cars"; -} diff --git a/third_party/gameq_v2/gameq/protocols/quake2.php b/third_party/gameq_v2/gameq/protocols/quake2.php index 8d2f25e3..f0366c2c 100644 --- a/third_party/gameq_v2/gameq/protocols/quake2.php +++ b/third_party/gameq_v2/gameq/protocols/quake2.php @@ -1,205 +1,219 @@ . - */ + + +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; /** - * Quake 2 Protocol Class + * Quake2 Protocol Class * - * This class is used as the basis for all game servers - * that use the Quake 2 protocol for querying - * server status. + * Handles processing Quake 3 servers * - * @author Austin Bischoff + * @package GameQ\Protocols */ -class GameQ_Protocols_Quake2 extends GameQ_Protocols +class Quake2 extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "\xFF\xFF\xFF\xFFstatus\x00", - ); - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); - - /** - * Default port for this server type - * - * @var int - */ - protected $port = 27910; // Default port, used if not set when instanced - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'quake2'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'quake2'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Quake 2"; - - /* - * Internal methods + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array */ + protected $packets = [ + self::PACKET_STATUS => "\xFF\xFF\xFF\xFFstatus\x00", + ]; - protected function preProcess_status($packets) + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\xFF\xFF\xFF\xFF\x70\x72\x69\x6e\x74" => 'processStatus', + ]; + + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'quake2'; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'quake2'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Quake 2 Server"; + + /** + * The client join link + * + * @type string + */ + protected $join_link = null; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'gametype' => 'gamename', + 'hostname' => 'hostname', + 'mapname' => 'mapname', + 'maxplayers' => 'maxclients', + 'mod' => 'g_gametype', + 'numplayers' => 'clients', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'ping' => 'ping', + 'score' => 'frags', + ], + ]; + + /** + * Handle response from the server + * + * @return mixed + * @throws Exception + */ + public function processResponse() { - // Should only be one packet - if (count($packets) > 1) - { - throw new GameQ_ProtocolsException('Quake 2 status has more than 1 packet'); - } + // Make a buffer + $buffer = new Buffer(implode('', $this->packets_response)); - // Make buffer so we can check this out - $buf = new GameQ_Buffer($packets[0]); + // Grab the header + $header = $buffer->readString("\x0A"); - // Grab the header - $header = $buf->read(11); + // Figure out which packet response this is + if (empty($header) || !array_key_exists($header, $this->responses)) { + throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); + } - // Now lets verify the header - if($header != "\xFF\xFF\xFF\xFFprint\x0a\\") - { - throw new GameQ_ProtocolsException('Unable to match Gamespy 2 status response header. Header: '. $header); - return FALSE; - } - - // Return the data with the header stripped, ready to go. - return $buf->getBuffer(); + return call_user_func_array([$this, $this->responses[$header]], [$buffer]); } /** - * Process the server status + * Process the status response * - * @throws GameQ_ProtocolsException + * @param Buffer $buffer + * + * @return array */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } + protected function processStatus(Buffer $buffer) + { + // We need to split the data and offload + $results = $this->processServerInfo(new Buffer($buffer->readString("\x0A"))); - // Set the result to a new result instance - $result = new GameQ_Result(); + $results = array_merge_recursive( + $results, + $this->processPlayers(new Buffer($buffer->getBuffer())) + ); - // Lets pre process and make sure these things are in the proper order by id - $data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]); + unset($buffer); - // Make buffer - $buf = new GameQ_Buffer($data); + // Return results + return $results; + } - // First section is the server info, the rest is player info - $server_info = $buf->readString("\x0A"); - $player_info = $buf->getBuffer(); + /** + * Handle processing the server information + * + * @param Buffer $buffer + * + * @return array + */ + protected function processServerInfo(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); - unset($buf); + // Burn leading \ if one exists + $buffer->readString('\\'); - // Make a new buffer for the server info - $buf_server = new GameQ_Buffer($server_info); + // Key / value pairs + while ($buffer->getLength()) { + // Add result + $result->add( + trim($buffer->readString('\\')), + utf8_encode(trim($buffer->readStringMulti(['\\', "\x0a"]))) + ); + } - // Key / value pairs - while ($buf_server->getLength()) - { - $result->add( - $buf_server->readString('\\'), - $buf_server->readStringMulti(array('\\', "\x0a"), $delimfound) - ); + $result->add('password', 0); + $result->add('mod', 0); - if ($delimfound === "\x0a") - { - break; - } - } + unset($buffer); - // Now send the rest to players - $this->parsePlayers($result, $player_info); - - // Free some memory - unset($sections, $player_info, $server_info, $delimfound, $buf_server, $data); - - // Return the result return $result->fetch(); - } + } - /** - * Parse the players and add them to the return. - * - * This is overloadable because it seems that different games return differen info. - * - * @param GameQ_Result $result - * @param string $players_info - */ - protected function parsePlayers(GameQ_Result &$result, $players_info) - { - // Explode the arrays out - $players = explode("\x0A", $players_info); + /** + * Handle processing of player data + * + * @param Buffer $buffer + * + * @return array + */ + protected function processPlayers(Buffer $buffer) + { + // Some games do not have a number of current players + $playerCount = 0; - // Remove the last array item as it is junk - array_pop($players); + // Set the result to a new result instance + $result = new Result(); - // Add total number of players - $result->add('num_players', count($players)); + // Loop until we are out of data + while ($buffer->getLength()) { + // Make a new buffer with this block + $playerInfo = new Buffer($buffer->readString("\x0A")); - // Loop the players - foreach($players AS $player_info) - { - $buf = new GameQ_Buffer($player_info); + // Add player info + $result->addPlayer('frags', $playerInfo->readString("\x20")); + $result->addPlayer('ping', $playerInfo->readString("\x20")); - // Add player info - $result->addPlayer('frags', $buf->readString("\x20")); - $result->addPlayer('ping', $buf->readString("\x20")); + // Skip first " + $playerInfo->skip(1); - // Skip first " - $buf->skip(1); + // Add player name, encoded + $result->addPlayer('name', utf8_encode(trim(($playerInfo->readString('"'))))); - // Add player name - $result->addPlayer('name', trim($buf->readString('"'))); + // Skip first " + $playerInfo->skip(2); - // Skip first " - $buf->skip(2); + // Add address + $result->addPlayer('address', trim($playerInfo->readString('"'))); - // Add address - $result->addPlayer('address', trim($buf->readString('"'))); - } + // Increment + $playerCount++; - // Free some memory - unset($buf, $players, $player_info); - } + // Clear + unset($playerInfo); + } + + $result->add('clients', $playerCount); + + // Clear + unset($buffer, $playerCount); + + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/quake3.php b/third_party/gameq_v2/gameq/protocols/quake3.php index c2f40326..6269b927 100644 --- a/third_party/gameq_v2/gameq/protocols/quake3.php +++ b/third_party/gameq_v2/gameq/protocols/quake3.php @@ -1,200 +1,214 @@ . - */ + + +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; /** - * Quake 3 Protocol Class + * Quake3 Protocol Class * - * This class is used as the basis for all game servers - * that use the Quake 3 protocol for querying - * server status. + * Handles processing Quake 3 servers * - * @author Austin Bischoff + * @package GameQ\Protocols */ -class GameQ_Protocols_Quake3 extends GameQ_Protocols +class Quake3 extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "\xFF\xFF\xFF\xFF\x67\x65\x74\x73\x74\x61\x74\x75\x73\x0A", - //self::PACKET_DETAILS => "\xFF\xFF\xFF\xFFgetinfo\x00", - ); - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); - - /** - * Default port for this server type - * - * @var int - */ - protected $port = 27960; // Default port, used if not set when instanced - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'quake3'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'quake3'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Quake 3"; - - /* - * Internal methods + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array */ + protected $packets = [ + self::PACKET_STATUS => "\xFF\xFF\xFF\xFF\x67\x65\x74\x73\x74\x61\x74\x75\x73\x0A", + ]; - protected function preProcess_status($packets) + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\xFF\xFF\xFF\xFFstatusResponse" => 'processStatus', + ]; + + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'quake3'; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'quake3'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Quake 3 Server"; + + /** + * The client join link + * + * @type string + */ + protected $join_link = null; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'gametype' => 'gamename', + 'hostname' => 'sv_hostname', + 'mapname' => 'mapname', + 'maxplayers' => 'sv_maxclients', + 'mod' => 'g_gametype', + 'numplayers' => 'clients', + 'password' => ['g_needpass', 'pswrd'], + ], + // Individual + 'player' => [ + 'name' => 'name', + 'ping' => 'ping', + 'score' => 'frags', + ], + ]; + + /** + * Handle response from the server + * + * @return mixed + * @throws Exception + */ + public function processResponse() { - // Should only be one packet - if (count($packets) > 1) - { - throw new GameQ_ProtocolsException('Quake 3 status has more than 1 packet'); - } + // Make a buffer + $buffer = new Buffer(implode('', $this->packets_response)); - // Make buffer so we can check this out - $buf = new GameQ_Buffer($packets[0]); + // Grab the header + $header = $buffer->readString("\x0A"); - // Grab the header - $header = $buf->read(20); + // Figure out which packet response this is + if (empty($header) || !array_key_exists($header, $this->responses)) { + throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); + } - // Now lets verify the header - if($header != "\xFF\xFF\xFF\xFFstatusResponse\x0A\x5C") - { - throw new GameQ_ProtocolsException('Unable to match Gamespy 3 challenge response header. Header: '. $header); - return FALSE; - } + return call_user_func_array([$this, $this->responses[$header]], [$buffer]); + } - // Return the data with the header stripped, ready to go. - return $buf->getBuffer(); + protected function processStatus(Buffer $buffer) + { + // We need to split the data and offload + $results = $this->processServerInfo(new Buffer($buffer->readString("\x0A"))); + + $results = array_merge_recursive( + $results, + $this->processPlayers(new Buffer($buffer->getBuffer())) + ); + + unset($buffer); + + // Return results + return $results; } /** - * Process the server status + * Handle processing the server information * - * @throws GameQ_ProtocolsException + * @param Buffer $buffer + * + * @return array */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } + protected function processServerInfo(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Burn leading \ if one exists + $buffer->readString('\\'); - // Lets pre process and make sure these things are in the proper order by id - $data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]); + // Key / value pairs + while ($buffer->getLength()) { + // Add result + $result->add( + trim($buffer->readString('\\')), + utf8_encode(trim($buffer->readStringMulti(['\\', "\x0a"]))) + ); + } - // Make buffer - $buf = new GameQ_Buffer($data); + unset($buffer); - // First section is the server info, the rest is player info - $server_info = $buf->readString("\x0A"); - $player_info = $buf->getBuffer(); - - unset($buf); - - // Make a new buffer for the server info - $buf_server = new GameQ_Buffer($server_info); - - // Key / value pairs - while ($buf_server->getLength()) - { - $result->add( - $buf_server->readString('\\'), - $buf_server->readStringMulti(array('\\', "\x0a"), $delimfound) - ); - - if ($delimfound === "\x0a") - { - break; - } - } - - // Now send the rest to players - $this->parsePlayers($result, $player_info); - - // Free some memory - unset($sections, $player_info, $server_info, $delimfound, $buf_server, $data); - - // Return the result return $result->fetch(); - } + } - /** - * Parse the players and add them to the return. - * - * This is overloadable because it seems that different games return differen info. - * - * @param GameQ_Result $result - * @param string $players_info - */ - protected function parsePlayers(GameQ_Result &$result, $players_info) - { - // Explode the arrays out - $players = explode("\x0A", $players_info); + /** + * Handle processing of player data + * + * @param Buffer $buffer + * + * @return array + * @throws Exception + */ + protected function processPlayers(Buffer $buffer) + { + // Some games do not have a number of current players + $playerCount = 0; - // Remove the last array item as it is junk - array_pop($players); + // Set the result to a new result instance + $result = new Result(); - // Add total number of players - $result->add('num_players', count($players)); + // Loop until we are out of data + while ($buffer->getLength()) { + // Add player info + $result->addPlayer('frags', $buffer->readString("\x20")); + $result->addPlayer('ping', $buffer->readString("\x20")); - // Loop the players - foreach($players AS $player_info) - { - $buf = new GameQ_Buffer($player_info); + // Look ahead to see if we have a name or team + $checkTeam = $buffer->lookAhead(1); - // Add player info - $result->addPlayer('frags', $buf->readString("\x20")); - $result->addPlayer('ping', $buf->readString("\x20")); + // We have team info + if ($checkTeam != '' and $checkTeam != '"') { + $result->addPlayer('team', $buffer->readString("\x20")); + } - // Skip first " - $buf->skip(1); + // Check to make sure we have player name + $checkPlayerName = $buffer->read(); - // Add player name - $result->addPlayer('name', trim($buf->readString('"'))); - } + // Bad response + if ($checkPlayerName !== '"') { + throw new Exception('Expected " but got ' . $checkPlayerName . ' for beginning of player name string!'); + } - // Free some memory - unset($buf, $players, $player_info); - } + // Add player name, encoded + $result->addPlayer('name', utf8_encode(trim($buffer->readString('"')))); + + // Burn ending delimiter + $buffer->read(); + + // Increment + $playerCount++; + } + + $result->add('clients', $playerCount); + + // Clear + unset($buffer, $playerCount); + + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/quake4.php b/third_party/gameq_v2/gameq/protocols/quake4.php index 12b61669..6a5f5c7e 100644 --- a/third_party/gameq_v2/gameq/protocols/quake4.php +++ b/third_party/gameq_v2/gameq/protocols/quake4.php @@ -3,42 +3,82 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Buffer; +use GameQ\Result; + /** * Quake 4 Protocol Class * - * @author Austin Bischoff + * @package GameQ\Protocols + * + * @author Wilson Jesus <> */ -class GameQ_Protocols_Quake4 extends GameQ_Protocols_Doom3 +class Quake4 extends Doom3 { - protected $name = "quake4"; - protected $name_long = "Quake 4"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'quake4'; - protected $port = 28004; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Quake 4"; - protected function parsePlayers(GameQ_Buffer &$buf, GameQ_Result &$result) - { - while (($id = $buf->readInt8()) != 32) - { - $result->addPlayer('id', $id); - $result->addPlayer('ping', $buf->readInt16()); - $result->addPlayer('rate', $buf->readInt32()); - $result->addPlayer('name', $buf->readString()); - $result->addPlayer('clantag', $buf->readString()); - } + /** + * Handle processing of player data + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function processPlayers(Buffer $buffer) + { + // Some games do not have a number of current players + $playerCount = 0; - return true; - } + // Set the result to a new result instance + $result = new Result(); + + // Parse players + // Loop thru the buffer until we run out of data + while (($id = $buffer->readInt8()) != 32) { + // Add player info results + $result->addPlayer('id', $id); + $result->addPlayer('ping', $buffer->readInt16()); + $result->addPlayer('rate', $buffer->readInt32()); + // Add player name, encoded + $result->addPlayer('name', utf8_encode(trim($buffer->readString()))); + $result->addPlayer('clantag', $buffer->readString()); + // Increment + $playerCount++; + } + + // Add the number of players to the result + $result->add('numplayers', $playerCount); + + // Clear + unset($buffer, $playerCount); + + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/redeclipse.php b/third_party/gameq_v2/gameq/protocols/redeclipse.php deleted file mode 100644 index fc91bfb9..00000000 --- a/third_party/gameq_v2/gameq/protocols/redeclipse.php +++ /dev/null @@ -1,212 +0,0 @@ -. - */ - -/** - * Red Eclipse - * - * This game is based off of Cube 2 but the protocol response is way - * different than Cube 2 - * - * Thanks to Poil for information to help build out this protocol class - * - * References: - * https://github.com/stainsby/redflare/blob/master/poller.js - * https://github.com/stainsby/redflare/blob/master/lib/protocol.js - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Redeclipse extends GameQ_Protocols_Cube2 -{ - /** - * The query protocol used to make the call - * - * @var string - */ - protected $protocol = 'redeclipse'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'redeclipse'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Red Eclipse"; - - /** - * Defined Game mutators - * - * @var array - */ - protected $mutators = array( - 'multi' => 1, - 'ffa' => 2, - 'coop' => 4, - 'insta' => 8, - 'medieval' => 16, - 'kaboom' => 32, - 'duel' => 64, - 'survivor' => 128, - 'classic' => 256, - 'onslaught' => 512, - 'jetpack' => 1024, - 'vampire' => 2048, - 'expert' => 4096, - 'resize' => 8192, - ); - - /** - * Defined Master modes (i.e access restrictions) - * - * @var array - */ - protected $mastermodes = array( - 'open', // 0 - 'veto', // 1 - 'locked', // 2 - 'private', // 3 - 'password', // 4 - ); - - /** - * Defined Game modes - * - * @var array - */ - protected $gamemodes = array( - 'demo', // 0 - 'edit', // 1 - 'deathmatch', // 2 - 'capture-the-flag', // 3 - 'defend-the-flag', // 4 - 'bomberball', // 5 - 'time-trial', // 6 - 'gauntlet' // 7 - ); - - /** - * Process the status result. This result is different from the parent - * - * @see GameQ_Protocols_Cube2::process_status() - */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Let's preprocess the rules - $data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]); - - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Check the header, should be the same response as the packet we sent - if($buf->read(6) != $this->packets[self::PACKET_STATUS]) - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header type (should be {$this->packets[self::PACKET_STATUS]})."); - return array(); - } - - /** - * Reference chart for ints by position - * - * 0 - Num players - * 1 - Number of items to follow (i.e. 8), not used yet - * 2 - Version - * 3 - gamemode (dm, ctf, etc...) - * 4 - mutators (sum of power of 2) - * 5 - Time remaining - * 6 - max players - * 7 - Mastermode (open, password, etc) - * 8 - variable count - * 9 - modification count - */ - - $result->add('num_players', $this->readInt($buf)); - - $items = $this->readInt($buf); // We dump this as we dont use it for now - - $result->add('version', $this->readInt($buf)); - $result->add('gamemode', $this->gamemodes[$this->readInt($buf)]); - - // This is a sum of power's of 2 (2^1, 1 << 1) - $mutators_number = $this->readInt($buf); - - $mutators = array(); - - foreach($this->mutators AS $mutator => $flag) - { - if($flag & $mutators_number) - { - $mutators[] = $mutator; - } - } - - $result->add('mutators', $mutators); - $result->add('mutators_number', $mutators_number); - - $result->add('time_remaining', $this->readInt($buf)); - $result->add('max_players', $this->readInt($buf)); - - $mastermode = $this->readInt($buf); - - $result->add('mastermode', $this->mastermodes[$mastermode]); - - $result->add('password', ((in_array($mastermode, array(4)))?TRUE:FALSE)); - - // @todo: No idea what these next 2 are used for - $result->add('variableCount', $this->readInt($buf)); - $result->add('modificationCount', $this->readInt($buf)); - - $result->add('map', $buf->readString()); - $result->add('servername', $buf->readString()); - - // The rest from here is player information, we read until we run out of strings (\x00) - while($raw = $buf->readString()) - { - // Items seem to be seperated by \xc - $items = explode("\xc", $raw); - - // Indexes 0, 1 & 5 seem to be junk - // Indexes 2, 3, 4 seem to have something of use, not sure about #3 - $result->addPlayer('guid', (int) trim($items[2], "[]")); - - // Index 4 has the player name with some kind int added on to the front, icon or something? - // Anyway remove it for now... - if(preg_match('/(\[[0-9]+\])(.*)/i', $items[4], $name)) - { - $result->addPlayer('name', $name[2]); - } - } - - unset($buf, $data); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v2/gameq/protocols/redfaction.php b/third_party/gameq_v2/gameq/protocols/redfaction.php deleted file mode 100644 index dcb5cf21..00000000 --- a/third_party/gameq_v2/gameq/protocols/redfaction.php +++ /dev/null @@ -1,121 +0,0 @@ -. - */ - -/** - * Red Faction Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Redfaction extends GameQ_Protocols -{ - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "\x00\x00\x00\x00", - ); - - protected $state = self::STATE_TESTING; - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); - - /** - * Default port for this server type - * - * @var int - */ - protected $port = 7755; // Default port, used if not set when instanced - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'redfaction'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'redfaction'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Red Faction"; - - /* - * Internal methods - */ - - /** - * Process the server status - * - * @throws GameQ_ProtocolsException - */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Header, we're being carefull here - if ($buf->read() !== "\x00") - { - throw new GameQ_ProtocolsException('Header error in Red Faction'); - return FALSE; - } - - // Dunno - while ($buf->read() !== "\x00") {} - $buf->read(); - - // Data - $result->add('servername', $buf->readString()); - $result->add('gametype', $buf->readInt8()); - $result->add('num_players', $buf->readInt8()); - $result->add('max_players', $buf->readInt8()); - $result->add('map', $buf->readString()); - $buf->read(); - $result->add('dedicated', $buf->readInt8()); - - // Free some memory - unset($sections, $buf, $data); - - // Return the result - return $result->fetch(); - } -} diff --git a/third_party/gameq_v2/gameq/protocols/redorchestra.php b/third_party/gameq_v2/gameq/protocols/redorchestra.php deleted file mode 100644 index d63c8e74..00000000 --- a/third_party/gameq_v2/gameq/protocols/redorchestra.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Red Orchestra: Ostfront 41-45 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Redorchestra extends GameQ_Protocols_Gamespy -{ - protected $name = "redorchestra"; - protected $name_long = "Red Orchestra: Ostfront 41-45"; - - protected $port = 7767; -} diff --git a/third_party/gameq_v2/gameq/protocols/redorchestra2.php b/third_party/gameq_v2/gameq/protocols/redorchestra2.php index 01b59a1e..67330167 100644 --- a/third_party/gameq_v2/gameq/protocols/redorchestra2.php +++ b/third_party/gameq_v2/gameq/protocols/redorchestra2.php @@ -3,30 +3,48 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Red Orchestra 2 Protocol Class - * - * Thanks to http://forums.tripwireinteractive.com/showthread.php?t=72439 for information about the protocol + * Class Redorchestra2 * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_Redorchestra2 extends GameQ_Protocols_Source +class Redorchestra2 extends Source { - protected $name = "redorchestra2"; - protected $name_long = "Red Orchestra 2"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'redorchestra2'; - protected $port = 27015; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Red Orchestra 2"; + + /** + * query_port = client_port + 19238 + * 27015 = 7777 + 19238 + * + * @type int + */ + protected $port_diff = 19238; } diff --git a/third_party/gameq_v2/gameq/protocols/rtcw.php b/third_party/gameq_v2/gameq/protocols/rtcw.php deleted file mode 100644 index 3a9addef..00000000 --- a/third_party/gameq_v2/gameq/protocols/rtcw.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Return to Castle Wolfenstein Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Rtcw extends GameQ_Protocols_Quake3 -{ - protected $name = "rtcw"; - protected $name_long = "Return to Castle Wolfenstein"; - - protected $port = 27960; -} diff --git a/third_party/gameq_v2/gameq/protocols/rust.php b/third_party/gameq_v2/gameq/protocols/rust.php index 6e43e4d2..356cc19f 100644 --- a/third_party/gameq_v2/gameq/protocols/rust.php +++ b/third_party/gameq_v2/gameq/protocols/rust.php @@ -3,44 +3,62 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Buffer; + /** - * Rust Protocol Class + * Class Rust * - * Seems to respond to A2S but no rules, unsure if players is complete - * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Rust extends GameQ_Protocols_Source +class Rust extends Source { - protected $name = "rust"; - protected $name_long = "Rust"; - /** - * Overload for client port - * - * @param string $ip - * @param integer $port - * @param array $options - */ - public function __construct($ip = FALSE, $port = FALSE, $options = array()) - { - // Got to do this first - parent::__construct($ip, $port, $options); + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'rust'; - // Correct the client port since query_port = client_port + 1 - $this->port_client(($this->port_client() - 1)); - } + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Rust"; + + /** + * Overload so we can get max players from mp of keywords and num players from cp keyword + * + * @param Buffer $buffer + */ + protected function processDetails(Buffer $buffer) + { + $results = parent::processDetails($buffer); + + if ($results['keywords']) { + //get max players from mp of keywords and num players from cp keyword + preg_match_all('/(mp|cp)([\d]+)/', $results['keywords'], $matches); + $results['max_players'] = intval($matches[2][0]); + $results['num_players'] = intval($matches[2][1]); + } + + return $results; + } } diff --git a/third_party/gameq_v2/gameq/protocols/samp.php b/third_party/gameq_v2/gameq/protocols/samp.php index ebb04705..cf01f834 100644 --- a/third_party/gameq_v2/gameq/protocols/samp.php +++ b/third_party/gameq_v2/gameq/protocols/samp.php @@ -3,237 +3,277 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Server; +use GameQ\Exception\Protocol as Exception; + /** - * San Andreas Multiplayer Protocol Class + * San Andreas Multiplayer Protocol Class (samp) * - * This class holds the query info and processing for SAMP + * Note: + * Player information will not be returned if player count is over 256 * * @author Austin Bischoff */ -class GameQ_Protocols_Samp extends GameQ_Protocols +class Samp extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "SAMP%s%si", - self::PACKET_PLAYERS => "SAMP%s%sd", - self::PACKET_RULES => "SAMP%s%sr", - ); - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - "process_players", - "process_rules", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_STATUS => "SAMP%si", + self::PACKET_PLAYERS => "SAMP%sd", + self::PACKET_RULES => "SAMP%sr", + ]; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 7777; // Default port, used if not set when instanced + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\x69" => "processStatus", // i + "\x64" => "processPlayers", // d + "\x72" => "processRules", // r + ]; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'samp'; + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'samp'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'samp'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'samp'; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "San Andreas Multiplayer"; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "San Andreas Multiplayer"; + + /** + * Holds the calculated server code that is passed when querying for information + * + * @type string + */ + protected $server_code = null; + + /** + * The client join link + * + * @type string + */ + protected $join_link = "samp://%s:%d/"; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'hostname' => ['hostname', 'servername'], + 'mapname' => 'mapname', + 'maxplayers' => 'max_players', + 'numplayers' => 'num_players', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'score' => 'score', + 'ping' => 'ping', + ], + ]; + + /** + * Handle some work before sending the packets out to the server + * + * @param \GameQ\Server $server + */ + public function beforeSend(Server $server) + { + + // Build the server code + $this->server_code = implode('', array_map('chr', explode('.', $server->ip()))) . + pack("S", $server->portClient()); + + // Loop over the packets and update them + foreach ($this->packets as $packetType => $packet) { + // Fill out the packet with the server info + $this->packets[$packetType] = sprintf($packet, $this->server_code); + } + } + + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { + + // Results that will be returned + $results = []; + + // Get the length of the server code so we can figure out how much to read later + $serverCodeLength = strlen($this->server_code); + + // We need to pre-sort these for split packets so we can do extra work where needed + foreach ($this->packets_response as $response) { + // Make new buffer + $buffer = new Buffer($response); + + // Check the header, should be SAMP + if (($header = $buffer->read(4)) !== 'SAMP') { + throw new Exception(__METHOD__ . " header response '{$header}' is not valid"); + } + + // Check to make sure the server response code matches what we sent + if ($buffer->read($serverCodeLength) !== $this->server_code) { + throw new Exception(__METHOD__ . " code check failed."); + } + + // Figure out what packet response this is for + $response_type = $buffer->read(1); + + // Figure out which packet response this is + if (!array_key_exists($response_type, $this->responses)) { + throw new Exception(__METHOD__ . " response type '{$response_type}' is not valid"); + } + + // Now we need to call the proper method + $results = array_merge( + $results, + call_user_func_array([$this, $this->responses[$response_type]], [$buffer]) + ); + + unset($buffer); + } + + return $results; + } /* * Internal methods */ - /** - * We need to modify the packets before they are sent for this protocol - * - * @see GameQ_Protocols_Core::beforeSend() - */ - public function beforeSend() - { - // We need to repack the IP address of the server - $address = implode('', array_map('chr', explode('.', $this->ip))); - - // Repack the server port - $port = pack ("S", $this->port); - - // Let's loop the packets and set the proper pieces - foreach($this->packets AS $packet_type => $packet) - { - // Fill out the packet with the server info - $this->packets[$packet_type] = sprintf($packet, $address, $port); - } - - // Free up some memory - unset($address, $port); - - return TRUE; - } - - protected function preProcess($packets) + /** + * Handles processing the server status data + * + * @param \GameQ\Buffer $buffer + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + protected function processStatus(Buffer $buffer) { - // Make buffer so we can check this out - $buf = new GameQ_Buffer(implode('', $packets)); - // Grab the header - $header = $buf->read(11); + // Set the result to a new result instance + $result = new Result(); - // Now lets verify the header - if(substr($header, 0, 4) != "SAMP") - { - throw new GameQ_ProtocolsException('Unable to match SAMP response header. Header: '. $header); - return FALSE; - } + // Always dedicated + $result->add('dedicated', 1); - // Return the data with the header stripped, ready to go. - return $buf->getBuffer(); + // Pull out the server information + $result->add('password', $buffer->readInt8()); + $result->add('num_players', $buffer->readInt16()); + $result->add('max_players', $buffer->readInt16()); + + // These are read differently for these last 3 + $result->add('servername', utf8_encode($buffer->read($buffer->readInt32()))); + $result->add('gametype', $buffer->read($buffer->readInt32())); + $result->add('language', $buffer->read($buffer->readInt32())); + + unset($buffer); + + return $result->fetch(); } /** - * Process the server status + * Handles processing the player data into a usable format * - * @throws GameQ_ProtocolsException + * @param \GameQ\Buffer $buffer + * + * @return array */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } + protected function processPlayers(Buffer $buffer) + { - // Set the result to a new result instance - $result = new GameQ_Result(); + // Set the result to a new result instance + $result = new Result(); - // Always dedicated - $result->add('dedicated', TRUE); + // Number of players + $result->add('num_players', $buffer->readInt16()); - // Preprocess and make buffer - $buf = new GameQ_Buffer($this->preProcess($this->packets_response[self::PACKET_STATUS])); + // Run until we run out of buffer + while ($buffer->getLength()) { + $result->addPlayer('id', $buffer->readInt8()); + $result->addPlayer('name', utf8_encode($buffer->readPascalString())); + $result->addPlayer('score', $buffer->readInt32()); + $result->addPlayer('ping', $buffer->readInt32()); + } - // Pull out the server information - $result->add('password', (bool) $buf->readInt8()); - $result->add('num_players', $buf->readInt16()); - $result->add('max_players', $buf->readInt16()); + unset($buffer); - // These are read differently for these last 3 - $result->add('servername', $buf->read($buf->readInt32())); - $result->add('gametype', $buf->read($buf->readInt32())); - $result->add('map', $buf->read($buf->readInt32())); - - // Free some memory - unset($buf); - - // Return the result return $result->fetch(); - } + } - /** - * Process server rules - */ - protected function process_rules() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_RULES)) - { - return array(); - } + /** + * Handles processing the rules data into a usable format + * + * @param \GameQ\Buffer $buffer + * + * @return array + */ + protected function processRules(Buffer $buffer) + { - // Set the result to a new result instance - $result = new GameQ_Result(); + // Set the result to a new result instance + $result = new Result(); - // Preprocess and make buffer - $buf = new GameQ_Buffer($this->preProcess($this->packets_response[self::PACKET_RULES])); + // Number of rules + $result->add('num_rules', $buffer->readInt16()); - // Number of rules - $result->add('num_rules', $buf->readInt16()); + // Run until we run out of buffer + while ($buffer->getLength()) { + $result->add($buffer->readPascalString(), $buffer->readPascalString()); + } - // Run until we run out of buffer - while ($buf->getLength()) - { - $result->add($buf->readPascalString(), $buf->readPascalString()); - } + unset($buffer); - // Free some memory - unset($buf); - - // Return the result - return $result->fetch(); - } - - /** - * Process the players - * - * NOTE: There is a restriction on the SAMP server side that if there are too many players - * the player return will be empty. Nothing can really be done about this unless you bug - * the game developers to fix it. - */ - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Preprocess and make buffer - $buf = new GameQ_Buffer($this->preProcess($this->packets_response[self::PACKET_PLAYERS])); - - // Number of players - $result->add('num_players', $buf->readInt16()); - - // Run until we run out of buffer - while ($buf->getLength()) - { - $result->addPlayer('id', $buf->readInt8()); - $result->addPlayer('name', $buf->readPascalString()); - $result->addPlayer('score', $buf->readInt32()); - $result->addPlayer('ping', $buf->readInt32()); - } - - // Free some memory - unset($buf); - - // Return the result - return $result->fetch(); - } + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/sof2.php b/third_party/gameq_v2/gameq/protocols/sof2.php index fda9d208..96a4db25 100644 --- a/third_party/gameq_v2/gameq/protocols/sof2.php +++ b/third_party/gameq_v2/gameq/protocols/sof2.php @@ -3,28 +3,47 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Soldier of Fortune 2 Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Sof2 extends GameQ_Protocols_Quake3 -{ - protected $name = "sof2"; - protected $name_long = "Soldier of Fortune 2"; +namespace GameQ\Protocols; - protected $port = 20100; +/** + * Soldier of Fortune 2 Class + * + * @package GameQ\Protocols + * @author Austin Bischoff + */ +class Sof2 extends Quake3 +{ + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'sof2'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Solder of Fortune II"; + + /** + * The client join link + * + * @type string + */ + protected $join_link = "sof2mp://%s:%d/"; } diff --git a/third_party/gameq_v2/gameq/protocols/soldat.php b/third_party/gameq_v2/gameq/protocols/soldat.php index e22fd3f7..a9dbbc4e 100644 --- a/third_party/gameq_v2/gameq/protocols/soldat.php +++ b/third_party/gameq_v2/gameq/protocols/soldat.php @@ -3,28 +3,57 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -/** - * Soldat Protocol Class - * - * @author Marcel Bößendörfer - */ -class GameQ_Protocols_Soldat extends GameQ_Protocols_ASE -{ - protected $name = "Soldat"; - protected $name_long = "Soldat"; +namespace GameQ\Protocols; - protected $port = 23196; +/** + * Class Soldat + * + * @package GameQ\Protocols + * + * @author Marcel Bößendörfer + * @author Austin Bischoff + */ +class Soldat extends Ase +{ + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'soldat'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Soldat"; + + /** + * query_port = client_port + 123 + * + * @type int + */ + protected $port_diff = 123; + + /** + * The client join link + * + * @type string + */ + protected $join_link = "soldat://%s:%d/"; } diff --git a/third_party/gameq_v2/gameq/protocols/source.php b/third_party/gameq_v2/gameq/protocols/source.php index 8a3f8684..dbf9212a 100644 --- a/third_party/gameq_v2/gameq/protocols/source.php +++ b/third_party/gameq_v2/gameq/protocols/source.php @@ -3,109 +3,223 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Buffer; +use GameQ\Exception\Protocol as Exception; +use GameQ\Protocol; +use GameQ\Result; + /** - * Valve Source Engine Protocol Class + * Valve Source Engine Protocol Class (A2S) * * This class is used as the basis for all other source based servers - * that rely on the source protocol for game querying + * that rely on the source protocol for game querying. + * + * @SuppressWarnings(PHPMD.NumberOfChildren) * * @author Austin Bischoff */ -class GameQ_Protocols_Source extends GameQ_Protocols +class Source extends Protocol { - /* - * Source engine type constants - */ - const SOURCE_ENGINE = 0; - const GOLDSOURCE_ENGINE = 1; - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x56\x00\x00\x00\x00", - self::PACKET_DETAILS => "\xFF\xFF\xFF\xFFTSource Engine Query\x00", - self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s", - self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s", - ); + /* + * Source engine type constants + */ + const SOURCE_ENGINE = 0, + GOLDSOURCE_ENGINE = 1; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_details", - "process_players", - "process_rules", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x56\x00\x00\x00\x00", + self::PACKET_DETAILS => "\xFF\xFF\xFF\xFFTSource Engine Query\x00%s", + self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s", + self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s", + ]; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 27015; // Default port, used if not set when instanced + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\x49" => "processDetails", // I + "\x6d" => "processDetailsGoldSource", // m, goldsource + "\x44" => "processPlayers", // D + "\x45" => "processRules", // E + ]; - /** - * The query protocol used to make the call - * - * @var string - */ - protected $protocol = 'source'; + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'source'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'source'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'source'; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Source Server"; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Source Server"; - /** - * Define the Source engine type. By default it is assumed to be Source - * - * @var int - */ - protected $source_engine = self::SOURCE_ENGINE; + /** + * Define the Source engine type. By default it is assumed to be Source + * + * @type int + */ + protected $source_engine = self::SOURCE_ENGINE; - protected $join_link = "steam://connect/%s:%d/"; + /** + * The client join link + * + * @type string + */ + protected $join_link = "steam://connect/%s:%d/"; - /** - * Parse the challenge response and apply it to all the packet types - * that require it. - * - * @see GameQ_Protocols_Core::parseChallengeAndApply() - */ - protected function parseChallengeAndApply() + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'gametype' => 'game_descr', + 'hostname' => 'hostname', + 'mapname' => 'map', + 'maxplayers' => 'max_players', + 'mod' => 'game_dir', + 'numplayers' => 'num_players', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'score' => 'score', + 'time' => 'time', + ], + ]; + + /** + * Parse the challenge response and apply it to all the packet types + * + * @param \GameQ\Buffer $challenge_buffer + * + * @return bool + * @throws \GameQ\Exception\Protocol + */ + public function challengeParseAndApply(Buffer $challenge_buffer) { - // Skip the header - $this->challenge_buffer->skip(5); - // Apply the challenge and return - return $this->challengeApply($this->challenge_buffer->read(4)); + // Skip the header + $challenge_buffer->skip(5); + + // Apply the challenge and return + return $this->challengeApply($challenge_buffer->read(4)); + } + + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { + // Will hold the results when complete + $results = []; + + // Holds sorted response packets + $packets = []; + + // We need to pre-sort these for split packets so we can do extra work where needed + foreach ($this->packets_response as $response) { + $buffer = new Buffer($response); + + // Get the header of packet (long) + $header = $buffer->readInt32Signed(); + + // Single packet + if ($header == -1) { + // We need to peek and see what kind of engine this is for later processing + if ($buffer->lookAhead(1) == "\x6d") { + $this->source_engine = self::GOLDSOURCE_ENGINE; + } + + $packets[] = $buffer->getBuffer(); + continue; + } else { + // Split packet + + // Packet Id (long) + $packet_id = $buffer->readInt32Signed() + 10; + + // Add the buffer to the packet as another array + $packets[$packet_id][] = $buffer->getBuffer(); + } + } + + // Free up memory + unset($response, $packet_id, $buffer, $header); + + // Now that we have the packets sorted we need to iterate and process them + foreach ($packets as $packet_id => $packet) { + // We first need to off load split packets to combine them + if (is_array($packet)) { + $buffer = new Buffer($this->processPackets($packet_id, $packet)); + } else { + $buffer = new Buffer($packet); + } + + // Figure out what packet response this is for + $response_type = $buffer->read(1); + + // Figure out which packet response this is + if (!array_key_exists($response_type, $this->responses)) { + throw new Exception(__METHOD__ . " response type '{$response_type}' is not valid"); + } + + // Now we need to call the proper method + $results = array_merge( + $results, + call_user_func_array([$this, $this->responses[$response_type]], [$buffer]) + ); + + unset($buffer); + } + + // Free up memory + unset($packets, $packet, $packet_id, $response_type); + + return $results; } /* @@ -113,343 +227,296 @@ class GameQ_Protocols_Source extends GameQ_Protocols */ /** - * Pre-process the server details data that was returned. + * Process the split packets and decompress if necessary * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + * + * @param $packet_id * @param array $packets + * + * @return string + * @throws \GameQ\Exception\Protocol */ - protected function preProcess_details($packets) + protected function processPackets($packet_id, array $packets = []) { - // Process the packets - return $this->process_packets($packets); + + // Init array so we can order + $packs = []; + + // We have multiple packets so we need to get them and order them + foreach ($packets as $i => $packet) { + // Make a buffer so we can read this info + $buffer = new Buffer($packet); + + // Gold source + if ($this->source_engine == self::GOLDSOURCE_ENGINE) { + // Grab the packet number (byte) + $packet_number = $buffer->readInt8(); + + // We need to burn the extra header (\xFF\xFF\xFF\xFF) on first loop + if ($i == 0) { + $buffer->read(4); + } + + // Now add the rest of the packet to the new array with the packet_number as the id so we can order it + $packs[$packet_number] = $buffer->getBuffer(); + } else { + // Number of packets in this set (byte) + $buffer->readInt8(); + + // The current packet number (byte) + $packet_number = $buffer->readInt8(); + + // Check to see if this is compressed + // @todo: Check to make sure these decompress correctly, new changes may affect this loop. + if ($packet_id & 0x80000000) { + // Check to see if we have Bzip2 installed + if (!function_exists('bzdecompress')) { + // @codeCoverageIgnoreStart + throw new Exception( + 'Bzip2 is not installed. See http://www.php.net/manual/en/book.bzip2.php for more info.', + 0 + ); + // @codeCoverageIgnoreEnd + } + + // Get the length of the packet (long) + $packet_length = $buffer->readInt32Signed(); + + // Checksum for the decompressed packet (long), burn it - doesnt work in split responses + $buffer->readInt32Signed(); + + // Try to decompress + $result = bzdecompress($buffer->getBuffer()); + + // Now verify the length + if (strlen($result) != $packet_length) { + // @codeCoverageIgnoreStart + throw new Exception( + "Checksum for compressed packet failed! Length expected: {$packet_length}, length + returned: " . strlen($result) + ); + // @codeCoverageIgnoreEnd + } + + // We need to burn the extra header (\xFF\xFF\xFF\xFF) on first loop + if ($i == 0) { + $result = substr($result, 4); + } + } else { + // Get the packet length (short), burn it + $buffer->readInt16Signed(); + + // We need to burn the extra header (\xFF\xFF\xFF\xFF) on first loop + if ($i == 0) { + $buffer->read(4); + } + + // Grab the rest of the buffer as a result + $result = $buffer->getBuffer(); + } + + // Add this packet to the list + $packs[$packet_number] = $result; + } + + unset($buffer); + } + + // Free some memory + unset($packets, $packet); + + // Sort the packets by packet number + ksort($packs); + + // Now combine the packs into one and return + return implode("", $packs); } /** * Handles processing the details data into a usable format * - * @throws GameQ_ProtocolsException + * @param \GameQ\Buffer $buffer + * + * @return mixed + * @throws \GameQ\Exception\Protocol */ - protected function process_details() + protected function processDetails(Buffer $buffer) { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_DETAILS)) - { - return array(); - } - // Set the result to a new result instance - $result = new GameQ_Result(); + // Set the result to a new result instance + $result = new Result(); - // Let's preprocess the rules - $data = $this->preProcess_details($this->packets_response[self::PACKET_DETAILS]); + $result->add('protocol', $buffer->readInt8()); + $result->add('hostname', $buffer->readString()); + $result->add('map', $buffer->readString()); + $result->add('game_dir', $buffer->readString()); + $result->add('game_descr', $buffer->readString()); + $result->add('steamappid', $buffer->readInt16()); + $result->add('num_players', $buffer->readInt8()); + $result->add('max_players', $buffer->readInt8()); + $result->add('num_bots', $buffer->readInt8()); + $result->add('dedicated', $buffer->read()); + $result->add('os', $buffer->read()); + $result->add('password', $buffer->readInt8()); + $result->add('secure', $buffer->readInt8()); - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Skip the header (0xFF0xFF0xFF0xFF) - $buf->skip(4); - - // Get the type - $type = $buf->read(1); - - // Make sure the data is formatted properly - // Source is 0x49, Goldsource is 0x6d, 0x44 I am not sure about - if(!in_array($type, array("\x49", "\x44", "\x6d"))) - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header type (should be 0x49|0x44|0x6d). Header type: 0x".bin2hex($type)); - return array(); - } - - // Update the engine type for other calls and other methods, if necessary - if(bin2hex($type) == '6d') - { - $this->source_engine = self::GOLDSOURCE_ENGINE; - } - - // Check engine type - if ($this->source_engine == self::GOLDSOURCE_ENGINE) - { - $result->add('address', $buf->readString()); - } - else - { - $result->add('protocol', $buf->readInt8()); + // Special result for The Ship only (appid=2400) + if ($result->get('steamappid') == 2400) { + $result->add('game_mode', $buffer->readInt8()); + $result->add('witness_count', $buffer->readInt8()); + $result->add('witness_time', $buffer->readInt8()); } - $result->add('hostname', $buf->readString()); - $result->add('map', $buf->readString()); - $result->add('game_dir', $buf->readString()); - $result->add('game_descr', $buf->readString()); + $result->add('version', $buffer->readString()); - // Check engine type - if ($this->source_engine != self::GOLDSOURCE_ENGINE) - { - $result->add('steamappid', $buf->readInt16()); + // Because of php 5.4... + $edfCheck = $buffer->lookAhead(1); + + // Extra data flag + if (!empty($edfCheck)) { + $edf = $buffer->readInt8(); + + if ($edf & 0x80) { + $result->add('port', $buffer->readInt16Signed()); + } + + if ($edf & 0x10) { + $result->add('steam_id', $buffer->readInt64()); + } + + if ($edf & 0x40) { + $result->add('sourcetv_port', $buffer->readInt16Signed()); + $result->add('sourcetv_name', $buffer->readString()); + } + + if ($edf & 0x20) { + $result->add('keywords', $buffer->readString()); + } + + if ($edf & 0x01) { + $result->add('game_id', $buffer->readInt64()); + } + + unset($edf); } - $result->add('num_players', $buf->readInt8()); - $result->add('max_players', $buf->readInt8()); - - // Check engine type - if ($this->source_engine == self::GOLDSOURCE_ENGINE) - { - $result->add('version', $buf->readInt8()); - } - else - { - $result->add('num_bots', $buf->readInt8()); - } - - $result->add('dedicated', $buf->read()); - $result->add('os', $buf->read()); - $result->add('password', $buf->readInt8()); - - // Check engine type - if ($this->source_engine == self::GOLDSOURCE_ENGINE) - { - $result->add('ismod', $buf->readInt8()); - } - - $result->add('secure', $buf->readInt8()); - - // Check engine type - if ($this->source_engine == self::GOLDSOURCE_ENGINE) - { - $result->add('num_bots', $buf->readInt8()); - } - else - { - $result->add('version', $buf->readInt8()); - } - - // Add extra data flag check here, only for source games (not goldsource) - // https://developer.valvesoftware.com/wiki/Server_Queries#Source_servers_2 - - unset($buf); + unset($buffer); return $result->fetch(); } /** - * Pre-process the player data sent + * Handles processing the server details from goldsource response * - * @param array $packets + * @param \GameQ\Buffer $buffer + * + * @return array + * @throws \GameQ\Exception\Protocol */ - protected function preProcess_players($packets) + protected function processDetailsGoldSource(Buffer $buffer) { - // Process the packets - return $this->process_packets($packets); + + // Set the result to a new result instance + $result = new Result(); + + $result->add('address', $buffer->readString()); + $result->add('hostname', $buffer->readString()); + $result->add('map', $buffer->readString()); + $result->add('game_dir', $buffer->readString()); + $result->add('game_descr', $buffer->readString()); + $result->add('num_players', $buffer->readInt8()); + $result->add('max_players', $buffer->readInt8()); + $result->add('version', $buffer->readInt8()); + $result->add('dedicated', $buffer->read()); + $result->add('os', $buffer->read()); + $result->add('password', $buffer->readInt8()); + + // Mod section + $result->add('ismod', $buffer->readInt8()); + + // We only run these if ismod is 1 (true) + if ($result->get('ismod') == 1) { + $result->add('mod_urlinfo', $buffer->readString()); + $result->add('mod_urldl', $buffer->readString()); + $buffer->skip(); + $result->add('mod_version', $buffer->readInt32Signed()); + $result->add('mod_size', $buffer->readInt32Signed()); + $result->add('mod_type', $buffer->readInt8()); + $result->add('mod_cldll', $buffer->readInt8()); + } + + $result->add('secure', $buffer->readInt8()); + $result->add('num_bots', $buffer->readInt8()); + + unset($buffer); + + return $result->fetch(); } /** - * Handles processing the player data into a useable format + * Handles processing the player data into a usable format * - * @throws GameQ_ProtocolsException + * @param \GameQ\Buffer $buffer + * + * @return mixed */ - protected function process_players() + protected function processPlayers(Buffer $buffer) { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } - // Set the result to a new result instance - $result = new GameQ_Result(); + // Set the result to a new result instance + $result = new Result(); - // Let's preprocess the rules - $data = $this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]); + // Pull out the number of players + $num_players = $buffer->readInt8(); - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Make sure the data is formatted properly - if(($header = $buf->read(5)) != "\xFF\xFF\xFF\xFF\x44") - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header (should be 0xFF0xFF0xFF0xFF0x44). Header: ".bin2hex($header)); - return array(); - } - - // Pull out the number of players - $num_players = $buf->readInt8(); - - // Player count + // Player count $result->add('num_players', $num_players); // No players so no need to look any further - if($num_players == 0) - { - return $result->fetch(); - } - - // Players list - while ($buf->getLength()) - { - $result->addPlayer('id', $buf->readInt8()); - $result->addPlayer('name', $buf->readString()); - $result->addPlayer('score', $buf->readInt32Signed()); - $result->addPlayer('time', $buf->readFloat32()); + if ($num_players == 0) { + return $result->fetch(); } - unset($buf); + // Players list + while ($buffer->getLength()) { + $result->addPlayer('id', $buffer->readInt8()); + $result->addPlayer('name', $buffer->readString()); + $result->addPlayer('score', $buffer->readInt32Signed()); + $result->addPlayer('time', $buffer->readFloat32()); + } + + unset($buffer); return $result->fetch(); } - /** - * Pre process the rules data that was returned. Make sure the return - * data is in a single string - * - * @param array $packets - */ - protected function preProcess_rules($packets) - { - // Process the packets - return $this->process_packets($packets); - } - /** * Handles processing the rules data into a usable format * - * @throws GameQ_ProtocolsException + * @param \GameQ\Buffer $buffer + * + * @return mixed */ - protected function process_rules() + protected function processRules(Buffer $buffer) { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_RULES)) - { - return array(); - } - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Let's preprocess the rules - $data = $this->preProcess_rules($this->packets_response[self::PACKET_RULES]); - - $buf = new GameQ_Buffer($data); - - // Make sure the data is formatted properly - if(($header = $buf->read(5)) != "\xFF\xFF\xFF\xFF\x45") - { - throw new GameQ_ProtocolsException("Data for ".__METHOD__." does not have the proper header (should be 0xFF0xFF0xFF0xFF0x45). Header: ".bin2hex($header)); - return array(); - } + // Set the result to a new result instance + $result = new Result(); // Count the number of rules - $num_rules = $buf->readInt16Signed(); + $num_rules = $buffer->readInt16Signed(); // Add the count of the number of rules this server has $result->add('num_rules', $num_rules); // Rules - while ($buf->getLength()) - { - $result->add($buf->readString(), $buf->readString()); + while ($buffer->getLength()) { + $result->add($buffer->readString(), $buffer->readString()); } - unset($buf); + unset($buffer); return $result->fetch(); } - - /** - * Process the packets to make sure we combine and decompress as needed - * - * @param array $packets - * @throws GameQ_ProtocolsException - * @return string - */ - protected function process_packets($packets) - { - // Make a buffer to see if we should have multiple packets - $buffer = new GameQ_Buffer($packets[0]); - - // First we need to see if the packet is split - // -2 = split packets - // -1 = single packet - $packet_type = $buffer->readInt32Signed(); - - // This is one packet so just return the rest of the buffer - if($packet_type == -1) - { - // Free some memory - unset($buffer); - - // We always return the packet as expected, with null included - return $packets[0]; - } - - // Free some memory - unset($buffer); - - // Init array so we can order - $packs = array(); - - // We have multiple packets so we need to get them and order them - foreach($packets AS $packet) - { - // Make a buffer so we can read this info - $buffer = new GameQ_Buffer($packet); - - // Pull some info - $packet_type = $buffer->readInt32Signed(); - $request_id = $buffer->readInt32Signed(); - - // Check to see if this is compressed - if($request_id & 0x80000000) - { - // Check to see if we have Bzip2 installed - if(!function_exists('bzdecompress')) - { - throw new GameQ_ProtocolsException('Bzip2 is not installed. See http://www.php.net/manual/en/book.bzip2.php for more info.', 0); - return FALSE; - } - - // Get some info - $num_packets = $buffer->readInt8(); - $cur_packet = $buffer->readInt8(); - $packet_length = $buffer->readInt32(); - $packet_checksum = $buffer->readInt32(); - - // Try to decompress - $result = bzdecompress($buffer->getBuffer()); - - // Now verify the length - if(strlen($result) != $packet_length) - { - throw new GameQ_ProtocolsException("Checksum for compressed packet failed! Length expected: {$packet_length}, length returned: ".strlen($result)); - } - - // Set the new packs - $packs[$cur_packet] = $result; - } - else // Normal packet - { - // Gold source does things a bit different - if($this->source_engine == self::GOLDSOURCE_ENGINE) - { - $packet_number = $buffer->readInt8(); - } - else // New source - { - $packet_number = $buffer->readInt16Signed(); - $split_length = $buffer->readInt16Signed(); - } - - // Now add the rest of the packet to the new array with the packet_number as the id so we can order it - $packs[$packet_number] = $buffer->getBuffer(); - } - - unset($buffer); - } - - // Free some memory - unset($packets, $packet); - - // Sort the packets by packet number - ksort($packs); - - // Now combine the packs into one and return - return implode("", $packs); - } } diff --git a/third_party/gameq_v2/gameq/protocols/stalker.php b/third_party/gameq_v2/gameq/protocols/stalker.php deleted file mode 100644 index b3b82eba..00000000 --- a/third_party/gameq_v2/gameq/protocols/stalker.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -/** - * Stalker Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Stalker extends GameQ_Protocols_Gamespy2 -{ - protected $name = "stalker"; - protected $name_long = "S.T.A.L.K.E.R: Shadow of Chernobyl"; - - protected $port = 5445; -} diff --git a/third_party/gameq_v2/gameq/protocols/starbound.php b/third_party/gameq_v2/gameq/protocols/starbound.php deleted file mode 100644 index bd3d7f2f..00000000 --- a/third_party/gameq_v2/gameq/protocols/starbound.php +++ /dev/null @@ -1,33 +0,0 @@ -. - */ - -/** - * Starbound Protocol Class - * - * Unable to test if player information is returned. Also appears the challenge procedure - * is ignored. - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Starbound extends GameQ_Protocols_Source -{ - protected $name = "starbound"; - protected $name_long = "Starbound"; - - protected $port = 21025; -} diff --git a/third_party/gameq_v2/gameq/protocols/teamspeak2.php b/third_party/gameq_v2/gameq/protocols/teamspeak2.php index ebbf08b7..df0d59aa 100644 --- a/third_party/gameq_v2/gameq/protocols/teamspeak2.php +++ b/third_party/gameq_v2/gameq/protocols/teamspeak2.php @@ -3,338 +3,288 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Server; +use GameQ\Exception\Protocol as Exception; + /** * Teamspeak 2 Protocol Class * - * This class provides some functionality for getting status information for Teamspeak 2 - * servers. + * All values are utf8 encoded upon processing * - * This code ported from GameQ v1. Credit to original author(s) as I just updated it to + * This code ported from GameQ v1/v2. Credit to original author(s) as I just updated it to * work within this new system. * * @author Austin Bischoff */ -class GameQ_Protocols_Teamspeak2 extends GameQ_Protocols +class Teamspeak2 extends Protocol { - /** - * Normalization for this protocol class - * - * @var array - */ - protected $normalize = array( - // General - 'general' => array( - 'dedicated' => array('dedicated'), - 'hostname' => array('servername'), - 'password' => array('serverpassword'), - 'numplayers' => array('servercurrentusers'), - 'maxplayers' => array('servermaxusers'), - 'players' => array('players'), - 'teams' => array('teams'), - ), - // Player - 'player' => array( - 'id' => array('pid'), - 'team' => array('cid'), - ), + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_DETAILS => "sel %d\x0asi\x0a", + self::PACKET_CHANNELS => "sel %d\x0acl\x0a", + self::PACKET_PLAYERS => "sel %d\x0apl\x0a", + ]; - // Team - 'team' => array( - 'id' => array('id'), - ), - ); + /** + * The transport mode for this protocol is TCP + * + * @type string + */ + protected $transport = self::TRANSPORT_TCP; - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_DETAILS => "sel %d\x0Asi\x0A", - self::PACKET_PLAYERS => "sel %d\x0Apl\x0A", - self::PACKET_CHANNELS => "sel %d\x0Acl\x0A", - ); + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'teamspeak2'; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_details", - "process_channels", - "process_players", - ); + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'teamspeak2'; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 8767; // Default port, used if not set when instanced + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Teamspeak 2"; - /** - * Because Teamspeak is run like a master server we have to know what port we are really querying - * - * @var int - */ - protected $master_server_port = 51234; + /** + * The client join link + * + * @type string + */ + protected $join_link = "teamspeak://%s:%d/"; - /** - * We have to use TCP connection - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + 'dedicated' => 'dedicated', + 'hostname' => 'server_name', + 'password' => 'server_password', + 'numplayers' => 'server_currentusers', + 'maxplayers' => 'server_maxusers', + ], + // Player + 'player' => [ + 'id' => 'p_id', + 'team' => 'c_id', + 'name' => 'nick', + ], + // Team + 'team' => [ + 'id' => 'id', + 'name' => 'name', + ], + ]; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'teamspeak2'; + /** + * Before we send off the queries we need to update the packets + * + * @param \GameQ\Server $server + * + * @throws \GameQ\Exception\Protocol + */ + public function beforeSend(Server $server) + { - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'teamspeak2'; + // Check to make sure we have a query_port because it is required + if (!isset($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) + || empty($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) + ) { + throw new Exception(__METHOD__ . " Missing required setting '" . Server::SERVER_OPTIONS_QUERY_PORT . "'."); + } - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Teamspeak 2"; + // Let's loop the packets and set the proper pieces + foreach ($this->packets as $packet_type => $packet) { + // Update with the client port for the server + $this->packets[$packet_type] = sprintf($packet, $server->portClient()); + } + } - protected $join_link = "teamspeak://%s:%d/"; + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { - /** - * We need to affect the packets we are sending before they are sent - * - * @see GameQ_Protocols_Core::beforeSend() - */ - public function beforeSend() - { - // Let's loop the packets and set the proper pieces - foreach($this->packets AS $packet_type => $packet) - { - // Update the query port for the server - $this->packets[$packet_type] = sprintf($packet, $this->port); - } + // Make a new buffer out of all of the packets + $buffer = new Buffer(implode('', $this->packets_response)); - // Set the port we are connecting to the master port - $this->port = $this->master_server_port; + // Check the header [TS] + if (($header = trim($buffer->readString("\n"))) !== '[TS]') { + throw new Exception(__METHOD__ . " Expected header '{$header}' does not match expected '[TS]'."); + } - return TRUE; - } + // Split this buffer as the data blocks are bound by "OK" and drop any empty values + $sections = array_filter(explode("OK", $buffer->getBuffer()), function ($value) { + $value = trim($value); + + return !empty($value); + }); + + // Trim up the values to remove extra whitespace + $sections = array_map('trim', $sections); + + // Set the result to a new result instance + $result = new Result(); + + // Now we need to iterate over the sections and off load the processing + foreach ($sections as $section) { + // Grab a snip of the data so we can figure out what it is + $check = substr($section, 0, 7); + + // Offload to the proper method + if ($check == 'server_') { + // Server settings and info + $this->processDetails($section, $result); + } elseif ($check == "id\tcode") { + // Channel info + $this->processChannels($section, $result); + } elseif ($check == "p_id\tc_") { + // Player info + $this->processPlayers($section, $result); + } + } + + unset($buffer, $sections, $section, $check); + + return $result->fetch(); + } /* * Internal methods */ - protected function preProcess($packets=array()) - { - // Create a buffer - $buffer = new GameQ_Buffer(implode("", $packets)); - - // Verify the header - $this->verify_header($buffer); - - return $buffer; - } /** - * Process the server information + * Handles processing the details data into a usable format + * + * @param string $data + * @param \GameQ\Result $result */ - protected function process_details() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_DETAILS)) - { - return array(); - } + protected function processDetails($data, Result &$result) + { - // Let's preprocess the status - $buffer = $this->preProcess($this->packets_response[self::PACKET_DETAILS]); + // Create a buffer + $buffer = new Buffer($data); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Always dedicated + $result->add('dedicated', 1); - // Always dedicated - $result->add('dedicated', TRUE); + // Let's loop until we run out of data + while ($buffer->getLength()) { + // Grab the row, which is an item + $row = trim($buffer->readString("\n")); - // Let's loop until we run out of data - while($buffer->getLength()) - { - // Grab the row, which is an item - // Check for end of packet - if(($row = trim($buffer->readString("\n"))) == 'OK') - { - break; - } + // Split out the information + list($key, $value) = explode('=', $row, 2); - // Split out the information - list($key, $value) = explode('=', $row, 2); + // Add this to the result + $result->add($key, utf8_encode($value)); + } - // Add this to the result - $result->add($key, $value); - } + unset($data, $buffer, $row, $key, $value); + } - unset($buffer, $row, $key, $value); + /** + * Process the channel listing + * + * @param string $data + * @param \GameQ\Result $result + */ + protected function processChannels($data, Result &$result) + { - return $result->fetch(); - } + // Create a buffer + $buffer = new Buffer($data); - /** - * Process the channel listing - */ - protected function process_channels() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_CHANNELS)) - { - return array(); - } + // The first line holds the column names, data returned is in column/row format + $columns = explode("\t", trim($buffer->readString("\n")), 9); - // Let's preprocess the status - $buffer = $this->preProcess($this->packets_response[self::PACKET_CHANNELS]); + // Loop through the rows until we run out of information + while ($buffer->getLength()) { + // Grab the row, which is a tabbed list of items + $row = trim($buffer->readString("\n")); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Explode and merge the data with the columns, then parse + $data = array_combine($columns, explode("\t", $row, 9)); - // The first line holds the column names, data returned is in column/row format - $columns = explode("\t", trim($buffer->readString("\n")), 9); + foreach ($data as $key => $value) { + // Now add the data to the result + $result->addTeam($key, utf8_encode($value)); + } + } - // Loop thru the rows until we run out of information - while($buffer->getLength()) - { - // Grab the row, which is a tabbed list of items - // Check for end of packet - if(($row = trim($buffer->readString("\n"))) == 'OK') - { - break; - } + unset($data, $buffer, $row, $columns, $key, $value); + } - // Explode and merge the data with the columns, then parse - $data = array_combine($columns, explode("\t", $row, 9)); + /** + * Process the user listing + * + * @param string $data + * @param \GameQ\Result $result + */ + protected function processPlayers($data, Result &$result) + { - foreach($data AS $key => $value) - { - // Now add the data to the result - $result->addTeam($key, $value); - } - } + // Create a buffer + $buffer = new Buffer($data); - unset($data, $buffer, $row, $columns, $key, $value); + // The first line holds the column names, data returned is in column/row format + $columns = explode("\t", trim($buffer->readString("\n")), 16); - return $result->fetch(); - } + // Loop through the rows until we run out of information + while ($buffer->getLength()) { + // Grab the row, which is a tabbed list of items + $row = trim($buffer->readString("\n")); - /** - * Process the players response - */ - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } + // Explode and merge the data with the columns, then parse + $data = array_combine($columns, explode("\t", $row, 16)); - // Let's preprocess the status - $buffer = $this->preProcess($this->packets_response[self::PACKET_PLAYERS]); + foreach ($data as $key => $value) { + // Now add the data to the result + $result->addPlayer($key, utf8_encode($value)); + } + } - // Set the result to a new result instance - $result = new GameQ_Result(); - - // The first line holds the column names, data returned is in column/row format - $columns = explode("\t", trim($buffer->readString("\n")), 16); - - // Loop thru the rows until we run out of information - while($buffer->getLength()) - { - // Grab the row, which is a tabbed list of items - // Check for end of packet - if(($row = trim($buffer->readString("\n"))) == 'OK') - { - break; - } - - // Explode and merge the data with the columns, then parse - $data = array_combine($columns, explode("\t", $row, 16)); - - foreach($data AS $key => $value) - { - // Now add the data to the result - $result->addPlayer($key, $value); - } - } - - unset($data, $buffer, $row, $columns, $key, $value); - - return $result->fetch(); - } - - - /** - * Verify the header of the returned response packet - * - * @param GameQ_Buffer $buffer - * @throws GameQ_ProtocolsException - */ - protected function verify_header(GameQ_Buffer &$buffer) - { - // Check length - if($buffer->getLength() < 6) - { - throw new GameQ_ProtocolsException(__METHOD__.": Length of buffer is not long enough"); - return FALSE; - } - - // Check to make sure the header is correct - if(($type = trim($buffer->readString("\n"))) != '[TS]') - { - throw new GameQ_ProtocolsException(__METHOD__.": Header returned did not match. Returned type {$type}"); - return FALSE; - } - - // Verify the response and return - return $this->verify_response(trim($buffer->readString("\n"))); - } - - /** - * Verify the response for the specific entity - * - * @param string $response - * @throws GameQ_ProtocolsException - */ - protected function verify_response($response) - { - // Check the response - if($response != 'OK') - { - throw new GameQ_ProtocolsException(__METHOD__.": Header return response was no 'OK'. Returned response {$response}"); - return FALSE; - } - - return TRUE; - } + unset($data, $buffer, $row, $columns, $key, $value); + } } diff --git a/third_party/gameq_v2/gameq/protocols/teamspeak3.php b/third_party/gameq_v2/gameq/protocols/teamspeak3.php index 097135d8..c66f6a44 100644 --- a/third_party/gameq_v2/gameq/protocols/teamspeak3.php +++ b/third_party/gameq_v2/gameq/protocols/teamspeak3.php @@ -3,395 +3,326 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Server; +use GameQ\Exception\Protocol as Exception; + /** * Teamspeak 3 Protocol Class * - * This class provides some functionality for getting status information for Teamspeak 3 - * servers. + * All values are utf8 encoded upon processing * - * This code ported from GameQ v1. Credit to original author(s) as I just updated it to + * This code ported from GameQ v1/v2. Credit to original author(s) as I just updated it to * work within this new system. * * @author Austin Bischoff */ -class GameQ_Protocols_Teamspeak3 extends GameQ_Protocols +class Teamspeak3 extends Protocol { - /** - * Normalization for this protocol class - * - * @var array - */ - protected $normalize = array( + + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_DETAILS => "use port=%d\x0Aserverinfo\x0A", + self::PACKET_PLAYERS => "use port=%d\x0Aclientlist\x0A", + self::PACKET_CHANNELS => "use port=%d\x0Achannellist -topic\x0A", + ]; + + /** + * The transport mode for this protocol is TCP + * + * @type string + */ + protected $transport = self::TRANSPORT_TCP; + + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'teamspeak3'; + + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'teamspeak3'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Teamspeak 3"; + + /** + * The client join link + * + * @type string + */ + protected $join_link = "ts3server://%s?port=%d"; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ // General - 'general' => array( - 'dedicated' => array('dedicated'), - 'hostname' => array('virtualservername'), - 'password' => array('virtualserverflagpassword'), - //'numplayers' => array('virtualserverclientsonline'), - 'maxplayers' => array('virtualservermaxclients'), - 'players' => array('players'), - 'teams' => array('teams'), - ), - + 'general' => [ + 'dedicated' => 'dedicated', + 'hostname' => 'virtualserver_name', + 'password' => 'virtualserver_flag_password', + 'numplayers' => 'numplayers', + 'maxplayers' => 'virtualserver_maxclients', + ], // Player - 'player' => array( - 'name' => array('clientnickname'), - 'team' => array('clid'), - ), - + 'player' => [ + 'id' => 'clid', + 'team' => 'cid', + 'name' => 'client_nickname', + ], // Team - 'team' => array( - 'name' => array('channelname'), - ), - ); + 'team' => [ + 'id' => 'cid', + 'name' => 'channel_name', + ], + ]; - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_DETAILS => "use port=%d\x0Aserverinfo\x0A", - self::PACKET_PLAYERS => "use port=%d\x0Aclientlist\x0A", - self::PACKET_CHANNELS => "use port=%d\x0Achannellist -topic\x0A", - ); + /** + * Before we send off the queries we need to update the packets + * + * @param \GameQ\Server $server + * + * @throws \GameQ\Exception\Protocol + */ + public function beforeSend(Server $server) + { - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_details", - "process_channels", - "process_players", - ); + // Check to make sure we have a query_port because it is required + if (!isset($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) + || empty($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) + ) { + throw new Exception(__METHOD__ . " Missing required setting '" . Server::SERVER_OPTIONS_QUERY_PORT . "'."); + } - /** - * Default port for this server type - * - * @var int - */ - protected $port = 9987; // Default port, used if not set when instanced + // Let's loop the packets and set the proper pieces + foreach ($this->packets as $packet_type => $packet) { + // Update with the client port for the server + $this->packets[$packet_type] = sprintf($packet, $server->portClient()); + } + } - /** - * Because Teamspeak is run like a master server we have to know what port we are really querying - * - * @var int - */ - protected $master_server_port = 10011; + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { - /** - * We have to use TCP connection - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; + // Make a new buffer out of all of the packets + $buffer = new Buffer(implode('', $this->packets_response)); - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'teamspeak3'; + // Check the header TS3 + if (($header = trim($buffer->readString("\n"))) !== 'TS3') { + throw new Exception(__METHOD__ . " Expected header '{$header}' does not match expected 'TS3'."); + } - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'teamspeak3'; + // Convert all the escaped characters + $raw = str_replace( + [ + '\\\\', // Translate escaped \ + '\\/', // Translate escaped / + ], + [ + '\\', + '/', + ], + $buffer->getBuffer() + ); - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Teamspeak 3"; + // Explode the sections and filter to remove empty, junk ones + $sections = array_filter(explode("\n", $raw), function ($value) { - protected $join_link = "ts3server://%s?port=%d"; + $value = trim($value); - /** - * Define the items being replaced to fix the return - * - * @var array - */ - protected $string_replace = array( - "\\\\" => "\\", - "\\/" => "/", - "\\s" => " ", - "\\p" => "|", - "\\;" => ";", - "\\a" => "\a", - "\\b" => "\b", - "\\f" => "\f", - "\\n" => "\n", - "\\r" => "\r", - "\\t" => "\t" - ); + // Not empty string or a message response for "error id=\d" + return !empty($value) && substr($value, 0, 5) !== 'error'; + }); - /** - * Overload so we can check for some special options - * - * @param string $ip - * @param int $port - * @param array $options - */ - public function __construct($ip = FALSE, $port = FALSE, $options = array()) - { - // Got to do this first - parent::__construct($ip, $port, $options); + // Trim up the values to remove extra whitespace + $sections = array_map('trim', $sections); - // Check for override in master server port (query) - if(isset($this->options['master_server_port']) && !empty($this->options['master_server_port'])) - { - // Override the master server port - $this->master_server_port = (int) $this->options['master_server_port']; - } - } + // Set the result to a new result instance + $result = new Result(); - /** - * We need to affect the packets we are sending before they are sent - * - * @see GameQ_Protocols_Core::beforeSend() - */ - public function beforeSend() - { - // Let's loop the packets and set the proper pieces - foreach($this->packets AS $packet_type => $packet) - { - // Update the query port for the server - $this->packets[$packet_type] = sprintf($packet, $this->port); - } + // Iterate over the sections and offload the parsing + foreach ($sections as $section) { + // Grab a snip of the data so we can figure out what it is + $check = substr(trim($section), 0, 4); - // Set the port we are connecting to the master port - $this->port = $this->master_server_port; + // Use the first part of the response to figure out where we need to go + if ($check == 'virt') { + // Server info + $this->processDetails($section, $result); + } elseif ($check == 'cid=') { + // Channels + $this->processChannels($section, $result); + } elseif ($check == 'clid') { + // Clients (players) + $this->processPlayers($section, $result); + } + } - return TRUE; - } + unset($buffer, $sections, $section, $check); + return $result->fetch(); + } /* * Internal methods */ - protected function preProcess($packets=array()) - { - // Create a buffer - $buffer = new GameQ_Buffer(implode("", $packets)); + /** + * Process the properties of the data. + * + * Takes data in "key1=value1 key2=value2 ..." and processes it into a usable format + * + * @param $data + * + * @return array + */ + protected function processProperties($data) + { - // Verify the header - $this->verify_header($buffer); + // Will hold the properties we are sending back + $properties = []; - return $buffer; - } + // All of these are split on space + $items = explode(' ', $data); + + // Iterate over the items + foreach ($items as $item) { + // Explode and make sure we always have 2 items in the array + list($key, $value) = array_pad(explode('=', $item, 2), 2, ''); + + // Convert spaces and other character changes + $properties[$key] = utf8_encode(str_replace( + [ + '\\s', // Translate spaces + ], + [ + ' ', + ], + $value + )); + } + + return $properties; + } /** - * Process the server information + * Handles processing the details data into a usable format + * + * @param string $data + * @param \GameQ\Result $result */ - protected function process_details() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_DETAILS)) - { - return array(); - } + protected function processDetails($data, Result &$result) + { - // Let's preprocess the status - $buffer = $this->preProcess($this->packets_response[self::PACKET_DETAILS]); + // Offload the parsing for these values + $properties = $this->processProperties($data); - // Process the buffer response - $data = $this->parse_response($buffer); + // Always dedicated + $result->add('dedicated', 1); - // Shift off the first item - $data = array_shift($data); + // Iterate over the properties + foreach ($properties as $key => $value) { + $result->add($key, $value); + } - // Set the result to a new result instance - $result = new GameQ_Result(); + // We need to manually figure out the number of players + $result->add( + 'numplayers', + ($properties['virtualserver_clientsonline'] - $properties['virtualserver_queryclientsonline']) + ); - // Always dedicated - $result->add('dedicated', TRUE); + unset($data, $properties, $key, $value); + } - // Loop the data and add it to the result - foreach($data AS $key => $value) - { - $result->add($key, $value); - } + /** + * Process the channel listing + * + * @param string $data + * @param \GameQ\Result $result + */ + protected function processChannels($data, Result &$result) + { - // Do correction for virtual clients - $result->add('numplayers', ($data['virtualserver_clientsonline'] - $data['virtualserver_queryclientsonline'])); + // We need to split the data at the pipe + $channels = explode('|', $data); - unset($data, $buffer, $key, $value); + // Iterate over the channels + foreach ($channels as $channel) { + // Offload the parsing for these values + $properties = $this->processProperties($channel); - return $result->fetch(); - } + // Iterate over the properties + foreach ($properties as $key => $value) { + $result->addTeam($key, $value); + } + } - /** - * Process the channel listing - */ - protected function process_channels() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_CHANNELS)) - { - return array(); - } + unset($data, $channel, $channels, $properties, $key, $value); + } - // Let's preprocess the status - $buffer = $this->preProcess($this->packets_response[self::PACKET_CHANNELS]); + /** + * Process the user listing + * + * @param string $data + * @param \GameQ\Result $result + */ + protected function processPlayers($data, Result &$result) + { - // Process the buffer response - $data = $this->parse_response($buffer); + // We need to split the data at the pipe + $players = explode('|', $data); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Iterate over the channels + foreach ($players as $player) { + // Offload the parsing for these values + $properties = $this->processProperties($player); - foreach ($data AS $channel) - { - $channel['channel_name'] = htmlentities($channel['channel_name'], ENT_QUOTES, "UTF-8"); - foreach ($channel AS $key => $value) - { - $result->addTeam($key, $value); - } - } + // Iterate over the properties + foreach ($properties as $key => $value) { + $result->addPlayer($key, $value); + } + } - unset($data, $buffer, $channel, $key, $value); - - return $result->fetch(); - } - - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } - - // Let's preprocess the status - $buffer = $this->preProcess($this->packets_response[self::PACKET_PLAYERS]); - - // Process the buffer response - $data = $this->parse_response($buffer); - - // Set the result to a new result instance - $result = new GameQ_Result(); - - foreach ($data AS $player) - { - // filter out query clients - if ($player['client_type'] == 1) - { - continue; - } - - $player['client_nickname'] = htmlentities($player['client_nickname'], ENT_QUOTES, "UTF-8"); - foreach ($player AS $key => $value) - { - $result->addPlayer($key, $value); - } - } - - unset($data, $buffer, $player, $key, $value); - - return $result->fetch(); - } - - - /** - * Verify the header of the returned response packet - * - * @param GameQ_Buffer $buffer - * @throws GameQ_ProtocolsException - */ - protected function verify_header(GameQ_Buffer &$buffer) - { - // Check length - if($buffer->getLength() < 6) - { - throw new GameQ_ProtocolsException(__METHOD__.": Length of buffer is not long enough"); - return FALSE; - } - - // Check to make sure the header is correct - if(($type = $buffer->readString("\n")) != 'TS3') - { - throw new GameQ_ProtocolsException(__METHOD__.": Header returned did not match. Returned {$type}"); - return FALSE; - } - - // Burn the welcome msg - $buffer->readString("\n"); - - // Verify the response and return - return $this->verify_response(trim($buffer->readString("\n"))); - } - - /** - * Verify the response for the specific entity - * - * @param string $response - * @throws GameQ_ProtocolsException - */ - protected function verify_response($response) - { - // Check the response - if($response != 'error id=0 msg=ok') - { - throw new GameQ_ProtocolsException(__METHOD__.": Header response was not ok. Response {$response}"); - return FALSE; - } - - return TRUE; - } - - /** - * Parse the buffer response into an array and return it - * - * @param GameQ_Buffer $buffer - */ - protected function parse_response(GameQ_Buffer &$buffer) - { - // The data is in the first block - $data = explode ('|', trim($buffer->readString("\n"))); - - // The response is the last block - $this->verify_response(trim($buffer->readString("\n"))); - - $return = array(); - - foreach ($data as $part) - { - $variables = explode (' ', $part); - - $info = array(); - - foreach ($variables as $variable) - { - // Explode and make sure we always have 2 items in the array - list($key, $value) = array_pad(explode('=', $variable, 2), 2, ''); - - $info[$key] = str_replace(array_keys($this->string_replace), array_values($this->string_replace), $value); - } - - // Add this to the return - $return[] = $info; - } - - return $return; - } + unset($data, $player, $players, $properties, $key, $value); + } } diff --git a/third_party/gameq_v2/gameq/protocols/teeworlds.php b/third_party/gameq_v2/gameq/protocols/teeworlds.php index 27e6fd06..1bdaa472 100644 --- a/third_party/gameq_v2/gameq/protocols/teeworlds.php +++ b/third_party/gameq_v2/gameq/protocols/teeworlds.php @@ -1,109 +1,181 @@ . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + /** - * Teeworlds Protocol + * Teeworlds Protocol class * + * Only supports versions > 0.5 + * + * @author Austin Bischoff * @author Marcel Bößendörfer */ -class GameQ_Protocols_Teeworlds extends GameQ_Protocols { +class Teeworlds extends Protocol +{ /** * Array of packets we want to look up. * Each key should correspond to a defined method in this or a parent class * - * @var array + * @type array */ - protected $packets = array( + protected $packets = [ self::PACKET_ALL => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x67\x69\x65\x33\x05", // 0.5 Packet (not compatible, maybe some wants to implement "Teeworldsold") //self::PACKET_STATUS => "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFgief", - ); + ]; /** - * Methods to be run when processing the response(s) + * Use the response flag to figure out what method to run * - * @var array + * @type array */ - protected $process_methods = array( - "process_all" - ); + protected $responses = [ + "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffinf35" => "processAll", + ]; /** - * Default port for this server type + * The query protocol used to make the call * - * @var int - */ - protected $port = 8303; // Default port, used if not set when instanced - - /** - * The protocol being used - * - * @var string + * @type string */ protected $protocol = 'teeworlds'; /** * String name of this protocol class * - * @var string + * @type string */ protected $name = 'teeworlds'; /** * Longer string name of this protocol class * - * @var string + * @type string */ - protected $name_long = "Teeworlds"; + protected $name_long = "Teeworlds Server"; - /* - * Internal methods + /** + * The client join link + * + * @type string */ + protected $join_link = "steam://connect/%s:%d/"; - protected function process_all() { - if(!$this->hasValidResponse(self::PACKET_ALL)) - { - return array(); + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'hostname' => 'hostname', + 'mapname' => 'map', + 'maxplayers' => 'num_players_total', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'score' => 'score', + ], + ]; + + /** + * Process the response + * + * @return array + * @throws Exception + */ + public function processResponse() + { + // Holds the results + $results = []; + + // Iterate over the packets + foreach ($this->packets_response as $response) { + // Make a buffer + $buffer = new Buffer($response); + + // Grab the header + $header = $buffer->readString(); + + // Figure out which packet response this is + if (!array_key_exists($header, $this->responses)) { + throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); + } + + // Now we need to call the proper method + $results = array_merge( + $results, + call_user_func_array([$this, $this->responses[$header]], [$buffer]) + ); } - $data = $this->packets_response[self::PACKET_ALL][0]; - $buf = new GameQ_Buffer($data); - $result = new GameQ_Result(); - $buf->readString(); - $result->add('version', $buf->readString()); - $result->add('hostname', $buf->readString()); - $result->add('map', $buf->readString()); - $result->add('game_descr', $buf->readString()); - $result->add('flags', $buf->readString()); // not use about that - $result->add('num_players', $buf->readString()); - $result->add('maxplayers', $buf->readString()); - $result->add('num_players_total', $buf->readString()); - $result->add('maxplayers_total', $buf->readString()); + + unset($buffer); + + return $results; + } + + /** + * Handle processing all of the data returned + * + * @param Buffer $buffer + * + * @return array + */ + protected function processAll(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); + + // Always dedicated + $result->add('dedicated', 1); + + $result->add('version', $buffer->readString()); + $result->add('hostname', $buffer->readString()); + $result->add('map', $buffer->readString()); + $result->add('game_descr', $buffer->readString()); + $result->add('flags', $buffer->readString()); // not sure about that + $result->add('num_players', $buffer->readString()); + $result->add('maxplayers', $buffer->readString()); + $result->add('num_players_total', $buffer->readString()); + $result->add('maxplayers_total', $buffer->readString()); // Players - while ($buf->getLength()) { - $result->addPlayer('name', $buf->readString()); - $result->addPlayer('clan', $buf->readString()); - $result->addPlayer('flag', $buf->readString()); - $result->addPlayer('score', $buf->readString()); - $result->addPlayer('team', $buf->readString()); + while ($buffer->getLength()) { + $result->addPlayer('name', $buffer->readString()); + $result->addPlayer('clan', $buffer->readString()); + $result->addPlayer('flag', $buffer->readString()); + $result->addPlayer('score', $buffer->readString()); + $result->addPlayer('team', $buffer->readString()); } + + unset($buffer); + return $result->fetch(); } } diff --git a/third_party/gameq_v2/gameq/protocols/terraria.php b/third_party/gameq_v2/gameq/protocols/terraria.php index b1c4fe22..d9455ef5 100644 --- a/third_party/gameq_v2/gameq/protocols/terraria.php +++ b/third_party/gameq_v2/gameq/protocols/terraria.php @@ -3,46 +3,57 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Terraria Protocol Class + * Class Terraria * - * This class utilizes the Tshock protocol + * @package GameQ\Protocols * - * @author Austin Bischoff + * @author Austin Bischoff */ -class GameQ_Protocols_Terraria extends GameQ_Protocols_Tshock +class Terraria extends Tshock { + /** - * Default port for this server type + * String name of this protocol class * - * @var int + * @type string */ - protected $port = 7878; // Default port, used if not set when instanced + protected $name = 'terraria'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'terraria'; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Terraria"; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Terraria"; + /** + * query_port = client_port + 101 + * 7878 = 7777 + 101 + * + * @type int + */ + protected $port_diff = 101; + + /** + * The client join link + * + * @type string + */ + protected $join_link = "steam://connect/%s:%d/"; } diff --git a/third_party/gameq_v2/gameq/protocols/tf2.php b/third_party/gameq_v2/gameq/protocols/tf2.php index 317a1bcb..e08411b7 100644 --- a/third_party/gameq_v2/gameq/protocols/tf2.php +++ b/third_party/gameq_v2/gameq/protocols/tf2.php @@ -3,26 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** - * Team Fortress 2 Protocol Class + * Class Tf2 * + * @package GameQ\Protocols * @author Austin Bischoff */ -class GameQ_Protocols_Tf2 extends GameQ_Protocols_Source +class Tf2 extends Source { - protected $name = "tf2"; - protected $name_long = "Team Fortress 2"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'tf2'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Team Fortress 2"; } diff --git a/third_party/gameq_v2/gameq/protocols/tfc.php b/third_party/gameq_v2/gameq/protocols/tfc.php deleted file mode 100644 index 62e3caba..00000000 --- a/third_party/gameq_v2/gameq/protocols/tfc.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Team Fortress Classic Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Tfc extends GameQ_Protocols_Source -{ - protected $name = "tfc"; - protected $name_long = "Team Fortress Classic"; -} diff --git a/third_party/gameq_v2/gameq/protocols/tribes2.php b/third_party/gameq_v2/gameq/protocols/tribes2.php deleted file mode 100644 index 2748d989..00000000 --- a/third_party/gameq_v2/gameq/protocols/tribes2.php +++ /dev/null @@ -1,204 +0,0 @@ -. - */ - -/** - * Tribes 2 Protocol Class - * - * Code adapted from the original tribes2 class from GameQ v1 - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Tribes2 extends GameQ_Protocols -{ - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_INFO => "\x0E\x02\x01\x02\x03\x04", - self::PACKET_STATUS => "\x12\x02\x01\x02\x03\x04", - ); - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_info", - "process_status", - ); - - /** - * Default port for this server type - * - * @var int - */ - protected $port = 28000; // Default port, used if not set when instanced - - /** - * The query protocol used to make the call - * - * @var string - */ - protected $protocol = 'tribes2'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'tribes2'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Tribes 2"; - - /** - * Pre-process the server info data that was returned. - * - * @param array $packets - */ - protected function preProcess_info($packets) - { - // Process the packets - return implode('', $packets); - } - - /** - * Handles processing the info data into a usable format - * - * @throws GameQ_ProtocolsException - */ - protected function process_info() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_INFO)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Let's preprocess the rules - $data = $this->preProcess_info($this->packets_response[self::PACKET_INFO]); - - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Skip the header - $buf->skip(6); - - $result->add('version', $buf->readPascalString()); - - // We skip this next part but it contains protocol and build information, man I wish I had some docs... - $buf->skip(12); - - $result->add('hostname', $buf->readPascalString()); - - unset($buf, $data); - - return $result->fetch(); - } - - /** - * Pre-process the server status data that was returned. - * - * @param array $packets - */ - protected function preProcess_status($packets) - { - // Process the packets - return implode('', $packets); - } - - /** - * Handles processing the status data into a usable format - * - * @throws GameQ_ProtocolsException - */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Let's preprocess the rules - $data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]); - - // Create a new buffer - $buf = new GameQ_Buffer($data); - - // Skip the header - $buf->skip(6); - - $result->add('mod', $buf->readPascalString()); - $result->add('gametype', $buf->readPascalString()); - $result->add('map', $buf->readPascalString()); - - // Grab the flag - $flag = $buf->read(); - - $bit = 1; - foreach (array('dedicated', 'password', 'linux', - 'tournament', 'no_alias') as $var) - { - $value = ($flag & $bit) ? 1 : 0; - $result->add($var, $value); - $bit *= 2; - } - - $result->add('num_players', $buf->readInt8()); - $result->add('max_players', $buf->readInt8()); - $result->add('num_bots', $buf->readInt8()); - $result->add('cpu', $buf->readInt16()); - $result->add('info', $buf->readPascalString()); - - $buf->skip(2); - - // Do teams - $num_teams = $buf->read(); - $result->add('num_teams', $num_teams); - - $buf->skip(); - - for ($i = 0; $i < $num_teams; $i++) - { - $result->addTeam('name', $buf->readString("\x09")); - $result->addTeam('score', $buf->readString("\x0a")); - } - - // Do players - // @todo: No code here to do players, no docs either, need example server with players - - unset($buf, $data); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v2/gameq/protocols/tshock.php b/third_party/gameq_v2/gameq/protocols/tshock.php index 4e27ac65..551a09e4 100644 --- a/third_party/gameq_v2/gameq/protocols/tshock.php +++ b/third_party/gameq_v2/gameq/protocols/tshock.php @@ -3,18 +3,22 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Exception\Protocol as Exception; +use GameQ\Result; /** * Tshock Protocol Class @@ -29,26 +33,16 @@ * * @author Austin Bischoff */ -abstract class GameQ_Protocols_Tshock extends GameQ_Protocols_Http +class Tshock extends Http { /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class + * Packets to send * * @var array */ - protected $packets = array( - self::PACKET_STATUS => "GET /status HTTP/1.0\r\nAccept: */*\r\n\r\n", - ); - - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); + protected $packets = [ + self::PACKET_STATUS => "GET /v2/server/status?players=true&rules=true HTTP/1.0\r\nAccept: */*\r\n\r\n", + ]; /** * The protocol being used @@ -71,61 +65,93 @@ abstract class GameQ_Protocols_Tshock extends GameQ_Protocols_Http */ protected $name_long = "Tshock"; - /* - * Internal methods + /** + * Normalize some items + * + * @var array */ - protected function preProcess_status($packets=array()) - { - // Implode and rip out the JSON - preg_match('/\{(.*)\}/ms', implode('', $packets), $m); + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'hostname' => 'hostname', + 'mapname' => 'world', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'nickname', + 'team' => 'team', + ], + ]; - return $m[0]; - } - - protected function process_status() + /** + * Process the response + * + * @return array + * @throws Exception + */ + public function processResponse() { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); + if (empty($this->packets_response)) { + return []; } + + // Implode and rip out the JSON + preg_match('/\{(.*)\}/ms', implode('', $this->packets_response), $matches); // Return should be JSON, let's validate - if(($json = json_decode($this->preProcess_status($this->packets_response[self::PACKET_STATUS]))) === NULL) - { - throw new GameQ_ProtocolsException("JSON response from Tshock protocol is invalid."); + if (!isset($matches[0]) || ($json = json_decode($matches[0])) === null) { + throw new Exception("JSON response from Tshock protocol is invalid."); } // Check the status response - if($json->status != 200) - { - throw new GameQ_ProtocolsException("JSON status from Tshock protocol response was '{$json->status}', expected '200'."); + if ($json->status != 200) { + throw new Exception("JSON status from Tshock protocol response was '{$json->status}', expected '200'."); } - // Set the result to a new result instance - $result = new GameQ_Result(); + $result = new Result(); // Server is always dedicated - $result->add('dedicated', TRUE); + $result->add('dedicated', 1); - // No mods, as of yet - $result->add('mod', FALSE); - - // These are the same no matter what mode the server is in + // Add server items $result->add('hostname', $json->name); $result->add('game_port', $json->port); + $result->add('serverversion', $json->serverversion); + $result->add('world', $json->world); + $result->add('uptime', $json->uptime); + $result->add('password', (int)$json->serverpassword); $result->add('numplayers', $json->playercount); - $result->add('maxplayers', 0); + $result->add('maxplayers', $json->maxplayers); - // Players are a comma(space) seperated list - $players = explode(', ', $json->players); - - // Do the players - foreach($players AS $player) - { - $result->addPlayer('name', $player); + // Parse players + foreach ($json->players as $player) { + $result->addPlayer('nickname', $player->nickname); + $result->addPlayer('username', $player->username); + $result->addPlayer('group', $player->group); + $result->addPlayer('active', (int)$player->active); + $result->addPlayer('state', $player->state); + $result->addPlayer('team', $player->team); } + // Make rules into simple array + $rules = []; + + // Parse rules + foreach ($json->rules as $rule => $value) { + // Add rule but convert boolean into int (0|1) + $rules[$rule] = (is_bool($value)) ? (int)$value : $value; + } + + // Add rules + $result->add('rules', $rules); + + unset($rules, $rule, $player, $value); + return $result->fetch(); } } diff --git a/third_party/gameq_v2/gameq/protocols/unreal2.php b/third_party/gameq_v2/gameq/protocols/unreal2.php index dda98ed6..0ef06757 100644 --- a/third_party/gameq_v2/gameq/protocols/unreal2.php +++ b/third_party/gameq_v2/gameq/protocols/unreal2.php @@ -3,300 +3,244 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Buffer; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + /** - * Unreal 2 Protocol Class + * Unreal 2 Protocol class * * @author Austin Bischoff */ -abstract class GameQ_Protocols_Unreal2 extends GameQ_Protocols +class Unreal2 extends Protocol { - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_DETAILS => "\x79\x00\x00\x00\x00", - self::PACKET_RULES => "\x79\x00\x00\x00\x01", - self::PACKET_PLAYERS => "\x79\x00\x00\x00\x02", - ); - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_details", - "process_rules", - "process_players", - ); + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_DETAILS => "\x79\x00\x00\x00\x00", + self::PACKET_RULES => "\x79\x00\x00\x00\x01", + self::PACKET_PLAYERS => "\x79\x00\x00\x00\x02", + ]; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 1; // Default port, used if not set when instanced + /** + * Use the response flag to figure out what method to run + * + * @type array + */ + protected $responses = [ + "\x80\x00\x00\x00\x00" => "processDetails", // 0 + "\x80\x00\x00\x00\x01" => "processRules", // 1 + "\x80\x00\x00\x00\x02" => "processPlayers", // 2 + ]; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'unreal2'; + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'unreal2'; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'unreal2'; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'unreal2'; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Unreal 2"; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Unreal 2"; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'ServerMode', + 'gametype' => 'gametype', + 'hostname' => 'servername', + 'mapname' => 'mapname', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'score' => 'score', + ], + ]; + + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { + + // Will hold the packets after sorting + $packets = []; + + // We need to pre-sort these for split packets so we can do extra work where needed + foreach ($this->packets_response as $response) { + $buffer = new Buffer($response); + + // Pull out the header + $header = $buffer->read(5); + + // Add the packet to the proper section, we will combine later + $packets[$header][] = $buffer->getBuffer(); + } + + unset($buffer); + + $results = []; + + // Now let's iterate and process + foreach ($packets as $header => $packetGroup) { + // Figure out which packet response this is + if (!array_key_exists($header, $this->responses)) { + throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); + } + + // Now we need to call the proper method + $results = array_merge( + $results, + call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))]) + ); + } + + unset($packets); + + return $results; + } /* * Internal methods */ /** - * Preprocess the server details packet(s) + * Handles processing the details data into a usable format * - * @param array $packets + * @param \GameQ\Buffer $buffer + * + * @return mixed + * @throws \GameQ\Exception\Protocol */ - protected function preProcess_details($packets=array()) + protected function processDetails(Buffer $buffer) { - // Only one return so no need for work - if(count($packets) == 1) - { - return substr($packets[0], 5); - } - // Loop all the packets and rip off the header - foreach($packets AS $id => $packet) - { - $packets[$id] = substr($packet, 5); - } + // Set the result to a new result instance + $result = new Result(); - // Return the data appended - return implode('', $packets); + $result->add('serverid', $buffer->readInt32()); // 0 + $result->add('serverip', $buffer->readPascalString(1)); // empty + $result->add('gameport', $buffer->readInt32()); + $result->add('queryport', $buffer->readInt32()); // 0 + $result->add('servername', utf8_encode($buffer->readPascalString(1))); + $result->add('mapname', utf8_encode($buffer->readPascalString(1))); + $result->add('gametype', $buffer->readPascalString(1)); + $result->add('numplayers', $buffer->readInt32()); + $result->add('maxplayers', $buffer->readInt32()); + $result->add('ping', $buffer->readInt32()); // 0 + + unset($buffer); + + return $result->fetch(); } - protected function process_details() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_DETAILS)) - { - return array(); - } + /** + * Handles processing the player data into a usable format + * + * @param \GameQ\Buffer $buffer + * + * @return mixed + */ + protected function processPlayers(Buffer $buffer) + { - // Set the result to a new result instance - $result = new GameQ_Result(); + // Set the result to a new result instance + $result = new Result(); - // Let's preprocess the rules - $data = $this->preProcess_details($this->packets_response[self::PACKET_DETAILS]); + // Parse players + while ($buffer->getLength()) { + // Player id + if (($id = $buffer->readInt32()) !== 0) { + // Add the results + $result->addPlayer('id', $id); + $result->addPlayer('name', utf8_encode($buffer->readPascalString(1))); + $result->addPlayer('ping', $buffer->readInt32()); + $result->addPlayer('score', $buffer->readInt32()); - // Create a buffer - $buf = new GameQ_Buffer($data); + // Skip the next 4, unsure what they are for + $buffer->skip(4); + } + } - $result->add('serverid', $buf->readInt32()); // 0 - $result->add('serverip', $buf->readPascalString(1)); // empty - $result->add('gameport', $buf->readInt32()); - $result->add('queryport', $buf->readInt32()); // 0 - $result->add('servername', $buf->readPascalString(1)); - $result->add('mapname', $buf->readPascalString(1)); - $result->add('gametype', $buf->readPascalString(1)); - $result->add('playercount', $buf->readInt32()); - $result->add('maxplayers', $buf->readInt32()); - $result->add('ping', $buf->readInt32()); // 0 + unset($buffer, $id); - unset($buf); + return $result->fetch(); + } - // Return the result - return $result->fetch(); - } + /** + * Handles processing the rules data into a usable format + * + * @param \GameQ\Buffer $buffer + * + * @return mixed + */ + protected function processRules(Buffer $buffer) + { - /** - * Preprocess the rules packet(s) - * - * @param array $packets - */ - protected function preProcess_rules($packets=array()) - { - // Only one return so no need for work - if(count($packets) == 1) - { - return substr($packets[0], 5); - } + // Set the result to a new result instance + $result = new Result(); - // Loop all the packets and rip off the header - foreach($packets AS $id => $packet) - { - $packets[$id] = substr($packet, 5); - } + // Named values + $inc = -1; + while ($buffer->getLength()) { + // Grab the key + $key = $buffer->readPascalString(1); - // Return the data appended - return implode('', $packets); - } + // Make sure mutators don't overwrite each other + if ($key === 'Mutator') { + $key .= ++$inc; + } - /** - * Process the Rules packet(s) - */ - protected function process_rules() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_RULES)) - { - return array(); - } + $result->add(strtolower($key), utf8_encode($buffer->readPascalString(1))); + } - // Set the result to a new result instance - $result = new GameQ_Result(); + unset($buffer); - // Let's preprocess the rules - $data = $this->preProcess_rules($this->packets_response[self::PACKET_RULES]); - - // Make a new buffer - $buf = new GameQ_Buffer($data); - - // Named values - $i = -1; - while ($buf->getLength()) - { - $key = $buf->readPascalString(1); - - // Make sure mutators don't overwrite each other - if ($key === 'Mutator') - { - $key .= ++$i; - } - - $result->add($key, $buf->readPascalString(1)); - } - - unset($buf, $i, $key); - - // Return the result - return $result->fetch(); - } - - /** - * Preprocess the player packet(s) returned - * - * @param array $packets - */ - protected function preProcess_players($packets=array()) - { - // Only one return so no need for work - if(count($packets) == 1) - { - return substr($packets[0], 5); - } - - // Loop all the packets and rip off the header - foreach($packets AS $id => $packet) - { - $packets[$id] = substr($packet, 5); - } - - // Return the data appended - return implode('', $packets); - } - - /** - * Process the player return data - */ - protected function process_players() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_PLAYERS)) - { - return array(); - } - - // Set the result to a new result instance - $result = new GameQ_Result(); - - // Let's preprocess the rules - $data = $this->preProcess_players($this->packets_response[self::PACKET_PLAYERS]); - - // Make a new buffer - $buf = new GameQ_Buffer($data); - - // Parse players - while ($buf->getLength()) - { - - // Player id - if (($id = $buf->readInt32()) === 0) - { - break; - } - - $result->addPlayer('id', $id); - $result->addPlayer('name', $this->_readUnrealString($buf)); - $result->addPlayer('ping', $buf->readInt32()); - $result->addPlayer('score', $buf->readInt32()); - $buf->skip(4); - } - - unset($buf, $id); - - // Return the result - return $result->fetch(); - } - - /** - * Read an Unreal Engine 2 string - * - * Adapted from original GameQ code - * - * @param GameQ_Buffer $buf - * @return string - */ - private function _readUnrealString(GameQ_Buffer &$buf) - { - // Normal pascal string - if (ord($buf->lookAhead(1)) < 129) - { - return $buf->readPascalString(1); - } - - // UnrealEngine2 color-coded string - $length = ($buf->readInt8() - 128) * 2 - 3; - $encstr = $buf->read($length); - $buf->skip(3); - - // Remove color-code tags - $encstr = preg_replace('~\x5e\\0\x23\\0..~s', '', $encstr); - - // Remove every second character - // The string is UCS-2, this approximates converting to latin-1 - $str = ''; - for ($i = 0, $ii = strlen($encstr); $i < $ii; $i += 2) - { - $str .= $encstr{$i}; - } - - return $str; - } + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/ut.php b/third_party/gameq_v2/gameq/protocols/ut.php index a51285b8..75722ce1 100644 --- a/third_party/gameq_v2/gameq/protocols/ut.php +++ b/third_party/gameq_v2/gameq/protocols/ut.php @@ -3,28 +3,71 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** * Unreal Tournament Protocol Class * * @author Austin Bischoff */ -class GameQ_Protocols_Ut extends GameQ_Protocols_Gamespy +class Ut extends Gamespy { - protected $name = "ut"; - protected $name_long = "Unreal Tournament"; - protected $port = 7778; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'ut'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Unreal Tournament"; + + /** + * query_port = client_port + 1 + * + * @type int + */ + protected $port_diff = 1; + + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + // target => source + 'dedicated' => 'dedicated', + 'gametype' => 'gametype', + 'hostname' => 'hostname', + 'mapname' => 'mapname', + 'maxplayers' => 'maxplayers', + 'numplayers' => 'numplayers', + 'password' => 'password', + ], + // Individual + 'player' => [ + 'name' => 'name', + 'score' => 'frags', + ], + ]; } diff --git a/third_party/gameq_v2/gameq/protocols/ut2004.php b/third_party/gameq_v2/gameq/protocols/ut2004.php index 12ad1cce..953089f9 100644 --- a/third_party/gameq_v2/gameq/protocols/ut2004.php +++ b/third_party/gameq_v2/gameq/protocols/ut2004.php @@ -3,28 +3,40 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** * Unreal Tournament 2004 Protocol Class * * @author Austin Bischoff */ -class GameQ_Protocols_Ut2004 extends GameQ_Protocols_Unreal2 +class Ut2004 extends Unreal2 { - protected $name = "ut2004"; - protected $name_long = "Unreal Tournament 2004"; - protected $port = 7778; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'ut2004'; + + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Unreal Tournament 2004"; } diff --git a/third_party/gameq_v2/gameq/protocols/ut3.php b/third_party/gameq_v2/gameq/protocols/ut3.php index ad2918dd..b55cc340 100644 --- a/third_party/gameq_v2/gameq/protocols/ut3.php +++ b/third_party/gameq_v2/gameq/protocols/ut3.php @@ -3,75 +3,131 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + /** * Unreal Tournament 3 Protocol Class * - * NOTE: The return from UT3 via the GameSpy 3 protocol is anything but consistent. You may - * notice different results even on the same server queried at different times. No real way to fix - * this problem currently. + * Note: The response from UT3 appears to not be consistent. Many times packets are incomplete or there are extra + * "echoes" in the responses. This may cause issues like odd characters showing up in the keys for the player and team + * array responses. Not sure much can be done about it. * * @author Austin Bischoff */ -class GameQ_Protocols_Ut3 extends GameQ_Protocols_Gamespy3 +class Ut3 extends Gamespy3 { - protected $name = "ut3"; - protected $name_long = "Unreal Tournament 3"; - protected $port = 6500; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'ut3'; - /** - * Process all the data at once - * @see GameQ_Protocols_Gamespy3::process_all() - */ - protected function process_all() - { - // Run the parent but we need to change some data - $result = parent::process_all(); + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Unreal Tournament 3"; - // Move some stuff around - $this->move_result($result, 'hostname', 'OwningPlayerName'); - $this->move_result($result, 'p1073741825', 'mapname'); - $this->move_result($result, 'p1073741826', 'gametype'); - $this->move_result($result, 'p1073741827', 'servername'); - $this->move_result($result, 'p1073741828', 'custom_mutators'); - $this->move_result($result, 'gamemode', 'open'); - $this->move_result($result, 's32779', 'gamemode'); - $this->move_result($result, 's0', 'bot_skill'); - $this->move_result($result, 's6', 'pure_server'); - $this->move_result($result, 's7', 'password'); - $this->move_result($result, 's8', 'vs_bots'); - $this->move_result($result, 's10', 'force_respawn'); - $this->move_result($result, 'p268435704', 'frag_limit'); - $this->move_result($result, 'p268435705', 'time_limit'); - $this->move_result($result, 'p268435703', 'numbots'); - $this->move_result($result, 'p268435717', 'stock_mutators'); + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + 'dedicated' => 'bIsDedicated', + 'hostname' => 'hostname', + 'numplayers' => 'numplayers', + ], + ]; + + /** + * Overload the response process so we can make some changes + * + * @return array + */ + public function processResponse() + { + + // Grab the result from the parent + /** @type array $result */ + $result = parent::processResponse(); + + // Move some stuff around + $this->renameResult($result, 'OwningPlayerName', 'hostname'); + $this->renameResult($result, 'p1073741825', 'mapname'); + $this->renameResult($result, 'p1073741826', 'gametype'); + $this->renameResult($result, 'p1073741827', 'servername'); + $this->renameResult($result, 'p1073741828', 'custom_mutators'); + $this->renameResult($result, 'gamemode', 'open'); + $this->renameResult($result, 's32779', 'gamemode'); + $this->renameResult($result, 's0', 'bot_skill'); + $this->renameResult($result, 's6', 'pure_server'); + $this->renameResult($result, 's7', 'password'); + $this->renameResult($result, 's8', 'vs_bots'); + $this->renameResult($result, 's10', 'force_respawn'); + $this->renameResult($result, 'p268435704', 'frag_limit'); + $this->renameResult($result, 'p268435705', 'time_limit'); + $this->renameResult($result, 'p268435703', 'numbots'); + $this->renameResult($result, 'p268435717', 'stock_mutators'); // Put custom mutators into an array - if(isset($result['custom_mutators'])) - { + if (isset($result['custom_mutators'])) { $result['custom_mutators'] = explode("\x1c", $result['custom_mutators']); } // Delete some unknown stuff - $this->delete_result($result, array('s1','s9','s11','s12','s13','s14')); + $this->deleteResult($result, ['s1', 's9', 's11', 's12', 's13', 's14']); - // Return the result - return $result; - } + // Return the result + return $result; + } - // UT3 Hack, yea I know it doesnt belong here. UT3 is such a mess it needs its own version of GSv3 - //$data = str_replace(array("\x00p1073741829\x00", "p1073741829\x00", "p268435968\x00"), '', $data); + /** + * Dirty hack to rename result entries into something more useful + * + * @param array $result + * @param string $old + * @param string $new + */ + protected function renameResult(array &$result, $old, $new) + { + + // Check to see if the old item is there + if (isset($result[$old])) { + $result[$new] = $result[$old]; + unset($result[$old]); + } + } + + /** + * Dirty hack to delete result items + * + * @param array $result + * @param array $array + */ + protected function deleteResult(array &$result, array $array) + { + + foreach ($array as $key) { + unset($result[$key]); + } + } } diff --git a/third_party/gameq_v2/gameq/protocols/ventrilo.php b/third_party/gameq_v2/gameq/protocols/ventrilo.php index 12671219..6986bedc 100644 --- a/third_party/gameq_v2/gameq/protocols/ventrilo.php +++ b/third_party/gameq_v2/gameq/protocols/ventrilo.php @@ -3,400 +3,875 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Protocol; +use GameQ\Result; +use GameQ\Exception\Protocol as Exception; + /** * Ventrilo Protocol Class * - * This class provides some functionality for getting status information for ventrilo - * servers. Note that a password is not required for versions >= 3.0.3 + * Note that a password is not required for versions >= 3.0.3 * - * This code ported from GameQ v1. Credit to original author(s) as I just updated it to + * All values are utf8 encoded upon processing + * + * This code ported from GameQ v1/v2. Credit to original author(s) as I just updated it to * work within this new system. * * @author Austin Bischoff */ -class GameQ_Protocols_Ventrilo extends GameQ_Protocols +class Ventrilo extends Protocol { - /** - * Normalization for this protocol class - * - * @var array - */ - protected $normalize = array( - // General - 'general' => array( - 'dedicated' => array('dedicated'), - 'hostname' => array('name'), - 'password' => array('auth'), - 'numplayers' => array('clientcount'), - 'maxplayers' => array('maxclients'), - 'players' => array('players'), - 'teams' => array('teams'), - ), - // Player - 'player' => array( - //'score' => array('score'), - ), + /** + * Array of packets we want to look up. + * Each key should correspond to a defined method in this or a parent class + * + * @type array + */ + protected $packets = [ + self::PACKET_ALL => + "V\xc8\xf4\xf9`\xa2\x1e\xa5M\xfb\x03\xccQN\xa1\x10\x95\xaf\xb2g\x17g\x812\xfbW\xfd\x8e\xd2\x22r\x034z\xbb\x98", + ]; - // Team - 'team' => array( - //'score' => array('tickets'), - ), - ); + /** + * The query protocol used to make the call + * + * @type string + */ + protected $protocol = 'ventrilo'; - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @var array - */ - protected $packets = array( - self::PACKET_STATUS => "V\xc8\xf4\xf9`\xa2\x1e\xa5M\xfb\x03\xccQN\xa1\x10\x95\xaf\xb2g\x17g\x812\xfbW\xfd\x8e\xd2\x22r\x034z\xbb\x98", - ); + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'ventrilo'; - /** - * Methods to be run when processing the response(s) - * - * @var array - */ - protected $process_methods = array( - "process_status", - ); + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Ventrilo"; - /** - * Default port for this server type - * - * @var int - */ - protected $port = 3784; // Default port, used if not set when instanced + /** + * The client join link + * + * @type string + */ + protected $join_link = "ventrilo://%s:%d/"; - /** - * Set to run in linear mode - * - * @var string - */ - protected $packet_mode = self::PACKET_MODE_LINEAR; + /** + * Normalize settings for this protocol + * + * @type array + */ + protected $normalize = [ + // General + 'general' => [ + 'dedicated' => 'dedicated', + 'password' => 'auth', + 'hostname' => 'name', + 'numplayers' => 'clientcount', + 'maxplayers' => 'maxclients', + ], + // Player + 'player' => [ + 'team' => 'cid', + 'name' => 'name', + ], + // Team + 'team' => [ + 'id' => 'cid', + 'name' => 'name', + ], + ]; - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'ventrilo'; + /** + * Encryption table for the header + * + * @type array + */ + private $head_encrypt_table = [ + 0x80, + 0xe5, + 0x0e, + 0x38, + 0xba, + 0x63, + 0x4c, + 0x99, + 0x88, + 0x63, + 0x4c, + 0xd6, + 0x54, + 0xb8, + 0x65, + 0x7e, + 0xbf, + 0x8a, + 0xf0, + 0x17, + 0x8a, + 0xaa, + 0x4d, + 0x0f, + 0xb7, + 0x23, + 0x27, + 0xf6, + 0xeb, + 0x12, + 0xf8, + 0xea, + 0x17, + 0xb7, + 0xcf, + 0x52, + 0x57, + 0xcb, + 0x51, + 0xcf, + 0x1b, + 0x14, + 0xfd, + 0x6f, + 0x84, + 0x38, + 0xb5, + 0x24, + 0x11, + 0xcf, + 0x7a, + 0x75, + 0x7a, + 0xbb, + 0x78, + 0x74, + 0xdc, + 0xbc, + 0x42, + 0xf0, + 0x17, + 0x3f, + 0x5e, + 0xeb, + 0x74, + 0x77, + 0x04, + 0x4e, + 0x8c, + 0xaf, + 0x23, + 0xdc, + 0x65, + 0xdf, + 0xa5, + 0x65, + 0xdd, + 0x7d, + 0xf4, + 0x3c, + 0x4c, + 0x95, + 0xbd, + 0xeb, + 0x65, + 0x1c, + 0xf4, + 0x24, + 0x5d, + 0x82, + 0x18, + 0xfb, + 0x50, + 0x86, + 0xb8, + 0x53, + 0xe0, + 0x4e, + 0x36, + 0x96, + 0x1f, + 0xb7, + 0xcb, + 0xaa, + 0xaf, + 0xea, + 0xcb, + 0x20, + 0x27, + 0x30, + 0x2a, + 0xae, + 0xb9, + 0x07, + 0x40, + 0xdf, + 0x12, + 0x75, + 0xc9, + 0x09, + 0x82, + 0x9c, + 0x30, + 0x80, + 0x5d, + 0x8f, + 0x0d, + 0x09, + 0xa1, + 0x64, + 0xec, + 0x91, + 0xd8, + 0x8a, + 0x50, + 0x1f, + 0x40, + 0x5d, + 0xf7, + 0x08, + 0x2a, + 0xf8, + 0x60, + 0x62, + 0xa0, + 0x4a, + 0x8b, + 0xba, + 0x4a, + 0x6d, + 0x00, + 0x0a, + 0x93, + 0x32, + 0x12, + 0xe5, + 0x07, + 0x01, + 0x65, + 0xf5, + 0xff, + 0xe0, + 0xae, + 0xa7, + 0x81, + 0xd1, + 0xba, + 0x25, + 0x62, + 0x61, + 0xb2, + 0x85, + 0xad, + 0x7e, + 0x9d, + 0x3f, + 0x49, + 0x89, + 0x26, + 0xe5, + 0xd5, + 0xac, + 0x9f, + 0x0e, + 0xd7, + 0x6e, + 0x47, + 0x94, + 0x16, + 0x84, + 0xc8, + 0xff, + 0x44, + 0xea, + 0x04, + 0x40, + 0xe0, + 0x33, + 0x11, + 0xa3, + 0x5b, + 0x1e, + 0x82, + 0xff, + 0x7a, + 0x69, + 0xe9, + 0x2f, + 0xfb, + 0xea, + 0x9a, + 0xc6, + 0x7b, + 0xdb, + 0xb1, + 0xff, + 0x97, + 0x76, + 0x56, + 0xf3, + 0x52, + 0xc2, + 0x3f, + 0x0f, + 0xb6, + 0xac, + 0x77, + 0xc4, + 0xbf, + 0x59, + 0x5e, + 0x80, + 0x74, + 0xbb, + 0xf2, + 0xde, + 0x57, + 0x62, + 0x4c, + 0x1a, + 0xff, + 0x95, + 0x6d, + 0xc7, + 0x04, + 0xa2, + 0x3b, + 0xc4, + 0x1b, + 0x72, + 0xc7, + 0x6c, + 0x82, + 0x60, + 0xd1, + 0x0d, + ]; - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'ventrilo'; + /** + * Encryption table for the data + * + * @type array + */ + private $data_encrypt_table = [ + 0x82, + 0x8b, + 0x7f, + 0x68, + 0x90, + 0xe0, + 0x44, + 0x09, + 0x19, + 0x3b, + 0x8e, + 0x5f, + 0xc2, + 0x82, + 0x38, + 0x23, + 0x6d, + 0xdb, + 0x62, + 0x49, + 0x52, + 0x6e, + 0x21, + 0xdf, + 0x51, + 0x6c, + 0x76, + 0x37, + 0x86, + 0x50, + 0x7d, + 0x48, + 0x1f, + 0x65, + 0xe7, + 0x52, + 0x6a, + 0x88, + 0xaa, + 0xc1, + 0x32, + 0x2f, + 0xf7, + 0x54, + 0x4c, + 0xaa, + 0x6d, + 0x7e, + 0x6d, + 0xa9, + 0x8c, + 0x0d, + 0x3f, + 0xff, + 0x6c, + 0x09, + 0xb3, + 0xa5, + 0xaf, + 0xdf, + 0x98, + 0x02, + 0xb4, + 0xbe, + 0x6d, + 0x69, + 0x0d, + 0x42, + 0x73, + 0xe4, + 0x34, + 0x50, + 0x07, + 0x30, + 0x79, + 0x41, + 0x2f, + 0x08, + 0x3f, + 0x42, + 0x73, + 0xa7, + 0x68, + 0xfa, + 0xee, + 0x88, + 0x0e, + 0x6e, + 0xa4, + 0x70, + 0x74, + 0x22, + 0x16, + 0xae, + 0x3c, + 0x81, + 0x14, + 0xa1, + 0xda, + 0x7f, + 0xd3, + 0x7c, + 0x48, + 0x7d, + 0x3f, + 0x46, + 0xfb, + 0x6d, + 0x92, + 0x25, + 0x17, + 0x36, + 0x26, + 0xdb, + 0xdf, + 0x5a, + 0x87, + 0x91, + 0x6f, + 0xd6, + 0xcd, + 0xd4, + 0xad, + 0x4a, + 0x29, + 0xdd, + 0x7d, + 0x59, + 0xbd, + 0x15, + 0x34, + 0x53, + 0xb1, + 0xd8, + 0x50, + 0x11, + 0x83, + 0x79, + 0x66, + 0x21, + 0x9e, + 0x87, + 0x5b, + 0x24, + 0x2f, + 0x4f, + 0xd7, + 0x73, + 0x34, + 0xa2, + 0xf7, + 0x09, + 0xd5, + 0xd9, + 0x42, + 0x9d, + 0xf8, + 0x15, + 0xdf, + 0x0e, + 0x10, + 0xcc, + 0x05, + 0x04, + 0x35, + 0x81, + 0xb2, + 0xd5, + 0x7a, + 0xd2, + 0xa0, + 0xa5, + 0x7b, + 0xb8, + 0x75, + 0xd2, + 0x35, + 0x0b, + 0x39, + 0x8f, + 0x1b, + 0x44, + 0x0e, + 0xce, + 0x66, + 0x87, + 0x1b, + 0x64, + 0xac, + 0xe1, + 0xca, + 0x67, + 0xb4, + 0xce, + 0x33, + 0xdb, + 0x89, + 0xfe, + 0xd8, + 0x8e, + 0xcd, + 0x58, + 0x92, + 0x41, + 0x50, + 0x40, + 0xcb, + 0x08, + 0xe1, + 0x15, + 0xee, + 0xf4, + 0x64, + 0xfe, + 0x1c, + 0xee, + 0x25, + 0xe7, + 0x21, + 0xe6, + 0x6c, + 0xc6, + 0xa6, + 0x2e, + 0x52, + 0x23, + 0xa7, + 0x20, + 0xd2, + 0xd7, + 0x28, + 0x07, + 0x23, + 0x14, + 0x24, + 0x3d, + 0x45, + 0xa5, + 0xc7, + 0x90, + 0xdb, + 0x77, + 0xdd, + 0xea, + 0x38, + 0x59, + 0x89, + 0x32, + 0xbc, + 0x00, + 0x3a, + 0x6d, + 0x61, + 0x4e, + 0xdb, + 0x29, + ]; - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Ventrilo"; + /** + * Process the response + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + public function processResponse() + { - protected $join_link = "ventrilo://%s:%d/"; + // We need to decrypt the packets + $decrypted = $this->decryptPackets($this->packets_response); - /** - * Encryption table for the header - * - * @var array - */ - protected $head_encrypt_table = array( - 0x80, 0xe5, 0x0e, 0x38, 0xba, 0x63, 0x4c, 0x99, 0x88, 0x63, 0x4c, 0xd6, 0x54, 0xb8, 0x65, 0x7e, - 0xbf, 0x8a, 0xf0, 0x17, 0x8a, 0xaa, 0x4d, 0x0f, 0xb7, 0x23, 0x27, 0xf6, 0xeb, 0x12, 0xf8, 0xea, - 0x17, 0xb7, 0xcf, 0x52, 0x57, 0xcb, 0x51, 0xcf, 0x1b, 0x14, 0xfd, 0x6f, 0x84, 0x38, 0xb5, 0x24, - 0x11, 0xcf, 0x7a, 0x75, 0x7a, 0xbb, 0x78, 0x74, 0xdc, 0xbc, 0x42, 0xf0, 0x17, 0x3f, 0x5e, 0xeb, - 0x74, 0x77, 0x04, 0x4e, 0x8c, 0xaf, 0x23, 0xdc, 0x65, 0xdf, 0xa5, 0x65, 0xdd, 0x7d, 0xf4, 0x3c, - 0x4c, 0x95, 0xbd, 0xeb, 0x65, 0x1c, 0xf4, 0x24, 0x5d, 0x82, 0x18, 0xfb, 0x50, 0x86, 0xb8, 0x53, - 0xe0, 0x4e, 0x36, 0x96, 0x1f, 0xb7, 0xcb, 0xaa, 0xaf, 0xea, 0xcb, 0x20, 0x27, 0x30, 0x2a, 0xae, - 0xb9, 0x07, 0x40, 0xdf, 0x12, 0x75, 0xc9, 0x09, 0x82, 0x9c, 0x30, 0x80, 0x5d, 0x8f, 0x0d, 0x09, - 0xa1, 0x64, 0xec, 0x91, 0xd8, 0x8a, 0x50, 0x1f, 0x40, 0x5d, 0xf7, 0x08, 0x2a, 0xf8, 0x60, 0x62, - 0xa0, 0x4a, 0x8b, 0xba, 0x4a, 0x6d, 0x00, 0x0a, 0x93, 0x32, 0x12, 0xe5, 0x07, 0x01, 0x65, 0xf5, - 0xff, 0xe0, 0xae, 0xa7, 0x81, 0xd1, 0xba, 0x25, 0x62, 0x61, 0xb2, 0x85, 0xad, 0x7e, 0x9d, 0x3f, - 0x49, 0x89, 0x26, 0xe5, 0xd5, 0xac, 0x9f, 0x0e, 0xd7, 0x6e, 0x47, 0x94, 0x16, 0x84, 0xc8, 0xff, - 0x44, 0xea, 0x04, 0x40, 0xe0, 0x33, 0x11, 0xa3, 0x5b, 0x1e, 0x82, 0xff, 0x7a, 0x69, 0xe9, 0x2f, - 0xfb, 0xea, 0x9a, 0xc6, 0x7b, 0xdb, 0xb1, 0xff, 0x97, 0x76, 0x56, 0xf3, 0x52, 0xc2, 0x3f, 0x0f, - 0xb6, 0xac, 0x77, 0xc4, 0xbf, 0x59, 0x5e, 0x80, 0x74, 0xbb, 0xf2, 0xde, 0x57, 0x62, 0x4c, 0x1a, - 0xff, 0x95, 0x6d, 0xc7, 0x04, 0xa2, 0x3b, 0xc4, 0x1b, 0x72, 0xc7, 0x6c, 0x82, 0x60, 0xd1, 0x0d, - ); + // Now let us convert special characters from hex to ascii all at once + $decrypted = preg_replace_callback( + '|%([0-9A-F]{2})|', + function ($matches) { - /** - * Encryption table for the data - * - * @var array - */ - protected $data_encrypt_table = array( - 0x82, 0x8b, 0x7f, 0x68, 0x90, 0xe0, 0x44, 0x09, 0x19, 0x3b, 0x8e, 0x5f, 0xc2, 0x82, 0x38, 0x23, - 0x6d, 0xdb, 0x62, 0x49, 0x52, 0x6e, 0x21, 0xdf, 0x51, 0x6c, 0x76, 0x37, 0x86, 0x50, 0x7d, 0x48, - 0x1f, 0x65, 0xe7, 0x52, 0x6a, 0x88, 0xaa, 0xc1, 0x32, 0x2f, 0xf7, 0x54, 0x4c, 0xaa, 0x6d, 0x7e, - 0x6d, 0xa9, 0x8c, 0x0d, 0x3f, 0xff, 0x6c, 0x09, 0xb3, 0xa5, 0xaf, 0xdf, 0x98, 0x02, 0xb4, 0xbe, - 0x6d, 0x69, 0x0d, 0x42, 0x73, 0xe4, 0x34, 0x50, 0x07, 0x30, 0x79, 0x41, 0x2f, 0x08, 0x3f, 0x42, - 0x73, 0xa7, 0x68, 0xfa, 0xee, 0x88, 0x0e, 0x6e, 0xa4, 0x70, 0x74, 0x22, 0x16, 0xae, 0x3c, 0x81, - 0x14, 0xa1, 0xda, 0x7f, 0xd3, 0x7c, 0x48, 0x7d, 0x3f, 0x46, 0xfb, 0x6d, 0x92, 0x25, 0x17, 0x36, - 0x26, 0xdb, 0xdf, 0x5a, 0x87, 0x91, 0x6f, 0xd6, 0xcd, 0xd4, 0xad, 0x4a, 0x29, 0xdd, 0x7d, 0x59, - 0xbd, 0x15, 0x34, 0x53, 0xb1, 0xd8, 0x50, 0x11, 0x83, 0x79, 0x66, 0x21, 0x9e, 0x87, 0x5b, 0x24, - 0x2f, 0x4f, 0xd7, 0x73, 0x34, 0xa2, 0xf7, 0x09, 0xd5, 0xd9, 0x42, 0x9d, 0xf8, 0x15, 0xdf, 0x0e, - 0x10, 0xcc, 0x05, 0x04, 0x35, 0x81, 0xb2, 0xd5, 0x7a, 0xd2, 0xa0, 0xa5, 0x7b, 0xb8, 0x75, 0xd2, - 0x35, 0x0b, 0x39, 0x8f, 0x1b, 0x44, 0x0e, 0xce, 0x66, 0x87, 0x1b, 0x64, 0xac, 0xe1, 0xca, 0x67, - 0xb4, 0xce, 0x33, 0xdb, 0x89, 0xfe, 0xd8, 0x8e, 0xcd, 0x58, 0x92, 0x41, 0x50, 0x40, 0xcb, 0x08, - 0xe1, 0x15, 0xee, 0xf4, 0x64, 0xfe, 0x1c, 0xee, 0x25, 0xe7, 0x21, 0xe6, 0x6c, 0xc6, 0xa6, 0x2e, - 0x52, 0x23, 0xa7, 0x20, 0xd2, 0xd7, 0x28, 0x07, 0x23, 0x14, 0x24, 0x3d, 0x45, 0xa5, 0xc7, 0x90, - 0xdb, 0x77, 0xdd, 0xea, 0x38, 0x59, 0x89, 0x32, 0xbc, 0x00, 0x3a, 0x6d, 0x61, 0x4e, 0xdb, 0x29, - ); + // Pack this into ascii + return pack('H*', $matches[1]); + }, + $decrypted + ); + + // Explode into lines + $lines = explode("\n", $decrypted); + + // Set the result to a new result instance + $result = new Result(); + + // Always dedicated + $result->add('dedicated', 1); + + // Defaults + $channelFields = 5; + $playerFields = 7; + + // Iterate over the lines + foreach ($lines as $line) { + // Trim all the outlying space + $line = trim($line); + + // We dont have anything in this line + if (strlen($line) == 0) { + continue; + } + + /** + * Everything is in this format: ITEM: VALUE + * + * Example: + * ... + * MAXCLIENTS: 175 + * VOICECODEC: 3,Speex + * VOICEFORMAT: 31,32 KHz%2C 16 bit%2C 9 Qlty + * UPTIME: 9167971 + * PLATFORM: Linux-i386 + * VERSION: 3.0.6 + * ... + */ + + // Check to see if we have a colon, every line should + if (($colon_pos = strpos($line, ":")) !== false && $colon_pos > 0) { + // Split the line into key/value pairs + list($key, $value) = explode(':', $line, 2); + + // Lower the font of the key + $key = strtolower($key); + + // Trim the value of extra space + $value = trim($value); + + // Switch and offload items as needed + switch ($key) { + case 'client': + $this->processPlayer($value, $playerFields, $result); + break; + + case 'channel': + $this->processChannel($value, $channelFields, $result); + break; + + // Find the number of fields for the channels + case 'channelfields': + $channelFields = count(explode(',', $value)); + break; + + // Find the number of fields for the players + case 'clientfields': + $playerFields = count(explode(',', $value)); + break; + + // By default we just add they key as an item + default: + $result->add($key, utf8_encode($value)); + break; + } + } + } + + unset($decrypted, $line, $lines, $colon_pos, $key, $value); + + return $result->fetch(); + } /* * Internal methods */ - /** - * Pre-process the server status data that was returned. - * - * @param array $packets - * @throws GameQ_ProtocolsException - */ - public function preProcess_status($packets=array()) - { - $packets_return = array(); + /** + * Decrypt the incoming packets + * + * @codeCoverageIgnore + * + * @param array $packets + * + * @return string + * @throws \GameQ\Exception\Protocol + */ + protected function decryptPackets(array $packets = []) + { - foreach ($packets AS $packet) - { - # Header : - $header = substr ($packet, 0, 20); - $header_items = array (); + // This will be returned + $decrypted = []; - $key = array_shift (unpack ("n1", $header)); - $chars = unpack ("C*", substr ($header, 2)); + foreach ($packets as $packet) { + # Header : + $header = substr($packet, 0, 20); - $a1 = $key & 0xFF; - $a2 = $key >> 8; + $header_items = []; - if ($a1 == 0) - { - throw new GameQ_ProtocolsException(__METHOD__.": Header key is invalid"); - } + $header_key = unpack("n1", $header); - $table = $this->head_encrypt_table; + $key = array_shift($header_key); + $chars = unpack("C*", substr($header, 2)); - $key = 0; - for( $i = 1; $i <= count( $chars ); $i++ ) - { - $chars[$i] -= ( $table[$a2] + (( $i - 1 ) % 5 )) & 0xFF; - $a2 = ($a2 + $a1) & 0xFF; - if ( ( $i % 2 ) == 0 ) - { - $short_array = unpack( "n1", pack( "C2", $chars[$i - 1], $chars[$i] )); - $header_items[$key] = $short_array[1]; - ++$key; - } - } + $a1 = $key & 0xFF; + $a2 = $key >> 8; - $header_items = array_combine(array( - 'zero', - 'cmd', - 'id', - 'totlen', - 'len', - 'totpck', - 'pck', - 'datakey', - 'crc' - ), $header_items); + if ($a1 == 0) { + throw new Exception(__METHOD__ . ": Header key is invalid"); + } - // Check to make sure the number of packets match - if ($header_items['totpck'] != count($packets)) - { - throw new GameQ_ProtocolsException(__METHOD__.": Too less packets recieved"); - } + $table = $this->head_encrypt_table; - # Data : - $table = $this->data_encrypt_table; + $characterCount = count($chars); - $a1 = $header_items['datakey'] & 0xFF; - $a2 = $header_items['datakey'] >> 8; + $key = 0; + for ($index = 1; $index <= $characterCount; $index++) { + $chars[$index] -= ($table[$a2] + (($index - 1) % 5)) & 0xFF; + $a2 = ($a2 + $a1) & 0xFF; + if (($index % 2) == 0) { + $short_array = unpack("n1", pack("C2", $chars[$index - 1], $chars[$index])); + $header_items[$key] = $short_array[1]; + ++$key; + } + } - if ( $a1 == 0 ) - { - throw new GameQ_ProtocolsException(__METHOD__.": Data key is invalid"); - } + $header_items = array_combine([ + 'zero', + 'cmd', + 'id', + 'totlen', + 'len', + 'totpck', + 'pck', + 'datakey', + 'crc', + ], $header_items); - $chars = unpack( "C*", substr ($packet, 20) ); - $data = ""; - for( $i = 1; $i <= count( $chars ); $i++ ) - { - $chars[$i] -= ($table[$a2] + (( $i - 1 ) % 72 )) & 0xFF; - $a2 = ($a2 + $a1) & 0xFF; - $data .= chr($chars[$i]); - } + // Check to make sure the number of packets match + if ($header_items['totpck'] != count($packets)) { + throw new Exception(__METHOD__ . ": Too few packets received"); + } - //@todo: Check CRC ??? + # Data : + $table = $this->data_encrypt_table; + $a1 = $header_items['datakey'] & 0xFF; + $a2 = $header_items['datakey'] >> 8; - $packets_return[$header_items['pck']] = $data; - } + if ($a1 == 0) { + throw new Exception(__METHOD__ . ": Data key is invalid"); + } - return implode('', $packets_return); - } + $chars = unpack("C*", substr($packet, 20)); + $data = ""; + $characterCount = count($chars); + + for ($index = 1; $index <= $characterCount; $index++) { + $chars[$index] -= ($table[$a2] + (($index - 1) % 72)) & 0xFF; + $a2 = ($a2 + $a1) & 0xFF; + $data .= chr($chars[$index]); + } + //@todo: Check CRC ??? + $decrypted[$header_items['pck']] = $data; + } + + // Return the decrypted packets as one string + return implode('', $decrypted); + } /** - * Process the server status information + * Process the channel listing * - * @throws GameQ_ProtocolsException + * @param string $data + * @param int $fieldCount + * @param \GameQ\Result $result */ - protected function process_status() - { - // Make sure we have a valid response - if(!$this->hasValidResponse(self::PACKET_STATUS)) - { - return array(); - } + protected function processChannel($data, $fieldCount, Result &$result) + { - // Let's preprocess the status - $data = $this->preProcess_status($this->packets_response[self::PACKET_STATUS]); + // Split the items on the comma + $items = explode(",", $data, $fieldCount); - // Set the result to a new result instance - $result = new GameQ_Result(); + // Iterate over the items for this channel + foreach ($items as $item) { + // Split the key=value pair + list($key, $value) = explode("=", $item, 2); - // Explode the data into lines - $lines = explode("\n", $data); + $result->addTeam(strtolower($key), utf8_encode($value)); + } + } - // Always dedicated - $result->add('dedicated', TRUE); + /** + * Process the user listing + * + * @param string $data + * @param int $fieldCount + * @param \GameQ\Result $result + */ + protected function processPlayer($data, $fieldCount, Result &$result) + { - // Loop the lines - foreach($lines AS $line) - { - // Trim all the outlying space - $line = trim($line); + // Split the items on the comma + $items = explode(",", $data, $fieldCount); - // We dont have anything in this line - if(strlen($line) == 0) - { - continue; - } + // Iterate over the items for this player + foreach ($items as $item) { + // Split the key=value pair + list($key, $value) = explode("=", $item, 2); - /** - * Everything is in this format: ITEM: VALUE - * - * Example: - * ... - * MAXCLIENTS: 175 - * VOICECODEC: 3,Speex - * VOICEFORMAT: 31,32 KHz%2C 16 bit%2C 9 Qlty - * UPTIME: 9167971 - * PLATFORM: Linux-i386 - * VERSION: 3.0.6 - * ... - */ - - // Check to see if we have a colon, every line should - if(($colon_pos = strpos($line, ":")) !== FALSE && $colon_pos > 0) - { - // Split the line into key/value pairs - list($key, $value) = explode(':', $line, 2); // Only return 2 items in the array incase of colon in $value - - // Lower the font of the key - $key = strtolower($key); - - // Trim the value of extra space - $value = trim($value); - - // Switch and offload items as needed - switch($key) - { - case 'client': - $this->client($value, $result); - break; - - case 'channel': - $this->channel($value, $result); - break; - - // Ignore these - case 'channelfields': - case 'clientfields': - break; - - // By default we just add they key as an item - default: - $result->add($key, $this->convertSpecialChars($value)); - break; - } - } - } - - unset($key, $value, $line, $lines, $data); - - return $result->fetch(); - } - - /** - * Convert the special characters within a value - * - * @param string $data - * @return mixed - */ - protected function convertSpecialChars($data) - { - return preg_replace_callback( - '|%([0-9A-F]{2})|', - create_function( - '$matches', - 'return chr (hexdec ($matches[0]));' - ), - $data); - } - - /** - * Break up the channel items into usable parts - * - * @param string $data - * @param GameQ_Result $result - */ - protected function channel($data, GameQ_Result &$result) - { - $items = explode (",", $data); - foreach ($items as $item) - { - $temp = explode("=", $item); - $key = strtolower($temp[0]); - $value = $temp[1]; - $result->addTeam($key, $this->convertSpecialChars($value)); - } - } - - /** - * Break up the clients into usable parts - * - * @param string $data - * @param GameQ_Result $result - */ - protected function client($data, GameQ_Result &$result) - { - $items = explode(",", $data); - - foreach ($items as $item) - { - $temp = explode("=", $item); - $key = strtolower($temp[0]); - $value = $temp[1]; - $result->addPlayer($key, $this->convertSpecialChars($value)); - } - } + $result->addPlayer(strtolower($key), utf8_encode($value)); + } + } } diff --git a/third_party/gameq_v2/gameq/protocols/warsow.php b/third_party/gameq_v2/gameq/protocols/warsow.php index c23207ec..f1d629a9 100644 --- a/third_party/gameq_v2/gameq/protocols/warsow.php +++ b/third_party/gameq_v2/gameq/protocols/warsow.php @@ -3,69 +3,94 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ\Protocols; + +use GameQ\Buffer; +use GameQ\Result; + /** * Warsow Protocol Class * - * @author Austin Bischoff + * @package GameQ\Protocols + * @author Austin Bischoff */ -class GameQ_Protocols_Warsow extends GameQ_Protocols_Quake3 +class Warsow extends Quake3 { - protected $name = "warsow"; - protected $name_long = "Warsow"; + /** + * String name of this protocol class + * + * @type string + */ + protected $name = 'warsow'; - protected $port = 44400; + /** + * Longer string name of this protocol class + * + * @type string + */ + protected $name_long = "Warsow"; - /** - * Overload the parse players because the data coming back is different - * @see GameQ_Protocols_Quake3::parsePlayers() - */ - protected function parsePlayers(GameQ_Result &$result, $players_info) - { - // Explode the arrays out - $players = explode("\x0A", $players_info); + /** + * The client join link + * + * @type string + */ + protected $join_link = "warsow://%s:%d/"; - // Remove the last array item as it is junk - array_pop($players); + /** + * Handle player info, different than quake3 base + * + * @param Buffer $buffer + * + * @return array + * @throws \GameQ\Exception\Protocol + */ + protected function processPlayers(Buffer $buffer) + { + // Set the result to a new result instance + $result = new Result(); - // Add total number of players - $result->add('num_players', count($players)); + // Loop until we are out of data + while ($buffer->getLength()) { + // Make a new buffer with this block + $playerInfo = new Buffer($buffer->readString("\x0A")); - // Loop the players - foreach($players AS $player_info) - { - $buf = new GameQ_Buffer($player_info); + // Add player info + $result->addPlayer('frags', $playerInfo->readString("\x20")); + $result->addPlayer('ping', $playerInfo->readString("\x20")); - // Add player info - $result->addPlayer('frags', $buf->readString("\x20")); - $result->addPlayer('ping', $buf->readString("\x20")); + // Skip first " + $playerInfo->skip(1); - // Skip first " - $buf->skip(1); + // Add player name, encoded + $result->addPlayer('name', utf8_encode(trim(($playerInfo->readString('"'))))); - // Add player name - $result->addPlayer('name', trim($buf->readString('"'))); + // Skip space + $playerInfo->skip(1); - // Skip space - $buf->skip(1); + // Add team + $result->addPlayer('team', $playerInfo->read()); - // Add team - $result->addPlayer('team', $buf->read()); - } + // Clear + unset($playerInfo); + } - // Free some memory - unset($buf, $players, $player_info); - } + // Clear + unset($buffer); + + return $result->fetch(); + } } diff --git a/third_party/gameq_v2/gameq/protocols/zombiemaster.php b/third_party/gameq_v2/gameq/protocols/zombiemaster.php deleted file mode 100644 index b3d5357f..00000000 --- a/third_party/gameq_v2/gameq/protocols/zombiemaster.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Zombie Master Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Zombiemaster extends GameQ_Protocols_Source -{ - protected $name = "zombiemaster"; - protected $name_long = "Zombie Master"; -} diff --git a/third_party/gameq_v2/gameq/protocols/zps.php b/third_party/gameq_v2/gameq/protocols/zps.php deleted file mode 100644 index 994c3e7a..00000000 --- a/third_party/gameq_v2/gameq/protocols/zps.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -/** - * Zombie Panic Source Protocol Class - * - * @author Austin Bischoff - */ -class GameQ_Protocols_Zps extends GameQ_Protocols_Source -{ - protected $name = "zps"; - protected $name_long = "Zombie Panic Source"; -} diff --git a/third_party/gameq_v3.1/GameQ/Query/Core.php b/third_party/gameq_v2/gameq/query/Core.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Query/Core.php rename to third_party/gameq_v2/gameq/query/Core.php diff --git a/third_party/gameq_v3.1/GameQ/Query/Native.php b/third_party/gameq_v2/gameq/query/Native.php similarity index 100% rename from third_party/gameq_v3.1/GameQ/Query/Native.php rename to third_party/gameq_v2/gameq/query/Native.php diff --git a/third_party/gameq_v2/gameq/result.php b/third_party/gameq_v2/gameq/result.php index 362b0d2b..7023f17a 100644 --- a/third_party/gameq_v2/gameq/result.php +++ b/third_party/gameq_v2/gameq/result.php @@ -3,64 +3,70 @@ * This file is part of GameQ. * * GameQ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by + * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GameQ is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +namespace GameQ; + /** * Provide an interface for easy storage of a parsed server response * * @author Aidan Lister * @author Tom Buskens */ -class GameQ_Result +class Result { + /** * Formatted server response * * @var array */ - protected $result = array(); + protected $result = []; /** * Adds variable to results * - * @param string $name Variable name - * @param string $value Variable value + * @param string $name Variable name + * @param string|array $value Variable value */ public function add($name, $value) { + $this->result[$name] = $value; } /** * Adds player variable to output * - * @param string $name Variable name - * @param string $value Variable value + * @param string $name Variable name + * @param string $value Variable value */ public function addPlayer($name, $value) { + $this->addSub('players', $name, $value); } /** * Adds player variable to output * - * @param string $name Variable name - * @param string $value Variable value + * @param string $name Variable name + * @param string $value Variable value */ public function addTeam($name, $value) { + $this->addSub('teams', $name, $value); } @@ -73,14 +79,16 @@ class GameQ_Result */ public function addSub($sub, $key, $value) { + // Nothing of this type yet, set an empty array if (!isset($this->result[$sub]) or !is_array($this->result[$sub])) { - $this->result[$sub] = array(); + $this->result[$sub] = []; } // Find the first entry that doesn't have this variable $found = false; - for ($i = 0; $i != count($this->result[$sub]); $i++) { + $count = count($this->result[$sub]); + for ($i = 0; $i != $count; $i++) { if (!isset($this->result[$sub][$i][$key])) { $this->result[$sub][$i][$key] = $value; $found = true; @@ -92,26 +100,31 @@ class GameQ_Result if (!$found) { $this->result[$sub][][$key] = $value; } + + unset($count); } /** * Return all stored results * - * @return mixed All results + * @return array All results */ public function fetch() { + return $this->result; } /** * Return a single variable * - * @param string $var The variable name + * @param string $var The variable name + * * @return mixed The variable value */ public function get($var) { + return isset($this->result[$var]) ? $this->result[$var] : null; } } diff --git a/third_party/gameq_v3.1/GameQ/Buffer.php b/third_party/gameq_v3.1/GameQ/Buffer.php deleted file mode 100644 index a080e427..00000000 --- a/third_party/gameq_v3.1/GameQ/Buffer.php +++ /dev/null @@ -1,526 +0,0 @@ -. - * - * - */ - -namespace GameQ; - -use GameQ\Exception\Protocol as Exception; - -/** - * Class Buffer - * - * Read specific byte sequences from a provided string or Buffer - * - * @package GameQ - * - * @author Austin Bischoff - * @author Aidan Lister - * @author Tom Buskens - */ -class Buffer -{ - - /** - * Constants for the byte code types we need to read as - */ - const NUMBER_TYPE_BIGENDIAN = 'be', - NUMBER_TYPE_LITTLEENDIAN = 'le', - NUMBER_TYPE_MACHINE = 'm'; - - /** - * The number type we use for reading integers. Defaults to little endian - * - * @type string - */ - private $number_type = self::NUMBER_TYPE_LITTLEENDIAN; - - /** - * The original data - * - * @type string - */ - private $data; - - /** - * The original data - * - * @type int - */ - private $length; - - /** - * Position of pointer - * - * @type int - */ - private $index = 0; - - /** - * Constructor - * - * @param string $data - * @param string $number_type - */ - public function __construct($data, $number_type = self::NUMBER_TYPE_LITTLEENDIAN) - { - - $this->number_type = $number_type; - $this->data = $data; - $this->length = strlen($data); - } - - /** - * Return all the data - * - * @return string The data - */ - public function getData() - { - - return $this->data; - } - - /** - * Return data currently in the buffer - * - * @return string The data currently in the buffer - */ - public function getBuffer() - { - - return substr($this->data, $this->index); - } - - /** - * Returns the number of bytes in the buffer - * - * @return int Length of the buffer - */ - public function getLength() - { - - return max($this->length - $this->index, 0); - } - - /** - * Read from the buffer - * - * @param int $length - * - * @return string - * @throws \GameQ\Exception\Protocol - */ - public function read($length = 1) - { - - if (($length + $this->index) > $this->length) { - throw new Exception("Unable to read length={$length} from buffer. Bad protocol format or return?"); - } - - $string = substr($this->data, $this->index, $length); - $this->index += $length; - - return $string; - } - - /** - * Read the last character from the buffer - * - * Unlike the other read functions, this function actually removes - * the character from the buffer. - * - * @return string - */ - public function readLast() - { - - $len = strlen($this->data); - $string = $this->data[strlen($this->data) - 1]; - $this->data = substr($this->data, 0, $len - 1); - $this->length -= 1; - - return $string; - } - - /** - * Look at the buffer, but don't remove - * - * @param int $length - * - * @return string - */ - public function lookAhead($length = 1) - { - - return substr($this->data, $this->index, $length); - } - - /** - * Skip forward in the buffer - * - * @param int $length - */ - public function skip($length = 1) - { - - $this->index += $length; - } - - /** - * Jump to a specific position in the buffer, - * will not jump past end of buffer - * - * @param $index - */ - public function jumpto($index) - { - - $this->index = min($index, $this->length - 1); - } - - /** - * Get the current pointer position - * - * @return int - */ - public function getPosition() - { - - return $this->index; - } - - /** - * Read from buffer until delimiter is reached - * - * If not found, return everything - * - * @param string $delim - * - * @return string - * @throws \GameQ\Exception\Protocol - */ - public function readString($delim = "\x00") - { - - // Get position of delimiter - $len = strpos($this->data, $delim, min($this->index, $this->length)); - - // If it is not found then return whole buffer - if ($len === false) { - return $this->read(strlen($this->data) - $this->index); - } - - // Read the string and remove the delimiter - $string = $this->read($len - $this->index); - ++$this->index; - - return $string; - } - - /** - * Reads a pascal string from the buffer - * - * @param int $offset Number of bits to cut off the end - * @param bool $read_offset True if the data after the offset is to be read - * - * @return string - * @throws \GameQ\Exception\Protocol - */ - public function readPascalString($offset = 0, $read_offset = false) - { - - // Get the proper offset - $len = $this->readInt8(); - $offset = max($len - $offset, 0); - - // Read the data - if ($read_offset) { - return $this->read($offset); - } else { - return substr($this->read($len), 0, $offset); - } - } - - /** - * Read from buffer until any of the delimiters is reached - * - * If not found, return everything - * - * @param $delims - * @param null|string &$delimfound - * - * @return string - * @throws \GameQ\Exception\Protocol - * - * @todo: Check to see if this is even used anymore - */ - public function readStringMulti($delims, &$delimfound = null) - { - - // Get position of delimiters - $pos = []; - foreach ($delims as $delim) { - if ($index = strpos($this->data, $delim, min($this->index, $this->length))) { - $pos[] = $index; - } - } - - // If none are found then return whole buffer - if (empty($pos)) { - return $this->read(strlen($this->data) - $this->index); - } - - // Read the string and remove the delimiter - sort($pos); - $string = $this->read($pos[0] - $this->index); - $delimfound = $this->read(); - - return $string; - } - - /** - * Read an 8-bit unsigned integer - * - * @return int - * @throws \GameQ\Exception\Protocol - */ - public function readInt8() - { - - $int = unpack('Cint', $this->read(1)); - - return $int['int']; - } - - /** - * Read and 8-bit signed integer - * - * @return int - * @throws \GameQ\Exception\Protocol - */ - public function readInt8Signed() - { - - $int = unpack('cint', $this->read(1)); - - return $int['int']; - } - - /** - * Read a 16-bit unsigned integer - * - * @return int - * @throws \GameQ\Exception\Protocol - */ - public function readInt16() - { - - // Change the integer type we are looking up - switch ($this->number_type) { - case self::NUMBER_TYPE_BIGENDIAN: - $type = 'nint'; - break; - - case self::NUMBER_TYPE_LITTLEENDIAN: - $type = 'vint'; - break; - - default: - $type = 'Sint'; - } - - $int = unpack($type, $this->read(2)); - - return $int['int']; - } - - /** - * Read a 16-bit signed integer - * - * @return int - * @throws \GameQ\Exception\Protocol - */ - public function readInt16Signed() - { - - // Read the data into a string - $string = $this->read(2); - - // For big endian we need to reverse the bytes - if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) { - $string = strrev($string); - } - - $int = unpack('sint', $string); - - unset($string); - - return $int['int']; - } - - /** - * Read a 32-bit unsigned integer - * - * @return int - * @throws \GameQ\Exception\Protocol - */ - public function readInt32($length = 4) - { - // Change the integer type we are looking up - $littleEndian = null; - switch ($this->number_type) { - case self::NUMBER_TYPE_BIGENDIAN: - $type = 'N'; - $littleEndian = false; - break; - - case self::NUMBER_TYPE_LITTLEENDIAN: - $type = 'V'; - $littleEndian = true; - break; - - default: - $type = 'L'; - } - - // read from the buffer and append/prepend empty bytes for shortened int32 - $corrected = $this->read($length); - - // Unpack the number - $int = unpack($type . 'int', self::extendBinaryString($corrected, 4, $littleEndian)); - - return $int['int']; - } - - /** - * Read a 32-bit signed integer - * - * @return int - * @throws \GameQ\Exception\Protocol - */ - public function readInt32Signed() - { - - // Read the data into a string - $string = $this->read(4); - - // For big endian we need to reverse the bytes - if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) { - $string = strrev($string); - } - - $int = unpack('lint', $string); - - unset($string); - - return $int['int']; - } - - /** - * Read a 64-bit unsigned integer - * - * @return int - * @throws \GameQ\Exception\Protocol - */ - public function readInt64() - { - - // We have the pack 64-bit codes available. See: http://php.net/manual/en/function.pack.php - if (version_compare(PHP_VERSION, '5.6.3') >= 0 && PHP_INT_SIZE == 8) { - // Change the integer type we are looking up - switch ($this->number_type) { - case self::NUMBER_TYPE_BIGENDIAN: - $type = 'Jint'; - break; - - case self::NUMBER_TYPE_LITTLEENDIAN: - $type = 'Pint'; - break; - - default: - $type = 'Qint'; - } - - $int64 = unpack($type, $this->read(8)); - - $int = $int64['int']; - - unset($int64); - } else { - if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) { - $high = $this->readInt32(); - $low = $this->readInt32(); - } else { - $low = $this->readInt32(); - $high = $this->readInt32(); - } - - // We have to determine the number via bitwise - $int = ($high << 32) | $low; - - unset($low, $high); - } - - return $int; - } - - /** - * Read a 32-bit float - * - * @return float - * @throws \GameQ\Exception\Protocol - */ - public function readFloat32() - { - - // Read the data into a string - $string = $this->read(4); - - // For big endian we need to reverse the bytes - if ($this->number_type == self::NUMBER_TYPE_BIGENDIAN) { - $string = strrev($string); - } - - $float = unpack('ffloat', $string); - - unset($string); - - return $float['float']; - } - - private static function extendBinaryString($input, $length = 4, $littleEndian = null) - { - if (is_null($littleEndian)) { - $littleEndian = self::isLittleEndian(); - } - - $extension = str_repeat(pack($littleEndian ? 'V' : 'N', 0b0000), $length - strlen($input)); - - if ($littleEndian) { - return $input . $extension; - } else { - return $extension . $input; - } - } - - private static function isLittleEndian() - { - return 0x00FF === current(unpack('v', pack('S', 0x00FF))); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Armedassault3.php b/third_party/gameq_v3.1/GameQ/Protocols/Armedassault3.php deleted file mode 100644 index 5bbca429..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Armedassault3.php +++ /dev/null @@ -1,32 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Armed assault 3 dummy Protocol Class - * - * Added for backward compatibility, please update to class arma3 - * - * @deprecated v3.0.10 - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Armedassault3 extends Arma3 -{ -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ase.php b/third_party/gameq_v3.1/GameQ/Protocols/Ase.php deleted file mode 100644 index abc47818..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Ase.php +++ /dev/null @@ -1,217 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; - -/** - * All-Seeing Eye Protocol class - * - * @author Marcel Bößendörfer - * @author Austin Bischoff - */ -class Ase extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_ALL => "s", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'ase'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ase'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "All-Seeing Eye"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'gametype', - 'hostname' => 'servername', - 'mapname' => 'map', - 'maxplayers' => 'max_players', - 'mod' => 'game_dir', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'score' => 'score', - 'team' => 'team', - 'ping' => 'ping', - 'time' => 'time', - ], - ]; - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - // Create a new buffer - $buffer = new Buffer(implode('', $this->packets_response)); - - // Check for valid response - if ($buffer->getLength() < 4) { - throw new \GameQ\Exception\Protocol(sprintf('%s The response from the server was empty.', __METHOD__)); - } - - // Read the header - $header = $buffer->read(4); - - // Verify header - if ($header !== 'EYE1') { - throw new \GameQ\Exception\Protocol(sprintf('%s The response header "%s" does not match expected "EYE1"', __METHOD__, $header)); - } - - // Create a new result - $result = new Result(); - - // Variables - $result->add('gamename', $buffer->readPascalString(1, true)); - $result->add('port', $buffer->readPascalString(1, true)); - $result->add('servername', $buffer->readPascalString(1, true)); - $result->add('gametype', $buffer->readPascalString(1, true)); - $result->add('map', $buffer->readPascalString(1, true)); - $result->add('version', $buffer->readPascalString(1, true)); - $result->add('password', $buffer->readPascalString(1, true)); - $result->add('num_players', $buffer->readPascalString(1, true)); - $result->add('max_players', $buffer->readPascalString(1, true)); - $result->add('dedicated', 1); - - // Offload the key/value pair processing - $this->processKeyValuePairs($buffer, $result); - - // Offload processing player and team info - $this->processPlayersAndTeams($buffer, $result); - - unset($buffer); - - return $result->fetch(); - } - - /* - * Internal methods - */ - - /** - * Handles processing the extra key/value pairs for server settings - * - * @param \GameQ\Buffer $buffer - * @param \GameQ\Result $result - */ - protected function processKeyValuePairs(Buffer &$buffer, Result &$result) - { - - // Key / value pairs - while ($buffer->getLength()) { - $key = $buffer->readPascalString(1, true); - - // If we have an empty key, we've reached the end - if (empty($key)) { - break; - } - - // Otherwise, add the pair - $result->add( - $key, - $buffer->readPascalString(1, true) - ); - } - - unset($key); - } - - /** - * Handles processing the player and team data into a usable format - * - * @param \GameQ\Buffer $buffer - * @param \GameQ\Result $result - */ - protected function processPlayersAndTeams(Buffer &$buffer, Result &$result) - { - - // Players and team info - while ($buffer->getLength()) { - // Get the flags - $flags = $buffer->readInt8(); - - // Get data according to the flags - if ($flags & 1) { - $result->addPlayer('name', $buffer->readPascalString(1, true)); - } - if ($flags & 2) { - $result->addPlayer('team', $buffer->readPascalString(1, true)); - } - if ($flags & 4) { - $result->addPlayer('skin', $buffer->readPascalString(1, true)); - } - if ($flags & 8) { - $result->addPlayer('score', $buffer->readPascalString(1, true)); - } - if ($flags & 16) { - $result->addPlayer('ping', $buffer->readPascalString(1, true)); - } - if ($flags & 32) { - $result->addPlayer('time', $buffer->readPascalString(1, true)); - } - } - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Bf2.php b/third_party/gameq_v3.1/GameQ/Protocols/Bf2.php deleted file mode 100644 index 0610f9d0..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Bf2.php +++ /dev/null @@ -1,98 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Battlefield 2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Bf2 extends Gamespy3 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'bf2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Battlefield 2"; - - /** - * query_port = client_port + 8433 - * 29900 = 16567 + 13333 - * - * @type int - */ - protected $port_diff = 13333; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "bf2://%s:%d"; - - /** - * BF2 has a different query packet to send than "normal" Gamespy 3 - * - * @var array - */ - protected $packets = [ - self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40\xFF\xFF\xFF\x01", - ]; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'gametype', - 'hostname' => 'hostname', - 'mapname' => 'mapname', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'player', - 'kills' => 'score', - 'deaths' => 'deaths', - 'ping' => 'ping', - 'score' => 'score', - ], - 'team' => [ - 'name' => 'team', - 'score' => 'score', - ], - ]; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Bf3.php b/third_party/gameq_v3.1/GameQ/Protocols/Bf3.php deleted file mode 100644 index 90845159..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Bf3.php +++ /dev/null @@ -1,348 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Battlefield 3 Protocol Class - * - * Good place for doc status and info is http://www.fpsadmin.com/forum/showthread.php?t=24134 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Bf3 extends Protocol -{ - - /** - * Array of packets we want to query. - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\x00\x00\x00\x21\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", - self::PACKET_VERSION => "\x00\x00\x00\x22\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00", - self::PACKET_PLAYERS => - "\x00\x00\x00\x23\x24\x00\x00\x00\x02\x00\x00\x00\x0b\x00\x00\x00listPlayers\x00\x03\x00\x00\x00\x61ll\x00", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - 1627389952 => "processDetails", // a - 1644167168 => "processVersion", // b - 1660944384 => "processPlayers", // c - ]; - - /** - * The transport mode for this protocol is TCP - * - * @type string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'bf3'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'bf3'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Battlefield 3"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * query_port = client_port + 22000 - * 47200 = 25200 + 22000 - * - * @type int - */ - protected $port_diff = 22000; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'hostname', - 'mapname' => 'map', - 'maxplayers' => 'max_players', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - 'player' => [ - 'name' => 'name', - 'score' => 'score', - 'ping' => 'ping', - ], - 'team' => [ - 'score' => 'tickets', - ], - ]; - - /** - * Process the response for the StarMade server - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // Holds the results sent back - $results = []; - - // Holds the processed packets after having been reassembled - $processed = []; - - // Start up the index for the processed - $sequence_id_last = 0; - - foreach ($this->packets_response as $packet) { - // Create a new buffer - $buffer = new Buffer($packet); - - // Each "good" packet begins with sequence_id (32-bit) - $sequence_id = $buffer->readInt32(); - - // Sequence id is a response - if (array_key_exists($sequence_id, $this->responses)) { - $processed[$sequence_id] = $buffer->getBuffer(); - $sequence_id_last = $sequence_id; - } else { - // This is a continuation of the previous packet, reset the buffer and append - $buffer->jumpto(0); - - // Append - $processed[$sequence_id_last] .= $buffer->getBuffer(); - } - } - - unset($buffer, $sequence_id_last, $sequence_id); - - // Iterate over the combined packets and do some work - foreach ($processed as $sequence_id => $data) { - // Create a new buffer - $buffer = new Buffer($data); - - // Get the length of the packet - $packetLength = $buffer->getLength(); - - // Check to make sure the expected length matches the real length - // Subtract 4 for the sequence_id pulled out earlier - if ($packetLength != ($buffer->readInt32() - 4)) { - throw new Exception(__METHOD__ . " packet length does not match expected length!"); - } - - // Now we need to call the proper method - $results = array_merge( - $results, - call_user_func_array([$this, $this->responses[$sequence_id]], [$buffer]) - ); - } - - return $results; - } - - /* - * Internal Methods - */ - - /** - * Decode the buffer into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function decode(Buffer $buffer) - { - - $items = []; - - // Get the number of words in this buffer - $itemCount = $buffer->readInt32(); - - // Loop over the number of items - for ($i = 0; $i < $itemCount; $i++) { - // Length of the string - $buffer->readInt32(); - - // Just read the string - $items[$i] = $buffer->readString(); - } - - return $items; - } - - /** - * Process the server details - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processDetails(Buffer $buffer) - { - - // Decode into items - $items = $this->decode($buffer); - - // Set the result to a new result instance - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - // These are the same no matter what mode the server is in - $result->add('hostname', $items[1]); - $result->add('num_players', (int)$items[2]); - $result->add('max_players', (int)$items[3]); - $result->add('gametype', $items[4]); - $result->add('map', $items[5]); - $result->add('roundsplayed', (int)$items[6]); - $result->add('roundstotal', (int)$items[7]); - $result->add('num_teams', (int)$items[8]); - - // Set the current index - $index_current = 9; - - // Pull the team count - $teamCount = $result->get('num_teams'); - - // Loop for the number of teams found, increment along the way - for ($id = 1; $id <= $teamCount; $id++, $index_current++) { - // Shows the tickets - $result->addTeam('tickets', $items[$index_current]); - // We add an id so we know which team this is - $result->addTeam('id', $id); - } - - // Get and set the rest of the data points. - $result->add('targetscore', (int)$items[$index_current]); - $result->add('online', 1); // Forced true, it seems $words[$index_current + 1] is always empty - $result->add('ranked', (int)$items[$index_current + 2]); - $result->add('punkbuster', (int)$items[$index_current + 3]); - $result->add('password', (int)$items[$index_current + 4]); - $result->add('uptime', (int)$items[$index_current + 5]); - $result->add('roundtime', (int)$items[$index_current + 6]); - // Added in R9 - $result->add('ip_port', $items[$index_current + 7]); - $result->add('punkbuster_version', $items[$index_current + 8]); - $result->add('join_queue', (int)$items[$index_current + 9]); - $result->add('region', $items[$index_current + 10]); - $result->add('pingsite', $items[$index_current + 11]); - $result->add('country', $items[$index_current + 12]); - // Added in R29, No docs as of yet - $result->add('quickmatch', (int)$items[$index_current + 13]); // Guessed from research - - unset($items, $index_current, $teamCount, $buffer); - - return $result->fetch(); - } - - /** - * Process the server version - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processVersion(Buffer $buffer) - { - - // Decode into items - $items = $this->decode($buffer); - - // Set the result to a new result instance - $result = new Result(); - - $result->add('version', $items[2]); - - unset($buffer, $items); - - return $result->fetch(); - } - - /** - * Process the players - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - - // Decode into items - $items = $this->decode($buffer); - - // Set the result to a new result instance - $result = new Result(); - - // Number of data points per player - $numTags = $items[1]; - - // Grab the tags for each player - $tags = array_slice($items, 2, $numTags); - - // Get the player count - $playerCount = $items[$numTags + 2]; - - // Iterate over the index until we run out of players - for ($i = 0, $x = $numTags + 3; $i < $playerCount; $i++, $x += $numTags) { - // Loop over the player tags and extract the info for that tag - foreach ($tags as $index => $tag) { - $result->addPlayer($tag, $items[($x + $index)]); - } - } - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Bf4.php b/third_party/gameq_v3.1/GameQ/Protocols/Bf4.php deleted file mode 100644 index 69517529..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Bf4.php +++ /dev/null @@ -1,114 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Battlefield 4 Protocol class - * - * Good place for doc status and info is http://battlelog.battlefield.com/bf4/forum/view/2955064768683911198/ - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Bf4 extends Bf3 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'bf4'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Battlefield 4"; - - /** - * Handle processing details since they are different than BF3 - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processDetails(Buffer $buffer) - { - - // Decode into items - $items = $this->decode($buffer); - - // Set the result to a new result instance - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - // These are the same no matter what mode the server is in - $result->add('hostname', $items[1]); - $result->add('num_players', (int) $items[2]); - $result->add('max_players', (int) $items[3]); - $result->add('gametype', $items[4]); - $result->add('map', $items[5]); - $result->add('roundsplayed', (int) $items[6]); - $result->add('roundstotal', (int) $items[7]); - $result->add('num_teams', (int) $items[8]); - - // Set the current index - $index_current = 9; - - // Pull the team count - $teamCount = $result->get('num_teams'); - - // Loop for the number of teams found, increment along the way - for ($id = 1; $id <= $teamCount; $id++, $index_current++) { - // Shows the tickets - $result->addTeam('tickets', $items[$index_current]); - // We add an id so we know which team this is - $result->addTeam('id', $id); - } - - // Get and set the rest of the data points. - $result->add('targetscore', (int) $items[$index_current]); - $result->add('online', 1); // Forced true, it seems $words[$index_current + 1] is always empty - $result->add('ranked', (int) $items[$index_current + 2]); - $result->add('punkbuster', (int) $items[$index_current + 3]); - $result->add('password', (int) $items[$index_current + 4]); - $result->add('uptime', (int) $items[$index_current + 5]); - $result->add('roundtime', (int) $items[$index_current + 6]); - $result->add('ip_port', $items[$index_current + 7]); - $result->add('punkbuster_version', $items[$index_current + 8]); - $result->add('join_queue', (int) $items[$index_current + 9]); - $result->add('region', $items[$index_current + 10]); - $result->add('pingsite', $items[$index_current + 11]); - $result->add('country', $items[$index_current + 12]); - //$result->add('quickmatch', (int) $items[$index_current + 13]); Supposed to be here according to R42 but is not - $result->add('blaze_player_count', (int) $items[$index_current + 13]); - $result->add('blaze_game_state', (int) $items[$index_current + 14]); - - unset($items, $index_current, $teamCount, $buffer); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Bfbc2.php b/third_party/gameq_v3.1/GameQ/Protocols/Bfbc2.php deleted file mode 100644 index b7167a02..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Bfbc2.php +++ /dev/null @@ -1,326 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Battlefield Bad Company 2 Protocol Class - * - * NOTE: There are no qualifiers to the response packets sent back from the server as to which response packet - * belongs to which query request. For now this class assumes the responses are in the same order as the order in - * which the packets were sent to the server. If this assumption turns out to be wrong there is easy way to tell which - * response belongs to which query. Hopefully this assumption will hold true as it has in my testing. - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Bfbc2 extends Protocol -{ - - /** - * Array of packets we want to query. - * - * @type array - */ - protected $packets = [ - self::PACKET_VERSION => "\x00\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00version\x00", - self::PACKET_STATUS => "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", - self::PACKET_PLAYERS => "\x00\x00\x00\x00\x24\x00\x00\x00\x02\x00\x00\x00\x0b\x00\x00\x00listPlayers\x00\x03\x00\x00\x00\x61ll\x00", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "processVersion", - "processDetails", - "processPlayers", - ]; - - /** - * The transport mode for this protocol is TCP - * - * @type string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'bfbc2'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'bfbc2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Battlefield Bad Company 2"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * query_port = client_port + 29321 - * 48888 = 19567 + 29321 - * - * @type int - */ - protected $port_diff = 29321; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'hostname', - 'mapname' => 'map', - 'maxplayers' => 'max_players', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - 'player' => [ - 'name' => 'name', - 'score' => 'score', - 'ping' => 'ping', - ], - 'team' => [ - 'score' => 'tickets', - ], - ]; - - /** - * Process the response for the StarMade server - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - //print_r($this->packets_response); - - // Holds the results sent back - $results = []; - - // Iterate over the response packets - // @todo: This protocol has no packet ordering, ids or anyway to identify which packet coming back belongs to which initial call. - foreach ($this->packets_response as $i => $packet) { - // Create a new buffer - $buffer = new Buffer($packet); - - // Burn first 4 bytes, same across all packets - $buffer->skip(4); - - // Get the packet length - $packetLength = $buffer->getLength(); - - // Check to make sure the expected length matches the real length - // Subtract 4 for the header burn - if ($packetLength != ($buffer->readInt32() - 4)) { - throw new Exception(__METHOD__ . " packet length does not match expected length!"); - } - - // We assume the packets are coming back in the same order as sent, this maybe incorrect... - $results = array_merge( - $results, - call_user_func_array([$this, $this->responses[$i]], [$buffer]) - ); - } - - unset($buffer, $packetLength); - - return $results; - } - - /* - * Internal Methods - */ - - /** - * Decode the buffer into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function decode(Buffer $buffer) - { - - $items = []; - - // Get the number of words in this buffer - $itemCount = $buffer->readInt32(); - - // Loop over the number of items - for ($i = 0; $i < $itemCount; $i++) { - // Length of the string - $buffer->readInt32(); - - // Just read the string - $items[$i] = $buffer->readString(); - } - - return $items; - } - - /** - * Process the server details - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processDetails(Buffer $buffer) - { - - // Decode into items - $items = $this->decode($buffer); - - // Set the result to a new result instance - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - // These are the same no matter what mode the server is in - $result->add('hostname', $items[1]); - $result->add('num_players', (int)$items[2]); - $result->add('max_players', (int)$items[3]); - $result->add('gametype', $items[4]); - $result->add('map', $items[5]); - $result->add('roundsplayed', (int)$items[6]); - $result->add('roundstotal', (int)$items[7]); - $result->add('num_teams', (int)$items[8]); - - // Set the current index - $index_current = 9; - - // Pull the team count - $teamCount = $result->get('num_teams'); - - // Loop for the number of teams found, increment along the way - for ($id = 1; $id <= $teamCount; $id++, $index_current++) { - // Shows the tickets - $result->addTeam('tickets', $items[$index_current]); - // We add an id so we know which team this is - $result->addTeam('id', $id); - } - - // Get and set the rest of the data points. - $result->add('targetscore', (int)$items[$index_current]); - $result->add('online', 1); // Forced true, shows accepting players - $result->add('ranked', (($items[$index_current + 2] == 'true') ? 1 : 0)); - $result->add('punkbuster', (($items[$index_current + 3] == 'true') ? 1 : 0)); - $result->add('password', (($items[$index_current + 4] == 'true') ? 1 : 0)); - $result->add('uptime', (int)$items[$index_current + 5]); - $result->add('roundtime', (int)$items[$index_current + 6]); - $result->add('mod', $items[$index_current + 7]); - - $result->add('ip_port', $items[$index_current + 9]); - $result->add('punkbuster_version', $items[$index_current + 10]); - $result->add('join_queue', (($items[$index_current + 11] == 'true') ? 1 : 0)); - $result->add('region', $items[$index_current + 12]); - - unset($items, $index_current, $teamCount, $buffer); - - return $result->fetch(); - } - - /** - * Process the server version - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processVersion(Buffer $buffer) - { - // Decode into items - $items = $this->decode($buffer); - - // Set the result to a new result instance - $result = new Result(); - - $result->add('version', $items[2]); - - unset($buffer, $items); - - return $result->fetch(); - } - - /** - * Process the players - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - - // Decode into items - $items = $this->decode($buffer); - - // Set the result to a new result instance - $result = new Result(); - - // Number of data points per player - $numTags = $items[1]; - - // Grab the tags for each player - $tags = array_slice($items, 2, $numTags); - - // Get the player count - $playerCount = $items[$numTags + 2]; - - // Iterate over the index until we run out of players - for ($i = 0, $x = $numTags + 3; $i < $playerCount; $i++, $x += $numTags) { - // Loop over the player tags and extract the info for that tag - foreach ($tags as $index => $tag) { - $result->addPlayer($tag, $items[($x + $index)]); - } - } - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Cod2.php b/third_party/gameq_v3.1/GameQ/Protocols/Cod2.php deleted file mode 100644 index 79be7ca2..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Cod2.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Call of Duty 2 Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Cod2 extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cod2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Call of Duty 2"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Cod4.php b/third_party/gameq_v3.1/GameQ/Protocols/Cod4.php deleted file mode 100644 index 9838d9cb..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Cod4.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Call of Duty 4 Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Cod4 extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cod4'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Call of Duty 4"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Coduo.php b/third_party/gameq_v3.1/GameQ/Protocols/Coduo.php deleted file mode 100644 index 2dd9a182..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Coduo.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Call of Duty United Offensive Class - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Coduo extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'coduo'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Call of Duty: United Offensive"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Codwaw.php b/third_party/gameq_v3.1/GameQ/Protocols/Codwaw.php deleted file mode 100644 index f730678e..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Codwaw.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Call of Duty World at War Class - * - * @package GameQ\Protocols - * @author naXe - * @author Austin Bischoff - */ -class Codwaw extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'codwaw'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Call of Duty: World at War"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Crysiswars.php b/third_party/gameq_v3.1/GameQ/Protocols/Crysiswars.php deleted file mode 100644 index 44dcdcf1..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Crysiswars.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Crysiswars - * - * @package GameQ\Protocols - * - * @author Austin Bischoff - */ -class Crysiswars extends Gamespy3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'crysiswars'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Crysis Wars"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Cs16.php b/third_party/gameq_v3.1/GameQ/Protocols/Cs16.php deleted file mode 100644 index 25a66029..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Cs16.php +++ /dev/null @@ -1,69 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Cs16 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Cs16 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cs16'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Counter-Strike 1.6"; - - /** - * In the case of cs 1.6 we offload split packets here because the split packet response for rules is in - * the old gold source format - * - * @param $packet_id - * @param array $packets - * - * @return string - * @throws \GameQ\Exception\Protocol - */ - protected function processPackets($packet_id, array $packets = []) - { - - // The response is gold source if the packets are split - $this->source_engine = self::GOLDSOURCE_ENGINE; - - // Offload to the parent - $packs = parent::processPackets($packet_id, $packets); - - // Reset the engine - $this->source_engine = self::SOURCE_ENGINE; - - // Return the result - return $packs; - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Cscz.php b/third_party/gameq_v3.1/GameQ/Protocols/Cscz.php deleted file mode 100644 index b539128f..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Cscz.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Cscz - * - * Based off of CS 1.6 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Cscz extends Cs16 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cscz'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Counter-Strike: Condition Zero"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Dayz.php b/third_party/gameq_v3.1/GameQ/Protocols/Dayz.php deleted file mode 100644 index 01c7c28d..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Dayz.php +++ /dev/null @@ -1,66 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Dayz - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dayz extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'dayz'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "DayZ Standalone"; - - /** - * Overload the math used to guess at the Query Port - * - * @param int $clientPort - * - * @return int - */ - public function findQueryPort($clientPort) - { - - /* - * Port layout: - * 2302 - 27016 - * 2402 - 27017 - * 2502 - 27018 - * 2602 - 27019 - * 2702 - 27020 - * ... - */ - - return 27016 + (($clientPort - 2302) / 100); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Dayzmod.php b/third_party/gameq_v3.1/GameQ/Protocols/Dayzmod.php deleted file mode 100644 index 2ce1076d..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Dayzmod.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Dayzmod - * - * @package GameQ\Protocols - * @author Marcel Bößendörfer - * @author Austin Bischoff - */ -class Dayzmod extends Armedassault2oa -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'dayzmod'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "DayZ Mod"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Etqw.php b/third_party/gameq_v3.1/GameQ/Protocols/Etqw.php deleted file mode 100644 index 1f3a446c..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Etqw.php +++ /dev/null @@ -1,234 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Exception\Protocol as Exception; -use GameQ\Protocol; -use GameQ\Result; - -/** - * Enemy Territory Quake Wars Protocol Class - * - * @author Austin Bischoff - */ -class Etqw extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\xFF\xFFgetInfoEx\x00\x00\x00\x00", - //self::PACKET_STATUS => "\xFF\xFFgetInfo\x00\x00\x00\x00\x00", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\xFF\xFFinfoExResponse" => "processStatus", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'etqw'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'etqw'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Enemy Territory Quake Wars"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'campaign', - 'hostname' => 'name', - 'mapname' => 'map', - 'maxplayers' => 'maxPlayers', - 'mod' => 'gamename', - 'numplayers' => 'numplayers', - 'password' => 'privateClients', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'score' => 'score', - 'time' => 'time', - ], - ]; - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - // In case it comes back as multiple packets (it shouldn't) - $buffer = new Buffer(implode('', $this->packets_response)); - - // Figure out what packet response this is for - $response_type = $buffer->readString(); - - // Figure out which packet response this is - if (!array_key_exists($response_type, $this->responses)) { - throw new Exception(__METHOD__ . " response type '{$response_type}' is not valid"); - } - - // Offload the call - $results = call_user_func_array([$this, $this->responses[$response_type]], [$buffer]); - - return $results; - } - - /* - * Internal methods - */ - - /** - * Handle processing the status response - * - * @param Buffer $buffer - * - * @return array - */ - protected function processStatus(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - // Defaults - $result->add('dedicated', 1); - - // Now burn the challenge, version and size - $buffer->skip(16); - - // Key / value pairs - while ($buffer->getLength()) { - $var = str_replace('si_', '', $buffer->readString()); - $val = $buffer->readString(); - if (empty($var) && empty($val)) { - break; - } - // Add the server prop - $result->add($var, $val); - } - // Now let's do the basic player info - $this->parsePlayers($buffer, $result); - - // Now grab the rest of the server info - $result->add('osmask', $buffer->readInt32()); - $result->add('ranked', $buffer->readInt8()); - $result->add('timeleft', $buffer->readInt32()); - $result->add('gamestate', $buffer->readInt8()); - $result->add('servertype', $buffer->readInt8()); - - // 0: regular server - if ($result->get('servertype') == 0) { - $result->add('interested_clients', $buffer->readInt8()); - } else { - // 1: tv server - $result->add('connected_clients', $buffer->readInt32()); - $result->add('max_clients', $buffer->readInt32()); - } - - // Now let's parse the extended player info - $this->parsePlayersExtra($buffer, $result); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Parse players out of the status ex response - * - * @param Buffer $buffer - * @param Result $result - */ - protected function parsePlayers(Buffer &$buffer, Result &$result) - { - // By default there are 0 players - $players = 0; - - // Iterate over the players until we run out - while (($id = $buffer->readInt8()) != 32) { - $result->addPlayer('id', $id); - $result->addPlayer('ping', $buffer->readInt16()); - $result->addPlayer('name', $buffer->readString()); - $result->addPlayer('clantag_pos', $buffer->readInt8()); - $result->addPlayer('clantag', $buffer->readString()); - $result->addPlayer('bot', $buffer->readInt8()); - $players++; - } - - // Let's add in the current players as a result - $result->add('numplayers', $players); - - // Free some memory - unset($id); - } - - /** - * Handle parsing extra player data - * - * @param Buffer $buffer - * @param Result $result - */ - protected function parsePlayersExtra(Buffer &$buffer, Result &$result) - { - // Iterate over the extra player info - while (($id = $buffer->readInt8()) != 32) { - $result->addPlayer('total_xp', $buffer->readFloat32()); - $result->addPlayer('teamname', $buffer->readString()); - $result->addPlayer('total_kills', $buffer->readInt32()); - $result->addPlayer('total_deaths', $buffer->readInt32()); - } - - // @todo: Add team stuff - - // Free some memory - unset($id); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ffe.php b/third_party/gameq_v3.1/GameQ/Protocols/Ffe.php deleted file mode 100644 index c0947bdc..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Ffe.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Ffe - Fortress Forever - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Ffe extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ffe'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Fortress Forever"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ffow.php b/third_party/gameq_v3.1/GameQ/Protocols/Ffow.php deleted file mode 100644 index 00c33d47..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Ffow.php +++ /dev/null @@ -1,243 +0,0 @@ - "\xFF\xFF\xFF\xFF\x57", - self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s", - self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s", - self::PACKET_INFO => "\xFF\xFF\xFF\xFF\x46\x4C\x53\x51", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\xFF\xFF\xFF\xFF\x49\x02" => 'processInfo', // I - "\xFF\xFF\xFF\xFF\x45\x00" => 'processRules', // E - "\xFF\xFF\xFF\xFF\x44\x00" => 'processPlayers', // D - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'ffow'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ffow'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Frontlines Fuel of War"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * query_port = client_port + 2 - * - * @type int - */ - protected $port_diff = 2; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'gamemode', - 'hostname' => 'servername', - 'mapname' => 'mapname', - 'maxplayers' => 'max_players', - 'mod' => 'modname', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'ping' => 'ping', - 'score' => 'frags', - ], - ]; - - /** - * Parse the challenge response and apply it to all the packet types - * - * @param \GameQ\Buffer $challenge_buffer - * - * @return bool - * @throws \GameQ\Exception\Protocol - */ - public function challengeParseAndApply(Buffer $challenge_buffer) - { - // Burn padding - $challenge_buffer->skip(5); - - // Apply the challenge and return - return $this->challengeApply($challenge_buffer->read(4)); - } - - /** - * Handle response from the server - * - * @return mixed - * @throws Exception - */ - public function processResponse() - { - // Init results - $results = []; - - foreach ($this->packets_response as $response) { - $buffer = new Buffer($response); - - // Figure out what packet response this is for - $response_type = $buffer->read(6); - - // Figure out which packet response this is - if (!array_key_exists($response_type, $this->responses)) { - throw new Exception(__METHOD__ . " response type '" . bin2hex($response_type) . "' is not valid"); - } - - // Now we need to call the proper method - $results = array_merge( - $results, - call_user_func_array([$this, $this->responses[$response_type]], [$buffer]) - ); - - unset($buffer); - } - - return $results; - } - - /** - * Handle processing the server information - * - * @param Buffer $buffer - * - * @return array - */ - protected function processInfo(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - $result->add('servername', $buffer->readString()); - $result->add('mapname', $buffer->readString()); - $result->add('modname', $buffer->readString()); - $result->add('gamemode', $buffer->readString()); - $result->add('description', $buffer->readString()); - $result->add('version', $buffer->readString()); - $result->add('port', $buffer->readInt16()); - $result->add('num_players', $buffer->readInt8()); - $result->add('max_players', $buffer->readInt8()); - $result->add('dedicated', $buffer->readInt8()); - $result->add('os', $buffer->readInt8()); - $result->add('password', $buffer->readInt8()); - $result->add('anticheat', $buffer->readInt8()); - $result->add('average_fps', $buffer->readInt8()); - $result->add('round', $buffer->readInt8()); - $result->add('max_rounds', $buffer->readInt8()); - $result->add('time_left', $buffer->readInt16()); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handle processing the server rules - * - * @param Buffer $buffer - * - * @return array - */ - protected function processRules(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - // Burn extra header - $buffer->skip(1); - - // Read rules until we run out of buffer - while ($buffer->getLength()) { - $key = $buffer->readString(); - // Check for map - if (strstr($key, "Map:")) { - $result->addSub("maplist", "name", $buffer->readString()); - } else // Regular rule - { - $result->add($key, $buffer->readString()); - } - } - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handle processing of player data - * - * @todo: Build this out when there is a server with players to test against - * - * @param Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - unset($buffer); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Gamespy.php b/third_party/gameq_v3.1/GameQ/Protocols/Gamespy.php deleted file mode 100644 index b1a1e4fa..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Gamespy.php +++ /dev/null @@ -1,181 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use \GameQ\Exception\Protocol as Exception; - -/** - * GameSpy Protocol class - * - * @author Austin Bischoff - */ -class Gamespy extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\x5C\x73\x74\x61\x74\x75\x73\x5C", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'gamespy'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'gamespy'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "GameSpy Server"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * Process the response for this protocol - * - * @return array - * @throws Exception - */ - public function processResponse() - { - // Holds the processed packets so we can sort them in case they come in an unordered - $processed = []; - - // Iterate over the packets - foreach ($this->packets_response as $response) { - // Check to see if we had a preg_match error - if (($match = preg_match("#^(.*)\\\\queryid\\\\([^\\\\]+)(\\\\|$)#", $response, $matches)) === false - || $match != 1 - ) { - throw new Exception(__METHOD__ . " An error occurred while parsing the packets for 'queryid'"); - } - - // Multiply so we move the decimal point out of the way, if there is one - $key = (int)(floatval($matches[2]) * 1000); - - // Add this packet to the processed - $processed[$key] = $matches[1]; - } - - // Sort the new array to make sure the keys (query ids) are in the proper order - ksort($processed, SORT_NUMERIC); - - // Create buffer and offload processing - return $this->processStatus(new Buffer(implode('', $processed))); - } - - /* - * Internal methods - */ - - /** - * Handle processing the status buffer - * - * @param Buffer $buffer - * - * @return array - */ - protected function processStatus(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - // By default dedicted - $result->add('dedicated', 1); - - // Lets peek and see if the data starts with a \ - if ($buffer->lookAhead(1) == '\\') { - // Burn the first one - $buffer->skip(1); - } - - // Explode the data - $data = explode('\\', $buffer->getBuffer()); - - // No longer needed - unset($buffer); - - // Init some vars - $numPlayers = 0; - $numTeams = 0; - - $itemCount = count($data); - - // Check to make sure we have more than 1 item in the array before trying to loop - if (count($data) > 1) { - // Now lets loop the array since we have items - for ($x = 0; $x < $itemCount; $x += 2) { - // Set some local vars - $key = $data[$x]; - $val = $data[$x + 1]; - - // Check for _ variable (i.e players) - if (($suffix = strrpos($key, '_')) !== false && is_numeric(substr($key, $suffix + 1))) { - // See if this is a team designation - if (substr($key, 0, $suffix) == 'teamname') { - $result->addTeam('teamname', $val); - $numTeams++; - } else { - // Its a player - if (substr($key, 0, $suffix) == 'playername') { - $numPlayers++; - } - $result->addPlayer(substr($key, 0, $suffix), utf8_encode($val)); - } - } else { - // Regular variable so just add the value. - $result->add($key, $val); - } - } - } - - // Add the player and team count - $result->add('num_players', $numPlayers); - $result->add('num_teams', $numTeams); - - // Unset some stuff to free up memory - unset($data, $key, $val, $suffix, $x, $itemCount); - - // Return the result - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Gamespy2.php b/third_party/gameq_v3.1/GameQ/Protocols/Gamespy2.php deleted file mode 100644 index c7788d9e..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Gamespy2.php +++ /dev/null @@ -1,269 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Exception\Protocol as Exception; -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; - -/** - * GameSpy2 Protocol class - * - * Given the ability for non utf-8 characters to be used as hostnames, player names, etc... this - * version returns all strings utf-8 encoded (utf8_encode). To access the proper version of a - * string response you must use utf8_decode() on the specific response. - * - * @author Austin Bischoff - */ -class Gamespy2 extends Protocol -{ - - /** - * Define the state of this class - * - * @type int - */ - protected $state = self::STATE_BETA; - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_DETAILS => "\xFE\xFD\x00\x43\x4F\x52\x59\xFF\x00\x00", - self::PACKET_PLAYERS => "\xFE\xFD\x00\x43\x4F\x52\x58\x00\xFF\xFF", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\x00\x43\x4F\x52\x59" => "processDetails", - "\x00\x43\x4F\x52\x58" => "processPlayers", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'gamespy2'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'gamespy2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "GameSpy2 Server"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'gametype', - 'hostname' => 'hostname', - 'mapname' => 'mapname', - 'maxplayers' => 'maxplayers', - 'mod' => 'mod', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - ]; - - - /** - * Process the response - * - * @return array - * @throws Exception - */ - public function processResponse() - { - - // Will hold the packets after sorting - $packets = []; - - // We need to pre-sort these for split packets so we can do extra work where needed - foreach ($this->packets_response as $response) { - $buffer = new Buffer($response); - - // Pull out the header - $header = $buffer->read(5); - - // Add the packet to the proper section, we will combine later - $packets[$header][] = $buffer->getBuffer(); - } - - unset($buffer); - - $results = []; - - // Now let's iterate and process - foreach ($packets as $header => $packetGroup) { - // Figure out which packet response this is - if (!array_key_exists($header, $this->responses)) { - throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); - } - - // Now we need to call the proper method - $results = array_merge( - $results, - call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))]) - ); - } - - unset($packets); - - return $results; - } - - /* - * Internal methods - */ - - /** - * Handles processing the details data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processDetails(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // We go until we hit an empty key - while ($buffer->getLength()) { - $key = $buffer->readString(); - if (strlen($key) == 0) { - break; - } - $result->add($key, utf8_encode($buffer->readString())); - } - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the players data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Skip the header - $buffer->skip(1); - - // Players are first - $this->parsePlayerTeam('players', $buffer, $result); - - // Teams are next - $this->parsePlayerTeam('teams', $buffer, $result); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Parse the player/team info returned from the player call - * - * @param string $dataType - * @param \GameQ\Buffer $buffer - * @param \GameQ\Result $result - * - * @throws Exception - */ - protected function parsePlayerTeam($dataType, Buffer &$buffer, Result &$result) - { - - // Do count - $result->add('num_' . $dataType, $buffer->readInt8()); - - // Variable names - $varNames = []; - - // Loop until we run out of length - while ($buffer->getLength()) { - $varNames[] = str_replace('_', '', $buffer->readString()); - - if ($buffer->lookAhead() === "\x00") { - $buffer->skip(); - break; - } - } - - // Check if there are any value entries - if ($buffer->lookAhead() == "\x00") { - $buffer->skip(); - - return; - } - - // Get the values - while ($buffer->getLength() > 4) { - foreach ($varNames as $varName) { - $result->addSub($dataType, utf8_encode($varName), utf8_encode($buffer->readString())); - } - if ($buffer->lookAhead() === "\x00") { - $buffer->skip(); - break; - } - } - - return; - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Gamespy3.php b/third_party/gameq_v3.1/GameQ/Protocols/Gamespy3.php deleted file mode 100644 index 2df0a4bd..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Gamespy3.php +++ /dev/null @@ -1,340 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; - -/** - * GameSpy3 Protocol class - * - * Given the ability for non utf-8 characters to be used as hostnames, player names, etc... this - * version returns all strings utf-8 encoded (utf8_encode). To access the proper version of a - * string response you must use utf8_decode() on the specific response. - * - * @author Austin Bischoff - */ -class Gamespy3 extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_CHALLENGE => "\xFE\xFD\x09\x10\x20\x30\x40", - self::PACKET_ALL => "\xFE\xFD\x00\x10\x20\x30\x40%s\xFF\xFF\xFF\x01", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'gamespy3'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'gamespy3'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "GameSpy3 Server"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * This defines the split between the server info and player/team info. - * This value can vary by game. This value is the default split. - * - * @var string - */ - protected $packetSplit = "/\\x00\\x00\\x01/m"; - - /** - * Parse the challenge response and apply it to all the packet types - * - * @param \GameQ\Buffer $challenge_buffer - * - * @return bool - * @throws \GameQ\Exception\Protocol - */ - public function challengeParseAndApply(Buffer $challenge_buffer) - { - // Pull out the challenge - $challenge = substr(preg_replace("/[^0-9\-]/si", "", $challenge_buffer->getBuffer()), 1); - - // By default, no challenge result (see #197) - $challenge_result = ''; - - // Check for valid challenge (see #197) - if ($challenge) { - // Encode chellenge result - $challenge_result = sprintf( - "%c%c%c%c", - ($challenge >> 24), - ($challenge >> 16), - ($challenge >> 8), - ($challenge >> 0) - ); - } - - // Apply the challenge and return - return $this->challengeApply($challenge_result); - } - - /** - * Process the response - * - * @return array - */ - public function processResponse() - { - - // Holds the processed packets - $processed = []; - - // Iterate over the packets - foreach ($this->packets_response as $response) { - // Make a buffer - $buffer = new Buffer($response, Buffer::NUMBER_TYPE_BIGENDIAN); - - // Packet type = 0 - $buffer->readInt8(); - - // Session Id - $buffer->readInt32(); - - // We need to burn the splitnum\0 because it is not used - $buffer->skip(9); - - // Get the id - $id = $buffer->readInt8(); - - // Burn next byte not sure what it is used for - $buffer->skip(1); - - // Add this packet to the processed - $processed[$id] = $buffer->getBuffer(); - - unset($buffer, $id); - } - - // Sort packets, reset index - ksort($processed); - - // Offload cleaning up the packets if they happen to be split - $packets = $this->cleanPackets(array_values($processed)); - - // Split the packets by type general and the rest (i.e. players & teams) - $split = preg_split($this->packetSplit, implode('', $packets)); - - // Create a new result - $result = new Result(); - - // Assign variable due to pass by reference in PHP 7+ - $buffer = new Buffer($split[0], Buffer::NUMBER_TYPE_BIGENDIAN); - - // First key should be server details and rules - $this->processDetails($buffer, $result); - - // The rest should be the player and team information, if it exists - if (array_key_exists(1, $split)) { - $buffer = new Buffer($split[1], Buffer::NUMBER_TYPE_BIGENDIAN); - $this->processPlayersAndTeams($buffer, $result); - } - - unset($buffer); - - return $result->fetch(); - } - - /* - * Internal methods - */ - - /** - * Handles cleaning up packets since the responses can be a bit "dirty" - * - * @param array $packets - * - * @return array - */ - protected function cleanPackets(array $packets = []) - { - - // Get the number of packets - $packetCount = count($packets); - - // Compare last var of current packet with first var of next packet - // On a partial match, remove last var from current packet, - // variable header from next packet - for ($i = 0, $x = $packetCount; $i < $x - 1; $i++) { - // First packet - $fst = substr($packets[$i], 0, -1); - // Second packet - $snd = $packets[$i + 1]; - // Get last variable from first packet - $fstvar = substr($fst, strrpos($fst, "\x00") + 1); - // Get first variable from last packet - $snd = substr($snd, strpos($snd, "\x00") + 2); - $sndvar = substr($snd, 0, strpos($snd, "\x00")); - // Check if fstvar is a substring of sndvar - // If so, remove it from the first string - if (!empty($fstvar) && strpos($sndvar, $fstvar) !== false) { - $packets[$i] = preg_replace("#(\\x00[^\\x00]+\\x00)$#", "\x00", $packets[$i]); - } - } - - // Now let's loop the return and remove any dupe prefixes - for ($x = 1; $x < $packetCount; $x++) { - $buffer = new Buffer($packets[$x], Buffer::NUMBER_TYPE_BIGENDIAN); - - $prefix = $buffer->readString(); - - // Check to see if the return before has the same prefix present - if ($prefix != null && strstr($packets[($x - 1)], $prefix)) { - // Update the return by removing the prefix plus 2 chars - $packets[$x] = substr(str_replace($prefix, '', $packets[$x]), 2); - } - - unset($buffer); - } - - unset($x, $i, $snd, $sndvar, $fst, $fstvar); - - // Return cleaned packets - return $packets; - } - - /** - * Handles processing the details data into a usable format - * - * @param \GameQ\Buffer $buffer - * @param \GameQ\Result $result - */ - protected function processDetails(Buffer &$buffer, Result &$result) - { - - // We go until we hit an empty key - while ($buffer->getLength()) { - $key = $buffer->readString(); - if (strlen($key) == 0) { - break; - } - $result->add($key, utf8_encode($buffer->readString())); - } - } - - /** - * Handles processing the player and team data into a usable format - * - * @param \GameQ\Buffer $buffer - * @param \GameQ\Result $result - */ - protected function processPlayersAndTeams(Buffer &$buffer, Result &$result) - { - - /* - * Explode the data into groups. First is player, next is team (item_t) - * Each group should be as follows: - * - * [0] => item_ - * [1] => information for item_ - * ... - */ - $data = explode("\x00\x00", $buffer->getBuffer()); - - // By default item_group is blank, this will be set for each loop thru the data - $item_group = ''; - - // By default the item_type is blank, this will be set on each loop - $item_type = ''; - - // Save count as variable - $count = count($data); - - // Loop through all of the $data for information and pull it out into the result - for ($x = 0; $x < $count - 1; $x++) { - // Pull out the item - $item = $data[$x]; - // If this is an empty item, move on - if ($item == '' || $item == "\x00") { - continue; - } - /* - * Left as reference: - * - * Each block of player_ and team_t have preceding junk chars - * - * player_ is actually \x01player_ - * team_t is actually \x00\x02team_t - * - * Probably a by-product of the change to exploding the data from the original. - * - * For now we just strip out these characters - */ - // Check to see if $item has a _ at the end, this is player info - if (substr($item, -1) == '_') { - // Set the item group - $item_group = 'players'; - // Set the item type, rip off any trailing stuff and bad chars - $item_type = rtrim(str_replace("\x01", '', $item), '_'); - } elseif (substr($item, -2) == '_t') { - // Check to see if $item has a _t at the end, this is team info - // Set the item group - $item_group = 'teams'; - // Set the item type, rip off any trailing stuff and bad chars - $item_type = rtrim(str_replace(["\x00", "\x02"], '', $item), '_t'); - } else { - // We can assume it is data belonging to a previously defined item - - // Make a temp buffer so we have easier access to the data - $buf_temp = new Buffer($item, Buffer::NUMBER_TYPE_BIGENDIAN); - // Get the values - while ($buf_temp->getLength()) { - // No value so break the loop, end of string - if (($val = $buf_temp->readString()) === '') { - break; - } - // Add the value to the proper item in the correct group - $result->addSub($item_group, $item_type, utf8_encode(trim($val))); - } - // Unset our buffer - unset($buf_temp); - } - } - // Free up some memory - unset($count, $data, $item, $item_group, $item_type, $val); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Gamespy4.php b/third_party/gameq_v3.1/GameQ/Protocols/Gamespy4.php deleted file mode 100644 index e28755f1..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Gamespy4.php +++ /dev/null @@ -1,34 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * GameSpy4 Protocol Class - * - * By all accounts GameSpy 4 seems to be GameSpy 3. - * - * References: - * http://www.deletedscreen.com/?p=951 - * http://pastebin.com/2zZFDuTd - * - * @author Austin Bischoff - */ -class Gamespy4 extends Gamespy3 -{ -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Http.php b/third_party/gameq_v3.1/GameQ/Protocols/Http.php deleted file mode 100644 index 2a86d8d1..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Http.php +++ /dev/null @@ -1,67 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; - -/** - * Class Http - * - * Generic HTTP protocol class. Useful for making http based requests - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -abstract class Http extends Protocol -{ - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'http'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'http'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Generic HTTP protocol"; - - /** - * Http protocol is TCP - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Insurgency.php b/third_party/gameq_v3.1/GameQ/Protocols/Insurgency.php deleted file mode 100644 index 77b8329e..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Insurgency.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Insurgency - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Insurgency extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'insurgency'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Insurgency"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Killingfloor.php b/third_party/gameq_v3.1/GameQ/Protocols/Killingfloor.php deleted file mode 100644 index 9cc19643..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Killingfloor.php +++ /dev/null @@ -1,96 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Class Killing floor - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Killingfloor extends Unreal2 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'killing floor'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Killing Floor"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "steam://connect/%s:%d/"; - - /** - * Overload the default detail process since this version is different - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processDetails(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - $result->add('serverid', $buffer->readInt32()); // 0 - $result->add('serverip', $buffer->readPascalString(1)); // empty - $result->add('gameport', $buffer->readInt32()); - $result->add('queryport', $buffer->readInt32()); // 0 - - // We burn the first char since it is not always correct with the hostname - $buffer->skip(1); - - // Read as a regular string since the length is incorrect (what we skipped earlier) - $result->add('servername', utf8_encode($buffer->readString())); - - // The rest is read as normal - $result->add('mapname', utf8_encode($buffer->readPascalString(1))); - $result->add('gametype', $buffer->readPascalString(1)); - $result->add('numplayers', $buffer->readInt32()); - $result->add('maxplayers', $buffer->readInt32()); - $result->add('currentwave', $buffer->readInt32()); - - unset($buffer); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/L4d.php b/third_party/gameq_v3.1/GameQ/Protocols/L4d.php deleted file mode 100644 index 596452a7..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/L4d.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class L4d - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class L4d extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'l4d'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Left 4 Dead"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/L4d2.php b/third_party/gameq_v3.1/GameQ/Protocols/L4d2.php deleted file mode 100644 index 475514c9..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/L4d2.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class L4d2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class L4d2 extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'l4d2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Left 4 Dead 2"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Minecraft.php b/third_party/gameq_v3.1/GameQ/Protocols/Minecraft.php deleted file mode 100644 index a895cb87..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Minecraft.php +++ /dev/null @@ -1,87 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Minecraft Protocol Class - * - * Thanks to https://github.com/xPaw/PHP-Minecraft-Query for helping me realize this is - * Gamespy 3 Protocol. Make sure you enable the items below for it to work. - * - * Information from original author: - * Instructions - * - * Before using this class, you need to make sure that your server is running GS4 status listener. - * - * Look for those settings in server.properties: - * - * enable-query=true - * query.port=25565 - * - * @package GameQ\Protocols - * - * @author Austin Bischoff - */ -class Minecraft extends Gamespy3 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'minecraft'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Minecraft"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "minecraft://%s:%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'game_id', - 'hostname' => 'hostname', - 'mapname' => 'map', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'player', - ], - ]; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Mta.php b/third_party/gameq_v3.1/GameQ/Protocols/Mta.php deleted file mode 100644 index b95dc4c8..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Mta.php +++ /dev/null @@ -1,59 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Multi Theft Auto - * - * @package GameQ\Protocols - * - * @author Marcel Bößendörfer - * @author Austin Bischoff - */ -class Mta extends Ase -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'mta'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Multi Theft Auto"; - - /** - * query_port = client_port + 123 - * - * @type int - */ - protected $port_diff = 123; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "mtasa://%s:%d/"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Mumble.php b/third_party/gameq_v3.1/GameQ/Protocols/Mumble.php deleted file mode 100644 index 299389cf..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Mumble.php +++ /dev/null @@ -1,194 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Mumble Protocol class - * - * References: - * https://github.com/edmundask/MurmurQuery - Thanks to skylord123 - * - * @author Austin Bischoff - */ -class Mumble extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_ALL => "\x6A\x73\x6F\x6E", // JSON packet - ]; - - /** - * The transport mode for this protocol is TCP - * - * @type string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'mumble'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'mumble'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Mumble Server"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "mumble://%s:%d/"; - - /** - * 27800 = 64738 - 36938 - * - * @type int - */ - protected $port_diff = -36938; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - 'dedicated' => 'dedicated', - 'gametype' => 'gametype', - 'hostname' => 'name', - 'numplayers' => 'numplayers', - 'maxplayers' => 'x_gtmurmur_max_users', - ], - // Player - 'player' => [ - 'name' => 'name', - 'ping' => 'tcpPing', - 'team' => 'channel', - 'time' => 'onlinesecs', - ], - // Team - 'team' => [ - 'name' => 'name', - ], - ]; - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // Try to json_decode, make it into an array - if (($data = json_decode(implode('', $this->packets_response), true)) === null) { - throw new Exception(__METHOD__ . " Unable to decode JSON data."); - } - - // Set the result to a new result instance - $result = new Result(); - - // Always dedicated - $result->add('dedicated', 1); - - // Let's iterate over the response items, there are a lot - foreach ($data as $key => $value) { - // Ignore root for now, that is where all of the channel/player info is housed - if (in_array($key, ['root'])) { - continue; - } - - // Add them as is - $result->add($key, $value); - } - - // Offload the channel and user parsing - $this->processChannelsAndUsers($data['root'], $result); - - unset($data); - - // Manually set the number of players - $result->add('numplayers', count($result->get('players'))); - - return $result->fetch(); - } - - /* - * Internal methods - */ - - /** - * Handles processing the the channels and user info - * - * @param array $data - * @param \GameQ\Result $result - */ - protected function processChannelsAndUsers(array $data, Result &$result) - { - - // Let's add all of the channel information - foreach ($data as $key => $value) { - // We will handle these later - if (in_array($key, ['channels', 'users'])) { - // skip - continue; - } - - // Add the channel property as a team - $result->addTeam($key, $value); - } - - // Itereate over the users in this channel - foreach ($data['users'] as $user) { - foreach ($user as $key => $value) { - $result->addPlayer($key, $value); - } - } - - // Offload more channels to parse - foreach ($data['channels'] as $channel) { - $this->processChannelsAndUsers($channel, $result); - } - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Quake2.php b/third_party/gameq_v3.1/GameQ/Protocols/Quake2.php deleted file mode 100644 index f0366c2c..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Quake2.php +++ /dev/null @@ -1,219 +0,0 @@ - "\xFF\xFF\xFF\xFFstatus\x00", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\xFF\xFF\xFF\xFF\x70\x72\x69\x6e\x74" => 'processStatus', - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'quake2'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'quake2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Quake 2 Server"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'gamename', - 'hostname' => 'hostname', - 'mapname' => 'mapname', - 'maxplayers' => 'maxclients', - 'mod' => 'g_gametype', - 'numplayers' => 'clients', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'ping' => 'ping', - 'score' => 'frags', - ], - ]; - - /** - * Handle response from the server - * - * @return mixed - * @throws Exception - */ - public function processResponse() - { - // Make a buffer - $buffer = new Buffer(implode('', $this->packets_response)); - - // Grab the header - $header = $buffer->readString("\x0A"); - - // Figure out which packet response this is - if (empty($header) || !array_key_exists($header, $this->responses)) { - throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); - } - - return call_user_func_array([$this, $this->responses[$header]], [$buffer]); - } - - /** - * Process the status response - * - * @param Buffer $buffer - * - * @return array - */ - protected function processStatus(Buffer $buffer) - { - // We need to split the data and offload - $results = $this->processServerInfo(new Buffer($buffer->readString("\x0A"))); - - $results = array_merge_recursive( - $results, - $this->processPlayers(new Buffer($buffer->getBuffer())) - ); - - unset($buffer); - - // Return results - return $results; - } - - /** - * Handle processing the server information - * - * @param Buffer $buffer - * - * @return array - */ - protected function processServerInfo(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - // Burn leading \ if one exists - $buffer->readString('\\'); - - // Key / value pairs - while ($buffer->getLength()) { - // Add result - $result->add( - trim($buffer->readString('\\')), - utf8_encode(trim($buffer->readStringMulti(['\\', "\x0a"]))) - ); - } - - $result->add('password', 0); - $result->add('mod', 0); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handle processing of player data - * - * @param Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - // Some games do not have a number of current players - $playerCount = 0; - - // Set the result to a new result instance - $result = new Result(); - - // Loop until we are out of data - while ($buffer->getLength()) { - // Make a new buffer with this block - $playerInfo = new Buffer($buffer->readString("\x0A")); - - // Add player info - $result->addPlayer('frags', $playerInfo->readString("\x20")); - $result->addPlayer('ping', $playerInfo->readString("\x20")); - - // Skip first " - $playerInfo->skip(1); - - // Add player name, encoded - $result->addPlayer('name', utf8_encode(trim(($playerInfo->readString('"'))))); - - // Skip first " - $playerInfo->skip(2); - - // Add address - $result->addPlayer('address', trim($playerInfo->readString('"'))); - - // Increment - $playerCount++; - - // Clear - unset($playerInfo); - } - - $result->add('clients', $playerCount); - - // Clear - unset($buffer, $playerCount); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Quake3.php b/third_party/gameq_v3.1/GameQ/Protocols/Quake3.php deleted file mode 100644 index 6269b927..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Quake3.php +++ /dev/null @@ -1,214 +0,0 @@ - "\xFF\xFF\xFF\xFF\x67\x65\x74\x73\x74\x61\x74\x75\x73\x0A", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\xFF\xFF\xFF\xFFstatusResponse" => 'processStatus', - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'quake3'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'quake3'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Quake 3 Server"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = null; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'gamename', - 'hostname' => 'sv_hostname', - 'mapname' => 'mapname', - 'maxplayers' => 'sv_maxclients', - 'mod' => 'g_gametype', - 'numplayers' => 'clients', - 'password' => ['g_needpass', 'pswrd'], - ], - // Individual - 'player' => [ - 'name' => 'name', - 'ping' => 'ping', - 'score' => 'frags', - ], - ]; - - /** - * Handle response from the server - * - * @return mixed - * @throws Exception - */ - public function processResponse() - { - // Make a buffer - $buffer = new Buffer(implode('', $this->packets_response)); - - // Grab the header - $header = $buffer->readString("\x0A"); - - // Figure out which packet response this is - if (empty($header) || !array_key_exists($header, $this->responses)) { - throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); - } - - return call_user_func_array([$this, $this->responses[$header]], [$buffer]); - } - - protected function processStatus(Buffer $buffer) - { - // We need to split the data and offload - $results = $this->processServerInfo(new Buffer($buffer->readString("\x0A"))); - - $results = array_merge_recursive( - $results, - $this->processPlayers(new Buffer($buffer->getBuffer())) - ); - - unset($buffer); - - // Return results - return $results; - } - - /** - * Handle processing the server information - * - * @param Buffer $buffer - * - * @return array - */ - protected function processServerInfo(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - // Burn leading \ if one exists - $buffer->readString('\\'); - - // Key / value pairs - while ($buffer->getLength()) { - // Add result - $result->add( - trim($buffer->readString('\\')), - utf8_encode(trim($buffer->readStringMulti(['\\', "\x0a"]))) - ); - } - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handle processing of player data - * - * @param Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processPlayers(Buffer $buffer) - { - // Some games do not have a number of current players - $playerCount = 0; - - // Set the result to a new result instance - $result = new Result(); - - // Loop until we are out of data - while ($buffer->getLength()) { - // Add player info - $result->addPlayer('frags', $buffer->readString("\x20")); - $result->addPlayer('ping', $buffer->readString("\x20")); - - // Look ahead to see if we have a name or team - $checkTeam = $buffer->lookAhead(1); - - // We have team info - if ($checkTeam != '' and $checkTeam != '"') { - $result->addPlayer('team', $buffer->readString("\x20")); - } - - // Check to make sure we have player name - $checkPlayerName = $buffer->read(); - - // Bad response - if ($checkPlayerName !== '"') { - throw new Exception('Expected " but got ' . $checkPlayerName . ' for beginning of player name string!'); - } - - // Add player name, encoded - $result->addPlayer('name', utf8_encode(trim($buffer->readString('"')))); - - // Burn ending delimiter - $buffer->read(); - - // Increment - $playerCount++; - } - - $result->add('clients', $playerCount); - - // Clear - unset($buffer, $playerCount); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Rust.php b/third_party/gameq_v3.1/GameQ/Protocols/Rust.php deleted file mode 100644 index 356cc19f..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Rust.php +++ /dev/null @@ -1,64 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; - -/** - * Class Rust - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Rust extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'rust'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Rust"; - - /** - * Overload so we can get max players from mp of keywords and num players from cp keyword - * - * @param Buffer $buffer - */ - protected function processDetails(Buffer $buffer) - { - $results = parent::processDetails($buffer); - - if ($results['keywords']) { - //get max players from mp of keywords and num players from cp keyword - preg_match_all('/(mp|cp)([\d]+)/', $results['keywords'], $matches); - $results['max_players'] = intval($matches[2][0]); - $results['num_players'] = intval($matches[2][1]); - } - - return $results; - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Samp.php b/third_party/gameq_v3.1/GameQ/Protocols/Samp.php deleted file mode 100644 index cf01f834..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Samp.php +++ /dev/null @@ -1,279 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Server; -use GameQ\Exception\Protocol as Exception; - -/** - * San Andreas Multiplayer Protocol Class (samp) - * - * Note: - * Player information will not be returned if player count is over 256 - * - * @author Austin Bischoff - */ -class Samp extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "SAMP%si", - self::PACKET_PLAYERS => "SAMP%sd", - self::PACKET_RULES => "SAMP%sr", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\x69" => "processStatus", // i - "\x64" => "processPlayers", // d - "\x72" => "processRules", // r - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'samp'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'samp'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "San Andreas Multiplayer"; - - /** - * Holds the calculated server code that is passed when querying for information - * - * @type string - */ - protected $server_code = null; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "samp://%s:%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => ['hostname', 'servername'], - 'mapname' => 'mapname', - 'maxplayers' => 'max_players', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'score' => 'score', - 'ping' => 'ping', - ], - ]; - - /** - * Handle some work before sending the packets out to the server - * - * @param \GameQ\Server $server - */ - public function beforeSend(Server $server) - { - - // Build the server code - $this->server_code = implode('', array_map('chr', explode('.', $server->ip()))) . - pack("S", $server->portClient()); - - // Loop over the packets and update them - foreach ($this->packets as $packetType => $packet) { - // Fill out the packet with the server info - $this->packets[$packetType] = sprintf($packet, $this->server_code); - } - } - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // Results that will be returned - $results = []; - - // Get the length of the server code so we can figure out how much to read later - $serverCodeLength = strlen($this->server_code); - - // We need to pre-sort these for split packets so we can do extra work where needed - foreach ($this->packets_response as $response) { - // Make new buffer - $buffer = new Buffer($response); - - // Check the header, should be SAMP - if (($header = $buffer->read(4)) !== 'SAMP') { - throw new Exception(__METHOD__ . " header response '{$header}' is not valid"); - } - - // Check to make sure the server response code matches what we sent - if ($buffer->read($serverCodeLength) !== $this->server_code) { - throw new Exception(__METHOD__ . " code check failed."); - } - - // Figure out what packet response this is for - $response_type = $buffer->read(1); - - // Figure out which packet response this is - if (!array_key_exists($response_type, $this->responses)) { - throw new Exception(__METHOD__ . " response type '{$response_type}' is not valid"); - } - - // Now we need to call the proper method - $results = array_merge( - $results, - call_user_func_array([$this, $this->responses[$response_type]], [$buffer]) - ); - - unset($buffer); - } - - return $results; - } - - /* - * Internal methods - */ - - /** - * Handles processing the server status data - * - * @param \GameQ\Buffer $buffer - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - protected function processStatus(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Always dedicated - $result->add('dedicated', 1); - - // Pull out the server information - $result->add('password', $buffer->readInt8()); - $result->add('num_players', $buffer->readInt16()); - $result->add('max_players', $buffer->readInt16()); - - // These are read differently for these last 3 - $result->add('servername', utf8_encode($buffer->read($buffer->readInt32()))); - $result->add('gametype', $buffer->read($buffer->readInt32())); - $result->add('language', $buffer->read($buffer->readInt32())); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the player data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Number of players - $result->add('num_players', $buffer->readInt16()); - - // Run until we run out of buffer - while ($buffer->getLength()) { - $result->addPlayer('id', $buffer->readInt8()); - $result->addPlayer('name', utf8_encode($buffer->readPascalString())); - $result->addPlayer('score', $buffer->readInt32()); - $result->addPlayer('ping', $buffer->readInt32()); - } - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the rules data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processRules(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Number of rules - $result->add('num_rules', $buffer->readInt16()); - - // Run until we run out of buffer - while ($buffer->getLength()) { - $result->add($buffer->readPascalString(), $buffer->readPascalString()); - } - - unset($buffer); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Sof2.php b/third_party/gameq_v3.1/GameQ/Protocols/Sof2.php deleted file mode 100644 index 96a4db25..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Sof2.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Soldier of Fortune 2 Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Sof2 extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'sof2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Solder of Fortune II"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "sof2mp://%s:%d/"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Soldat.php b/third_party/gameq_v3.1/GameQ/Protocols/Soldat.php deleted file mode 100644 index a9dbbc4e..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Soldat.php +++ /dev/null @@ -1,59 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Soldat - * - * @package GameQ\Protocols - * - * @author Marcel Bößendörfer - * @author Austin Bischoff - */ -class Soldat extends Ase -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'soldat'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Soldat"; - - /** - * query_port = client_port + 123 - * - * @type int - */ - protected $port_diff = 123; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "soldat://%s:%d/"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Source.php b/third_party/gameq_v3.1/GameQ/Protocols/Source.php deleted file mode 100644 index dbf9212a..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Source.php +++ /dev/null @@ -1,522 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Exception\Protocol as Exception; -use GameQ\Protocol; -use GameQ\Result; - -/** - * Valve Source Engine Protocol Class (A2S) - * - * This class is used as the basis for all other source based servers - * that rely on the source protocol for game querying. - * - * @SuppressWarnings(PHPMD.NumberOfChildren) - * - * @author Austin Bischoff - */ -class Source extends Protocol -{ - - /* - * Source engine type constants - */ - const SOURCE_ENGINE = 0, - GOLDSOURCE_ENGINE = 1; - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_CHALLENGE => "\xFF\xFF\xFF\xFF\x56\x00\x00\x00\x00", - self::PACKET_DETAILS => "\xFF\xFF\xFF\xFFTSource Engine Query\x00%s", - self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFF\x55%s", - self::PACKET_RULES => "\xFF\xFF\xFF\xFF\x56%s", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\x49" => "processDetails", // I - "\x6d" => "processDetailsGoldSource", // m, goldsource - "\x44" => "processPlayers", // D - "\x45" => "processRules", // E - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'source'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'source'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Source Server"; - - /** - * Define the Source engine type. By default it is assumed to be Source - * - * @type int - */ - protected $source_engine = self::SOURCE_ENGINE; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "steam://connect/%s:%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'game_descr', - 'hostname' => 'hostname', - 'mapname' => 'map', - 'maxplayers' => 'max_players', - 'mod' => 'game_dir', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'score' => 'score', - 'time' => 'time', - ], - ]; - - /** - * Parse the challenge response and apply it to all the packet types - * - * @param \GameQ\Buffer $challenge_buffer - * - * @return bool - * @throws \GameQ\Exception\Protocol - */ - public function challengeParseAndApply(Buffer $challenge_buffer) - { - - // Skip the header - $challenge_buffer->skip(5); - - // Apply the challenge and return - return $this->challengeApply($challenge_buffer->read(4)); - } - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - // Will hold the results when complete - $results = []; - - // Holds sorted response packets - $packets = []; - - // We need to pre-sort these for split packets so we can do extra work where needed - foreach ($this->packets_response as $response) { - $buffer = new Buffer($response); - - // Get the header of packet (long) - $header = $buffer->readInt32Signed(); - - // Single packet - if ($header == -1) { - // We need to peek and see what kind of engine this is for later processing - if ($buffer->lookAhead(1) == "\x6d") { - $this->source_engine = self::GOLDSOURCE_ENGINE; - } - - $packets[] = $buffer->getBuffer(); - continue; - } else { - // Split packet - - // Packet Id (long) - $packet_id = $buffer->readInt32Signed() + 10; - - // Add the buffer to the packet as another array - $packets[$packet_id][] = $buffer->getBuffer(); - } - } - - // Free up memory - unset($response, $packet_id, $buffer, $header); - - // Now that we have the packets sorted we need to iterate and process them - foreach ($packets as $packet_id => $packet) { - // We first need to off load split packets to combine them - if (is_array($packet)) { - $buffer = new Buffer($this->processPackets($packet_id, $packet)); - } else { - $buffer = new Buffer($packet); - } - - // Figure out what packet response this is for - $response_type = $buffer->read(1); - - // Figure out which packet response this is - if (!array_key_exists($response_type, $this->responses)) { - throw new Exception(__METHOD__ . " response type '{$response_type}' is not valid"); - } - - // Now we need to call the proper method - $results = array_merge( - $results, - call_user_func_array([$this, $this->responses[$response_type]], [$buffer]) - ); - - unset($buffer); - } - - // Free up memory - unset($packets, $packet, $packet_id, $response_type); - - return $results; - } - - /* - * Internal methods - */ - - /** - * Process the split packets and decompress if necessary - * - * @SuppressWarnings(PHPMD.UnusedLocalVariable) - * - * @param $packet_id - * @param array $packets - * - * @return string - * @throws \GameQ\Exception\Protocol - */ - protected function processPackets($packet_id, array $packets = []) - { - - // Init array so we can order - $packs = []; - - // We have multiple packets so we need to get them and order them - foreach ($packets as $i => $packet) { - // Make a buffer so we can read this info - $buffer = new Buffer($packet); - - // Gold source - if ($this->source_engine == self::GOLDSOURCE_ENGINE) { - // Grab the packet number (byte) - $packet_number = $buffer->readInt8(); - - // We need to burn the extra header (\xFF\xFF\xFF\xFF) on first loop - if ($i == 0) { - $buffer->read(4); - } - - // Now add the rest of the packet to the new array with the packet_number as the id so we can order it - $packs[$packet_number] = $buffer->getBuffer(); - } else { - // Number of packets in this set (byte) - $buffer->readInt8(); - - // The current packet number (byte) - $packet_number = $buffer->readInt8(); - - // Check to see if this is compressed - // @todo: Check to make sure these decompress correctly, new changes may affect this loop. - if ($packet_id & 0x80000000) { - // Check to see if we have Bzip2 installed - if (!function_exists('bzdecompress')) { - // @codeCoverageIgnoreStart - throw new Exception( - 'Bzip2 is not installed. See http://www.php.net/manual/en/book.bzip2.php for more info.', - 0 - ); - // @codeCoverageIgnoreEnd - } - - // Get the length of the packet (long) - $packet_length = $buffer->readInt32Signed(); - - // Checksum for the decompressed packet (long), burn it - doesnt work in split responses - $buffer->readInt32Signed(); - - // Try to decompress - $result = bzdecompress($buffer->getBuffer()); - - // Now verify the length - if (strlen($result) != $packet_length) { - // @codeCoverageIgnoreStart - throw new Exception( - "Checksum for compressed packet failed! Length expected: {$packet_length}, length - returned: " . strlen($result) - ); - // @codeCoverageIgnoreEnd - } - - // We need to burn the extra header (\xFF\xFF\xFF\xFF) on first loop - if ($i == 0) { - $result = substr($result, 4); - } - } else { - // Get the packet length (short), burn it - $buffer->readInt16Signed(); - - // We need to burn the extra header (\xFF\xFF\xFF\xFF) on first loop - if ($i == 0) { - $buffer->read(4); - } - - // Grab the rest of the buffer as a result - $result = $buffer->getBuffer(); - } - - // Add this packet to the list - $packs[$packet_number] = $result; - } - - unset($buffer); - } - - // Free some memory - unset($packets, $packet); - - // Sort the packets by packet number - ksort($packs); - - // Now combine the packs into one and return - return implode("", $packs); - } - - /** - * Handles processing the details data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return mixed - * @throws \GameQ\Exception\Protocol - */ - protected function processDetails(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - $result->add('protocol', $buffer->readInt8()); - $result->add('hostname', $buffer->readString()); - $result->add('map', $buffer->readString()); - $result->add('game_dir', $buffer->readString()); - $result->add('game_descr', $buffer->readString()); - $result->add('steamappid', $buffer->readInt16()); - $result->add('num_players', $buffer->readInt8()); - $result->add('max_players', $buffer->readInt8()); - $result->add('num_bots', $buffer->readInt8()); - $result->add('dedicated', $buffer->read()); - $result->add('os', $buffer->read()); - $result->add('password', $buffer->readInt8()); - $result->add('secure', $buffer->readInt8()); - - // Special result for The Ship only (appid=2400) - if ($result->get('steamappid') == 2400) { - $result->add('game_mode', $buffer->readInt8()); - $result->add('witness_count', $buffer->readInt8()); - $result->add('witness_time', $buffer->readInt8()); - } - - $result->add('version', $buffer->readString()); - - // Because of php 5.4... - $edfCheck = $buffer->lookAhead(1); - - // Extra data flag - if (!empty($edfCheck)) { - $edf = $buffer->readInt8(); - - if ($edf & 0x80) { - $result->add('port', $buffer->readInt16Signed()); - } - - if ($edf & 0x10) { - $result->add('steam_id', $buffer->readInt64()); - } - - if ($edf & 0x40) { - $result->add('sourcetv_port', $buffer->readInt16Signed()); - $result->add('sourcetv_name', $buffer->readString()); - } - - if ($edf & 0x20) { - $result->add('keywords', $buffer->readString()); - } - - if ($edf & 0x01) { - $result->add('game_id', $buffer->readInt64()); - } - - unset($edf); - } - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the server details from goldsource response - * - * @param \GameQ\Buffer $buffer - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - protected function processDetailsGoldSource(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - $result->add('address', $buffer->readString()); - $result->add('hostname', $buffer->readString()); - $result->add('map', $buffer->readString()); - $result->add('game_dir', $buffer->readString()); - $result->add('game_descr', $buffer->readString()); - $result->add('num_players', $buffer->readInt8()); - $result->add('max_players', $buffer->readInt8()); - $result->add('version', $buffer->readInt8()); - $result->add('dedicated', $buffer->read()); - $result->add('os', $buffer->read()); - $result->add('password', $buffer->readInt8()); - - // Mod section - $result->add('ismod', $buffer->readInt8()); - - // We only run these if ismod is 1 (true) - if ($result->get('ismod') == 1) { - $result->add('mod_urlinfo', $buffer->readString()); - $result->add('mod_urldl', $buffer->readString()); - $buffer->skip(); - $result->add('mod_version', $buffer->readInt32Signed()); - $result->add('mod_size', $buffer->readInt32Signed()); - $result->add('mod_type', $buffer->readInt8()); - $result->add('mod_cldll', $buffer->readInt8()); - } - - $result->add('secure', $buffer->readInt8()); - $result->add('num_bots', $buffer->readInt8()); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the player data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return mixed - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Pull out the number of players - $num_players = $buffer->readInt8(); - - // Player count - $result->add('num_players', $num_players); - - // No players so no need to look any further - if ($num_players == 0) { - return $result->fetch(); - } - - // Players list - while ($buffer->getLength()) { - $result->addPlayer('id', $buffer->readInt8()); - $result->addPlayer('name', $buffer->readString()); - $result->addPlayer('score', $buffer->readInt32Signed()); - $result->addPlayer('time', $buffer->readFloat32()); - } - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the rules data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return mixed - */ - protected function processRules(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Count the number of rules - $num_rules = $buffer->readInt16Signed(); - - // Add the count of the number of rules this server has - $result->add('num_rules', $num_rules); - - // Rules - while ($buffer->getLength()) { - $result->add($buffer->readString(), $buffer->readString()); - } - - unset($buffer); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Teamspeak2.php b/third_party/gameq_v3.1/GameQ/Protocols/Teamspeak2.php deleted file mode 100644 index df0d59aa..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Teamspeak2.php +++ /dev/null @@ -1,290 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Server; -use GameQ\Exception\Protocol as Exception; - -/** - * Teamspeak 2 Protocol Class - * - * All values are utf8 encoded upon processing - * - * This code ported from GameQ v1/v2. Credit to original author(s) as I just updated it to - * work within this new system. - * - * @author Austin Bischoff - */ -class Teamspeak2 extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_DETAILS => "sel %d\x0asi\x0a", - self::PACKET_CHANNELS => "sel %d\x0acl\x0a", - self::PACKET_PLAYERS => "sel %d\x0apl\x0a", - ]; - - /** - * The transport mode for this protocol is TCP - * - * @type string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'teamspeak2'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'teamspeak2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Teamspeak 2"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "teamspeak://%s:%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - 'dedicated' => 'dedicated', - 'hostname' => 'server_name', - 'password' => 'server_password', - 'numplayers' => 'server_currentusers', - 'maxplayers' => 'server_maxusers', - ], - // Player - 'player' => [ - 'id' => 'p_id', - 'team' => 'c_id', - 'name' => 'nick', - ], - // Team - 'team' => [ - 'id' => 'id', - 'name' => 'name', - ], - ]; - - /** - * Before we send off the queries we need to update the packets - * - * @param \GameQ\Server $server - * - * @throws \GameQ\Exception\Protocol - */ - public function beforeSend(Server $server) - { - - // Check to make sure we have a query_port because it is required - if (!isset($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) - || empty($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) - ) { - throw new Exception(__METHOD__ . " Missing required setting '" . Server::SERVER_OPTIONS_QUERY_PORT . "'."); - } - - // Let's loop the packets and set the proper pieces - foreach ($this->packets as $packet_type => $packet) { - // Update with the client port for the server - $this->packets[$packet_type] = sprintf($packet, $server->portClient()); - } - } - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // Make a new buffer out of all of the packets - $buffer = new Buffer(implode('', $this->packets_response)); - - // Check the header [TS] - if (($header = trim($buffer->readString("\n"))) !== '[TS]') { - throw new Exception(__METHOD__ . " Expected header '{$header}' does not match expected '[TS]'."); - } - - // Split this buffer as the data blocks are bound by "OK" and drop any empty values - $sections = array_filter(explode("OK", $buffer->getBuffer()), function ($value) { - - $value = trim($value); - - return !empty($value); - }); - - // Trim up the values to remove extra whitespace - $sections = array_map('trim', $sections); - - // Set the result to a new result instance - $result = new Result(); - - // Now we need to iterate over the sections and off load the processing - foreach ($sections as $section) { - // Grab a snip of the data so we can figure out what it is - $check = substr($section, 0, 7); - - // Offload to the proper method - if ($check == 'server_') { - // Server settings and info - $this->processDetails($section, $result); - } elseif ($check == "id\tcode") { - // Channel info - $this->processChannels($section, $result); - } elseif ($check == "p_id\tc_") { - // Player info - $this->processPlayers($section, $result); - } - } - - unset($buffer, $sections, $section, $check); - - return $result->fetch(); - } - - /* - * Internal methods - */ - - - /** - * Handles processing the details data into a usable format - * - * @param string $data - * @param \GameQ\Result $result - */ - protected function processDetails($data, Result &$result) - { - - // Create a buffer - $buffer = new Buffer($data); - - // Always dedicated - $result->add('dedicated', 1); - - // Let's loop until we run out of data - while ($buffer->getLength()) { - // Grab the row, which is an item - $row = trim($buffer->readString("\n")); - - // Split out the information - list($key, $value) = explode('=', $row, 2); - - // Add this to the result - $result->add($key, utf8_encode($value)); - } - - unset($data, $buffer, $row, $key, $value); - } - - /** - * Process the channel listing - * - * @param string $data - * @param \GameQ\Result $result - */ - protected function processChannels($data, Result &$result) - { - - // Create a buffer - $buffer = new Buffer($data); - - // The first line holds the column names, data returned is in column/row format - $columns = explode("\t", trim($buffer->readString("\n")), 9); - - // Loop through the rows until we run out of information - while ($buffer->getLength()) { - // Grab the row, which is a tabbed list of items - $row = trim($buffer->readString("\n")); - - // Explode and merge the data with the columns, then parse - $data = array_combine($columns, explode("\t", $row, 9)); - - foreach ($data as $key => $value) { - // Now add the data to the result - $result->addTeam($key, utf8_encode($value)); - } - } - - unset($data, $buffer, $row, $columns, $key, $value); - } - - /** - * Process the user listing - * - * @param string $data - * @param \GameQ\Result $result - */ - protected function processPlayers($data, Result &$result) - { - - // Create a buffer - $buffer = new Buffer($data); - - // The first line holds the column names, data returned is in column/row format - $columns = explode("\t", trim($buffer->readString("\n")), 16); - - // Loop through the rows until we run out of information - while ($buffer->getLength()) { - // Grab the row, which is a tabbed list of items - $row = trim($buffer->readString("\n")); - - // Explode and merge the data with the columns, then parse - $data = array_combine($columns, explode("\t", $row, 16)); - - foreach ($data as $key => $value) { - // Now add the data to the result - $result->addPlayer($key, utf8_encode($value)); - } - } - - unset($data, $buffer, $row, $columns, $key, $value); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Teamspeak3.php b/third_party/gameq_v3.1/GameQ/Protocols/Teamspeak3.php deleted file mode 100644 index c66f6a44..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Teamspeak3.php +++ /dev/null @@ -1,328 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Server; -use GameQ\Exception\Protocol as Exception; - -/** - * Teamspeak 3 Protocol Class - * - * All values are utf8 encoded upon processing - * - * This code ported from GameQ v1/v2. Credit to original author(s) as I just updated it to - * work within this new system. - * - * @author Austin Bischoff - */ -class Teamspeak3 extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_DETAILS => "use port=%d\x0Aserverinfo\x0A", - self::PACKET_PLAYERS => "use port=%d\x0Aclientlist\x0A", - self::PACKET_CHANNELS => "use port=%d\x0Achannellist -topic\x0A", - ]; - - /** - * The transport mode for this protocol is TCP - * - * @type string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'teamspeak3'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'teamspeak3'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Teamspeak 3"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "ts3server://%s?port=%d"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - 'dedicated' => 'dedicated', - 'hostname' => 'virtualserver_name', - 'password' => 'virtualserver_flag_password', - 'numplayers' => 'numplayers', - 'maxplayers' => 'virtualserver_maxclients', - ], - // Player - 'player' => [ - 'id' => 'clid', - 'team' => 'cid', - 'name' => 'client_nickname', - ], - // Team - 'team' => [ - 'id' => 'cid', - 'name' => 'channel_name', - ], - ]; - - /** - * Before we send off the queries we need to update the packets - * - * @param \GameQ\Server $server - * - * @throws \GameQ\Exception\Protocol - */ - public function beforeSend(Server $server) - { - - // Check to make sure we have a query_port because it is required - if (!isset($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) - || empty($this->options[Server::SERVER_OPTIONS_QUERY_PORT]) - ) { - throw new Exception(__METHOD__ . " Missing required setting '" . Server::SERVER_OPTIONS_QUERY_PORT . "'."); - } - - // Let's loop the packets and set the proper pieces - foreach ($this->packets as $packet_type => $packet) { - // Update with the client port for the server - $this->packets[$packet_type] = sprintf($packet, $server->portClient()); - } - } - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // Make a new buffer out of all of the packets - $buffer = new Buffer(implode('', $this->packets_response)); - - // Check the header TS3 - if (($header = trim($buffer->readString("\n"))) !== 'TS3') { - throw new Exception(__METHOD__ . " Expected header '{$header}' does not match expected 'TS3'."); - } - - // Convert all the escaped characters - $raw = str_replace( - [ - '\\\\', // Translate escaped \ - '\\/', // Translate escaped / - ], - [ - '\\', - '/', - ], - $buffer->getBuffer() - ); - - // Explode the sections and filter to remove empty, junk ones - $sections = array_filter(explode("\n", $raw), function ($value) { - - $value = trim($value); - - // Not empty string or a message response for "error id=\d" - return !empty($value) && substr($value, 0, 5) !== 'error'; - }); - - // Trim up the values to remove extra whitespace - $sections = array_map('trim', $sections); - - // Set the result to a new result instance - $result = new Result(); - - // Iterate over the sections and offload the parsing - foreach ($sections as $section) { - // Grab a snip of the data so we can figure out what it is - $check = substr(trim($section), 0, 4); - - // Use the first part of the response to figure out where we need to go - if ($check == 'virt') { - // Server info - $this->processDetails($section, $result); - } elseif ($check == 'cid=') { - // Channels - $this->processChannels($section, $result); - } elseif ($check == 'clid') { - // Clients (players) - $this->processPlayers($section, $result); - } - } - - unset($buffer, $sections, $section, $check); - - return $result->fetch(); - } - - /* - * Internal methods - */ - - /** - * Process the properties of the data. - * - * Takes data in "key1=value1 key2=value2 ..." and processes it into a usable format - * - * @param $data - * - * @return array - */ - protected function processProperties($data) - { - - // Will hold the properties we are sending back - $properties = []; - - // All of these are split on space - $items = explode(' ', $data); - - // Iterate over the items - foreach ($items as $item) { - // Explode and make sure we always have 2 items in the array - list($key, $value) = array_pad(explode('=', $item, 2), 2, ''); - - // Convert spaces and other character changes - $properties[$key] = utf8_encode(str_replace( - [ - '\\s', // Translate spaces - ], - [ - ' ', - ], - $value - )); - } - - return $properties; - } - - /** - * Handles processing the details data into a usable format - * - * @param string $data - * @param \GameQ\Result $result - */ - protected function processDetails($data, Result &$result) - { - - // Offload the parsing for these values - $properties = $this->processProperties($data); - - // Always dedicated - $result->add('dedicated', 1); - - // Iterate over the properties - foreach ($properties as $key => $value) { - $result->add($key, $value); - } - - // We need to manually figure out the number of players - $result->add( - 'numplayers', - ($properties['virtualserver_clientsonline'] - $properties['virtualserver_queryclientsonline']) - ); - - unset($data, $properties, $key, $value); - } - - /** - * Process the channel listing - * - * @param string $data - * @param \GameQ\Result $result - */ - protected function processChannels($data, Result &$result) - { - - // We need to split the data at the pipe - $channels = explode('|', $data); - - // Iterate over the channels - foreach ($channels as $channel) { - // Offload the parsing for these values - $properties = $this->processProperties($channel); - - // Iterate over the properties - foreach ($properties as $key => $value) { - $result->addTeam($key, $value); - } - } - - unset($data, $channel, $channels, $properties, $key, $value); - } - - /** - * Process the user listing - * - * @param string $data - * @param \GameQ\Result $result - */ - protected function processPlayers($data, Result &$result) - { - - // We need to split the data at the pipe - $players = explode('|', $data); - - // Iterate over the channels - foreach ($players as $player) { - // Offload the parsing for these values - $properties = $this->processProperties($player); - - // Iterate over the properties - foreach ($properties as $key => $value) { - $result->addPlayer($key, $value); - } - } - - unset($data, $player, $players, $properties, $key, $value); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Teeworlds.php b/third_party/gameq_v3.1/GameQ/Protocols/Teeworlds.php deleted file mode 100644 index 1bdaa472..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Teeworlds.php +++ /dev/null @@ -1,181 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Teeworlds Protocol class - * - * Only supports versions > 0.5 - * - * @author Austin Bischoff - * @author Marcel Bößendörfer - */ -class Teeworlds extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_ALL => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x67\x69\x65\x33\x05", - // 0.5 Packet (not compatible, maybe some wants to implement "Teeworldsold") - //self::PACKET_STATUS => "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFgief", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffinf35" => "processAll", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'teeworlds'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'teeworlds'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Teeworlds Server"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "steam://connect/%s:%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'hostname', - 'mapname' => 'map', - 'maxplayers' => 'num_players_total', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'score' => 'score', - ], - ]; - - /** - * Process the response - * - * @return array - * @throws Exception - */ - public function processResponse() - { - // Holds the results - $results = []; - - // Iterate over the packets - foreach ($this->packets_response as $response) { - // Make a buffer - $buffer = new Buffer($response); - - // Grab the header - $header = $buffer->readString(); - - // Figure out which packet response this is - if (!array_key_exists($header, $this->responses)) { - throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); - } - - // Now we need to call the proper method - $results = array_merge( - $results, - call_user_func_array([$this, $this->responses[$header]], [$buffer]) - ); - } - - unset($buffer); - - return $results; - } - - /** - * Handle processing all of the data returned - * - * @param Buffer $buffer - * - * @return array - */ - protected function processAll(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - // Always dedicated - $result->add('dedicated', 1); - - $result->add('version', $buffer->readString()); - $result->add('hostname', $buffer->readString()); - $result->add('map', $buffer->readString()); - $result->add('game_descr', $buffer->readString()); - $result->add('flags', $buffer->readString()); // not sure about that - $result->add('num_players', $buffer->readString()); - $result->add('maxplayers', $buffer->readString()); - $result->add('num_players_total', $buffer->readString()); - $result->add('maxplayers_total', $buffer->readString()); - - // Players - while ($buffer->getLength()) { - $result->addPlayer('name', $buffer->readString()); - $result->addPlayer('clan', $buffer->readString()); - $result->addPlayer('flag', $buffer->readString()); - $result->addPlayer('score', $buffer->readString()); - $result->addPlayer('team', $buffer->readString()); - } - - unset($buffer); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Terraria.php b/third_party/gameq_v3.1/GameQ/Protocols/Terraria.php deleted file mode 100644 index d9455ef5..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Terraria.php +++ /dev/null @@ -1,59 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Terraria - * - * @package GameQ\Protocols - * - * @author Austin Bischoff - */ -class Terraria extends Tshock -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'terraria'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Terraria"; - - /** - * query_port = client_port + 101 - * 7878 = 7777 + 101 - * - * @type int - */ - protected $port_diff = 101; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "steam://connect/%s:%d/"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Tf2.php b/third_party/gameq_v3.1/GameQ/Protocols/Tf2.php deleted file mode 100644 index e08411b7..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Tf2.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Tf2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Tf2 extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'tf2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Team Fortress 2"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Tshock.php b/third_party/gameq_v3.1/GameQ/Protocols/Tshock.php deleted file mode 100644 index 551a09e4..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Tshock.php +++ /dev/null @@ -1,157 +0,0 @@ -. - */ -namespace GameQ\Protocols; - -use GameQ\Exception\Protocol as Exception; -use GameQ\Result; - -/** - * Tshock Protocol Class - * - * Result from this call should be a header + JSON response - * - * References: - * - https://tshock.atlassian.net/wiki/display/TSHOCKPLUGINS/REST+API+Endpoints#RESTAPIEndpoints-/status - * - http://tshock.co/xf/index.php?threads/rest-tshock-server-status-image.430/ - * - * Special thanks to intradox and Ruok2bu for game & protocol references - * - * @author Austin Bischoff - */ -class Tshock extends Http -{ - /** - * Packets to send - * - * @var array - */ - protected $packets = [ - self::PACKET_STATUS => "GET /v2/server/status?players=true&rules=true HTTP/1.0\r\nAccept: */*\r\n\r\n", - ]; - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'tshock'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'tshock'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Tshock"; - - /** - * Normalize some items - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'hostname', - 'mapname' => 'world', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'nickname', - 'team' => 'team', - ], - ]; - - /** - * Process the response - * - * @return array - * @throws Exception - */ - public function processResponse() - { - if (empty($this->packets_response)) { - return []; - } - - // Implode and rip out the JSON - preg_match('/\{(.*)\}/ms', implode('', $this->packets_response), $matches); - - // Return should be JSON, let's validate - if (!isset($matches[0]) || ($json = json_decode($matches[0])) === null) { - throw new Exception("JSON response from Tshock protocol is invalid."); - } - - // Check the status response - if ($json->status != 200) { - throw new Exception("JSON status from Tshock protocol response was '{$json->status}', expected '200'."); - } - - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - // Add server items - $result->add('hostname', $json->name); - $result->add('game_port', $json->port); - $result->add('serverversion', $json->serverversion); - $result->add('world', $json->world); - $result->add('uptime', $json->uptime); - $result->add('password', (int)$json->serverpassword); - $result->add('numplayers', $json->playercount); - $result->add('maxplayers', $json->maxplayers); - - // Parse players - foreach ($json->players as $player) { - $result->addPlayer('nickname', $player->nickname); - $result->addPlayer('username', $player->username); - $result->addPlayer('group', $player->group); - $result->addPlayer('active', (int)$player->active); - $result->addPlayer('state', $player->state); - $result->addPlayer('team', $player->team); - } - - // Make rules into simple array - $rules = []; - - // Parse rules - foreach ($json->rules as $rule => $value) { - // Add rule but convert boolean into int (0|1) - $rules[$rule] = (is_bool($value)) ? (int)$value : $value; - } - - // Add rules - $result->add('rules', $rules); - - unset($rules, $rule, $player, $value); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Unreal2.php b/third_party/gameq_v3.1/GameQ/Protocols/Unreal2.php deleted file mode 100644 index 0ef06757..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Unreal2.php +++ /dev/null @@ -1,246 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Unreal 2 Protocol class - * - * @author Austin Bischoff - */ -class Unreal2 extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_DETAILS => "\x79\x00\x00\x00\x00", - self::PACKET_RULES => "\x79\x00\x00\x00\x01", - self::PACKET_PLAYERS => "\x79\x00\x00\x00\x02", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\x80\x00\x00\x00\x00" => "processDetails", // 0 - "\x80\x00\x00\x00\x01" => "processRules", // 1 - "\x80\x00\x00\x00\x02" => "processPlayers", // 2 - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'unreal2'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'unreal2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Unreal 2"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'ServerMode', - 'gametype' => 'gametype', - 'hostname' => 'servername', - 'mapname' => 'mapname', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'score' => 'score', - ], - ]; - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // Will hold the packets after sorting - $packets = []; - - // We need to pre-sort these for split packets so we can do extra work where needed - foreach ($this->packets_response as $response) { - $buffer = new Buffer($response); - - // Pull out the header - $header = $buffer->read(5); - - // Add the packet to the proper section, we will combine later - $packets[$header][] = $buffer->getBuffer(); - } - - unset($buffer); - - $results = []; - - // Now let's iterate and process - foreach ($packets as $header => $packetGroup) { - // Figure out which packet response this is - if (!array_key_exists($header, $this->responses)) { - throw new Exception(__METHOD__ . " response type '" . bin2hex($header) . "' is not valid"); - } - - // Now we need to call the proper method - $results = array_merge( - $results, - call_user_func_array([$this, $this->responses[$header]], [new Buffer(implode($packetGroup))]) - ); - } - - unset($packets); - - return $results; - } - - /* - * Internal methods - */ - - /** - * Handles processing the details data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return mixed - * @throws \GameQ\Exception\Protocol - */ - protected function processDetails(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - $result->add('serverid', $buffer->readInt32()); // 0 - $result->add('serverip', $buffer->readPascalString(1)); // empty - $result->add('gameport', $buffer->readInt32()); - $result->add('queryport', $buffer->readInt32()); // 0 - $result->add('servername', utf8_encode($buffer->readPascalString(1))); - $result->add('mapname', utf8_encode($buffer->readPascalString(1))); - $result->add('gametype', $buffer->readPascalString(1)); - $result->add('numplayers', $buffer->readInt32()); - $result->add('maxplayers', $buffer->readInt32()); - $result->add('ping', $buffer->readInt32()); // 0 - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the player data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return mixed - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Parse players - while ($buffer->getLength()) { - // Player id - if (($id = $buffer->readInt32()) !== 0) { - // Add the results - $result->addPlayer('id', $id); - $result->addPlayer('name', utf8_encode($buffer->readPascalString(1))); - $result->addPlayer('ping', $buffer->readInt32()); - $result->addPlayer('score', $buffer->readInt32()); - - // Skip the next 4, unsure what they are for - $buffer->skip(4); - } - } - - unset($buffer, $id); - - return $result->fetch(); - } - - /** - * Handles processing the rules data into a usable format - * - * @param \GameQ\Buffer $buffer - * - * @return mixed - */ - protected function processRules(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Named values - $inc = -1; - while ($buffer->getLength()) { - // Grab the key - $key = $buffer->readPascalString(1); - - // Make sure mutators don't overwrite each other - if ($key === 'Mutator') { - $key .= ++$inc; - } - - $result->add(strtolower($key), utf8_encode($buffer->readPascalString(1))); - } - - unset($buffer); - - return $result->fetch(); - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ut2004.php b/third_party/gameq_v3.1/GameQ/Protocols/Ut2004.php deleted file mode 100644 index 953089f9..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Ut2004.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Unreal Tournament 2004 Protocol Class - * - * @author Austin Bischoff - */ -class Ut2004 extends Unreal2 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ut2004'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Unreal Tournament 2004"; -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ut3.php b/third_party/gameq_v3.1/GameQ/Protocols/Ut3.php deleted file mode 100644 index b55cc340..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Ut3.php +++ /dev/null @@ -1,133 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Unreal Tournament 3 Protocol Class - * - * Note: The response from UT3 appears to not be consistent. Many times packets are incomplete or there are extra - * "echoes" in the responses. This may cause issues like odd characters showing up in the keys for the player and team - * array responses. Not sure much can be done about it. - * - * @author Austin Bischoff - */ -class Ut3 extends Gamespy3 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ut3'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Unreal Tournament 3"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - 'dedicated' => 'bIsDedicated', - 'hostname' => 'hostname', - 'numplayers' => 'numplayers', - ], - ]; - - /** - * Overload the response process so we can make some changes - * - * @return array - */ - public function processResponse() - { - - // Grab the result from the parent - /** @type array $result */ - $result = parent::processResponse(); - - // Move some stuff around - $this->renameResult($result, 'OwningPlayerName', 'hostname'); - $this->renameResult($result, 'p1073741825', 'mapname'); - $this->renameResult($result, 'p1073741826', 'gametype'); - $this->renameResult($result, 'p1073741827', 'servername'); - $this->renameResult($result, 'p1073741828', 'custom_mutators'); - $this->renameResult($result, 'gamemode', 'open'); - $this->renameResult($result, 's32779', 'gamemode'); - $this->renameResult($result, 's0', 'bot_skill'); - $this->renameResult($result, 's6', 'pure_server'); - $this->renameResult($result, 's7', 'password'); - $this->renameResult($result, 's8', 'vs_bots'); - $this->renameResult($result, 's10', 'force_respawn'); - $this->renameResult($result, 'p268435704', 'frag_limit'); - $this->renameResult($result, 'p268435705', 'time_limit'); - $this->renameResult($result, 'p268435703', 'numbots'); - $this->renameResult($result, 'p268435717', 'stock_mutators'); - - // Put custom mutators into an array - if (isset($result['custom_mutators'])) { - $result['custom_mutators'] = explode("\x1c", $result['custom_mutators']); - } - - // Delete some unknown stuff - $this->deleteResult($result, ['s1', 's9', 's11', 's12', 's13', 's14']); - - // Return the result - return $result; - } - - /** - * Dirty hack to rename result entries into something more useful - * - * @param array $result - * @param string $old - * @param string $new - */ - protected function renameResult(array &$result, $old, $new) - { - - // Check to see if the old item is there - if (isset($result[$old])) { - $result[$new] = $result[$old]; - unset($result[$old]); - } - } - - /** - * Dirty hack to delete result items - * - * @param array $result - * @param array $array - */ - protected function deleteResult(array &$result, array $array) - { - - foreach ($array as $key) { - unset($result[$key]); - } - } -} diff --git a/third_party/gameq_v3.1/GameQ/Protocols/Ventrilo.php b/third_party/gameq_v3.1/GameQ/Protocols/Ventrilo.php deleted file mode 100644 index 6986bedc..00000000 --- a/third_party/gameq_v3.1/GameQ/Protocols/Ventrilo.php +++ /dev/null @@ -1,877 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Ventrilo Protocol Class - * - * Note that a password is not required for versions >= 3.0.3 - * - * All values are utf8 encoded upon processing - * - * This code ported from GameQ v1/v2. Credit to original author(s) as I just updated it to - * work within this new system. - * - * @author Austin Bischoff - */ -class Ventrilo extends Protocol -{ - - /** - * Array of packets we want to look up. - * Each key should correspond to a defined method in this or a parent class - * - * @type array - */ - protected $packets = [ - self::PACKET_ALL => - "V\xc8\xf4\xf9`\xa2\x1e\xa5M\xfb\x03\xccQN\xa1\x10\x95\xaf\xb2g\x17g\x812\xfbW\xfd\x8e\xd2\x22r\x034z\xbb\x98", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'ventrilo'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ventrilo'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Ventrilo"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "ventrilo://%s:%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - 'dedicated' => 'dedicated', - 'password' => 'auth', - 'hostname' => 'name', - 'numplayers' => 'clientcount', - 'maxplayers' => 'maxclients', - ], - // Player - 'player' => [ - 'team' => 'cid', - 'name' => 'name', - ], - // Team - 'team' => [ - 'id' => 'cid', - 'name' => 'name', - ], - ]; - - /** - * Encryption table for the header - * - * @type array - */ - private $head_encrypt_table = [ - 0x80, - 0xe5, - 0x0e, - 0x38, - 0xba, - 0x63, - 0x4c, - 0x99, - 0x88, - 0x63, - 0x4c, - 0xd6, - 0x54, - 0xb8, - 0x65, - 0x7e, - 0xbf, - 0x8a, - 0xf0, - 0x17, - 0x8a, - 0xaa, - 0x4d, - 0x0f, - 0xb7, - 0x23, - 0x27, - 0xf6, - 0xeb, - 0x12, - 0xf8, - 0xea, - 0x17, - 0xb7, - 0xcf, - 0x52, - 0x57, - 0xcb, - 0x51, - 0xcf, - 0x1b, - 0x14, - 0xfd, - 0x6f, - 0x84, - 0x38, - 0xb5, - 0x24, - 0x11, - 0xcf, - 0x7a, - 0x75, - 0x7a, - 0xbb, - 0x78, - 0x74, - 0xdc, - 0xbc, - 0x42, - 0xf0, - 0x17, - 0x3f, - 0x5e, - 0xeb, - 0x74, - 0x77, - 0x04, - 0x4e, - 0x8c, - 0xaf, - 0x23, - 0xdc, - 0x65, - 0xdf, - 0xa5, - 0x65, - 0xdd, - 0x7d, - 0xf4, - 0x3c, - 0x4c, - 0x95, - 0xbd, - 0xeb, - 0x65, - 0x1c, - 0xf4, - 0x24, - 0x5d, - 0x82, - 0x18, - 0xfb, - 0x50, - 0x86, - 0xb8, - 0x53, - 0xe0, - 0x4e, - 0x36, - 0x96, - 0x1f, - 0xb7, - 0xcb, - 0xaa, - 0xaf, - 0xea, - 0xcb, - 0x20, - 0x27, - 0x30, - 0x2a, - 0xae, - 0xb9, - 0x07, - 0x40, - 0xdf, - 0x12, - 0x75, - 0xc9, - 0x09, - 0x82, - 0x9c, - 0x30, - 0x80, - 0x5d, - 0x8f, - 0x0d, - 0x09, - 0xa1, - 0x64, - 0xec, - 0x91, - 0xd8, - 0x8a, - 0x50, - 0x1f, - 0x40, - 0x5d, - 0xf7, - 0x08, - 0x2a, - 0xf8, - 0x60, - 0x62, - 0xa0, - 0x4a, - 0x8b, - 0xba, - 0x4a, - 0x6d, - 0x00, - 0x0a, - 0x93, - 0x32, - 0x12, - 0xe5, - 0x07, - 0x01, - 0x65, - 0xf5, - 0xff, - 0xe0, - 0xae, - 0xa7, - 0x81, - 0xd1, - 0xba, - 0x25, - 0x62, - 0x61, - 0xb2, - 0x85, - 0xad, - 0x7e, - 0x9d, - 0x3f, - 0x49, - 0x89, - 0x26, - 0xe5, - 0xd5, - 0xac, - 0x9f, - 0x0e, - 0xd7, - 0x6e, - 0x47, - 0x94, - 0x16, - 0x84, - 0xc8, - 0xff, - 0x44, - 0xea, - 0x04, - 0x40, - 0xe0, - 0x33, - 0x11, - 0xa3, - 0x5b, - 0x1e, - 0x82, - 0xff, - 0x7a, - 0x69, - 0xe9, - 0x2f, - 0xfb, - 0xea, - 0x9a, - 0xc6, - 0x7b, - 0xdb, - 0xb1, - 0xff, - 0x97, - 0x76, - 0x56, - 0xf3, - 0x52, - 0xc2, - 0x3f, - 0x0f, - 0xb6, - 0xac, - 0x77, - 0xc4, - 0xbf, - 0x59, - 0x5e, - 0x80, - 0x74, - 0xbb, - 0xf2, - 0xde, - 0x57, - 0x62, - 0x4c, - 0x1a, - 0xff, - 0x95, - 0x6d, - 0xc7, - 0x04, - 0xa2, - 0x3b, - 0xc4, - 0x1b, - 0x72, - 0xc7, - 0x6c, - 0x82, - 0x60, - 0xd1, - 0x0d, - ]; - - /** - * Encryption table for the data - * - * @type array - */ - private $data_encrypt_table = [ - 0x82, - 0x8b, - 0x7f, - 0x68, - 0x90, - 0xe0, - 0x44, - 0x09, - 0x19, - 0x3b, - 0x8e, - 0x5f, - 0xc2, - 0x82, - 0x38, - 0x23, - 0x6d, - 0xdb, - 0x62, - 0x49, - 0x52, - 0x6e, - 0x21, - 0xdf, - 0x51, - 0x6c, - 0x76, - 0x37, - 0x86, - 0x50, - 0x7d, - 0x48, - 0x1f, - 0x65, - 0xe7, - 0x52, - 0x6a, - 0x88, - 0xaa, - 0xc1, - 0x32, - 0x2f, - 0xf7, - 0x54, - 0x4c, - 0xaa, - 0x6d, - 0x7e, - 0x6d, - 0xa9, - 0x8c, - 0x0d, - 0x3f, - 0xff, - 0x6c, - 0x09, - 0xb3, - 0xa5, - 0xaf, - 0xdf, - 0x98, - 0x02, - 0xb4, - 0xbe, - 0x6d, - 0x69, - 0x0d, - 0x42, - 0x73, - 0xe4, - 0x34, - 0x50, - 0x07, - 0x30, - 0x79, - 0x41, - 0x2f, - 0x08, - 0x3f, - 0x42, - 0x73, - 0xa7, - 0x68, - 0xfa, - 0xee, - 0x88, - 0x0e, - 0x6e, - 0xa4, - 0x70, - 0x74, - 0x22, - 0x16, - 0xae, - 0x3c, - 0x81, - 0x14, - 0xa1, - 0xda, - 0x7f, - 0xd3, - 0x7c, - 0x48, - 0x7d, - 0x3f, - 0x46, - 0xfb, - 0x6d, - 0x92, - 0x25, - 0x17, - 0x36, - 0x26, - 0xdb, - 0xdf, - 0x5a, - 0x87, - 0x91, - 0x6f, - 0xd6, - 0xcd, - 0xd4, - 0xad, - 0x4a, - 0x29, - 0xdd, - 0x7d, - 0x59, - 0xbd, - 0x15, - 0x34, - 0x53, - 0xb1, - 0xd8, - 0x50, - 0x11, - 0x83, - 0x79, - 0x66, - 0x21, - 0x9e, - 0x87, - 0x5b, - 0x24, - 0x2f, - 0x4f, - 0xd7, - 0x73, - 0x34, - 0xa2, - 0xf7, - 0x09, - 0xd5, - 0xd9, - 0x42, - 0x9d, - 0xf8, - 0x15, - 0xdf, - 0x0e, - 0x10, - 0xcc, - 0x05, - 0x04, - 0x35, - 0x81, - 0xb2, - 0xd5, - 0x7a, - 0xd2, - 0xa0, - 0xa5, - 0x7b, - 0xb8, - 0x75, - 0xd2, - 0x35, - 0x0b, - 0x39, - 0x8f, - 0x1b, - 0x44, - 0x0e, - 0xce, - 0x66, - 0x87, - 0x1b, - 0x64, - 0xac, - 0xe1, - 0xca, - 0x67, - 0xb4, - 0xce, - 0x33, - 0xdb, - 0x89, - 0xfe, - 0xd8, - 0x8e, - 0xcd, - 0x58, - 0x92, - 0x41, - 0x50, - 0x40, - 0xcb, - 0x08, - 0xe1, - 0x15, - 0xee, - 0xf4, - 0x64, - 0xfe, - 0x1c, - 0xee, - 0x25, - 0xe7, - 0x21, - 0xe6, - 0x6c, - 0xc6, - 0xa6, - 0x2e, - 0x52, - 0x23, - 0xa7, - 0x20, - 0xd2, - 0xd7, - 0x28, - 0x07, - 0x23, - 0x14, - 0x24, - 0x3d, - 0x45, - 0xa5, - 0xc7, - 0x90, - 0xdb, - 0x77, - 0xdd, - 0xea, - 0x38, - 0x59, - 0x89, - 0x32, - 0xbc, - 0x00, - 0x3a, - 0x6d, - 0x61, - 0x4e, - 0xdb, - 0x29, - ]; - - /** - * Process the response - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // We need to decrypt the packets - $decrypted = $this->decryptPackets($this->packets_response); - - // Now let us convert special characters from hex to ascii all at once - $decrypted = preg_replace_callback( - '|%([0-9A-F]{2})|', - function ($matches) { - - // Pack this into ascii - return pack('H*', $matches[1]); - }, - $decrypted - ); - - // Explode into lines - $lines = explode("\n", $decrypted); - - // Set the result to a new result instance - $result = new Result(); - - // Always dedicated - $result->add('dedicated', 1); - - // Defaults - $channelFields = 5; - $playerFields = 7; - - // Iterate over the lines - foreach ($lines as $line) { - // Trim all the outlying space - $line = trim($line); - - // We dont have anything in this line - if (strlen($line) == 0) { - continue; - } - - /** - * Everything is in this format: ITEM: VALUE - * - * Example: - * ... - * MAXCLIENTS: 175 - * VOICECODEC: 3,Speex - * VOICEFORMAT: 31,32 KHz%2C 16 bit%2C 9 Qlty - * UPTIME: 9167971 - * PLATFORM: Linux-i386 - * VERSION: 3.0.6 - * ... - */ - - // Check to see if we have a colon, every line should - if (($colon_pos = strpos($line, ":")) !== false && $colon_pos > 0) { - // Split the line into key/value pairs - list($key, $value) = explode(':', $line, 2); - - // Lower the font of the key - $key = strtolower($key); - - // Trim the value of extra space - $value = trim($value); - - // Switch and offload items as needed - switch ($key) { - case 'client': - $this->processPlayer($value, $playerFields, $result); - break; - - case 'channel': - $this->processChannel($value, $channelFields, $result); - break; - - // Find the number of fields for the channels - case 'channelfields': - $channelFields = count(explode(',', $value)); - break; - - // Find the number of fields for the players - case 'clientfields': - $playerFields = count(explode(',', $value)); - break; - - // By default we just add they key as an item - default: - $result->add($key, utf8_encode($value)); - break; - } - } - } - - unset($decrypted, $line, $lines, $colon_pos, $key, $value); - - return $result->fetch(); - } - - /* - * Internal methods - */ - - /** - * Decrypt the incoming packets - * - * @codeCoverageIgnore - * - * @param array $packets - * - * @return string - * @throws \GameQ\Exception\Protocol - */ - protected function decryptPackets(array $packets = []) - { - - // This will be returned - $decrypted = []; - - foreach ($packets as $packet) { - # Header : - $header = substr($packet, 0, 20); - - $header_items = []; - - $header_key = unpack("n1", $header); - - $key = array_shift($header_key); - - $chars = unpack("C*", substr($header, 2)); - - $a1 = $key & 0xFF; - $a2 = $key >> 8; - - if ($a1 == 0) { - throw new Exception(__METHOD__ . ": Header key is invalid"); - } - - $table = $this->head_encrypt_table; - - $characterCount = count($chars); - - $key = 0; - for ($index = 1; $index <= $characterCount; $index++) { - $chars[$index] -= ($table[$a2] + (($index - 1) % 5)) & 0xFF; - $a2 = ($a2 + $a1) & 0xFF; - if (($index % 2) == 0) { - $short_array = unpack("n1", pack("C2", $chars[$index - 1], $chars[$index])); - $header_items[$key] = $short_array[1]; - ++$key; - } - } - - $header_items = array_combine([ - 'zero', - 'cmd', - 'id', - 'totlen', - 'len', - 'totpck', - 'pck', - 'datakey', - 'crc', - ], $header_items); - - // Check to make sure the number of packets match - if ($header_items['totpck'] != count($packets)) { - throw new Exception(__METHOD__ . ": Too few packets received"); - } - - # Data : - $table = $this->data_encrypt_table; - $a1 = $header_items['datakey'] & 0xFF; - $a2 = $header_items['datakey'] >> 8; - - if ($a1 == 0) { - throw new Exception(__METHOD__ . ": Data key is invalid"); - } - - $chars = unpack("C*", substr($packet, 20)); - $data = ""; - $characterCount = count($chars); - - for ($index = 1; $index <= $characterCount; $index++) { - $chars[$index] -= ($table[$a2] + (($index - 1) % 72)) & 0xFF; - $a2 = ($a2 + $a1) & 0xFF; - $data .= chr($chars[$index]); - } - //@todo: Check CRC ??? - $decrypted[$header_items['pck']] = $data; - } - - // Return the decrypted packets as one string - return implode('', $decrypted); - } - - /** - * Process the channel listing - * - * @param string $data - * @param int $fieldCount - * @param \GameQ\Result $result - */ - protected function processChannel($data, $fieldCount, Result &$result) - { - - // Split the items on the comma - $items = explode(",", $data, $fieldCount); - - // Iterate over the items for this channel - foreach ($items as $item) { - // Split the key=value pair - list($key, $value) = explode("=", $item, 2); - - $result->addTeam(strtolower($key), utf8_encode($value)); - } - } - - /** - * Process the user listing - * - * @param string $data - * @param int $fieldCount - * @param \GameQ\Result $result - */ - protected function processPlayer($data, $fieldCount, Result &$result) - { - - // Split the items on the comma - $items = explode(",", $data, $fieldCount); - - // Iterate over the items for this player - foreach ($items as $item) { - // Split the key=value pair - list($key, $value) = explode("=", $item, 2); - - $result->addPlayer(strtolower($key), utf8_encode($value)); - } - } -} diff --git a/third_party/gameq_v3.1/GameQ/Result.php b/third_party/gameq_v3.1/GameQ/Result.php deleted file mode 100644 index 7023f17a..00000000 --- a/third_party/gameq_v3.1/GameQ/Result.php +++ /dev/null @@ -1,130 +0,0 @@ -. - */ - -namespace GameQ; - -/** - * Provide an interface for easy storage of a parsed server response - * - * @author Aidan Lister - * @author Tom Buskens - */ -class Result -{ - - /** - * Formatted server response - * - * @var array - */ - protected $result = []; - - /** - * Adds variable to results - * - * @param string $name Variable name - * @param string|array $value Variable value - */ - public function add($name, $value) - { - - $this->result[$name] = $value; - } - - /** - * Adds player variable to output - * - * @param string $name Variable name - * @param string $value Variable value - */ - public function addPlayer($name, $value) - { - - $this->addSub('players', $name, $value); - } - - /** - * Adds player variable to output - * - * @param string $name Variable name - * @param string $value Variable value - */ - public function addTeam($name, $value) - { - - $this->addSub('teams', $name, $value); - } - - /** - * Add a variable to a category - * - * @param $sub string The category - * @param $key string The variable name - * @param $value string The variable value - */ - public function addSub($sub, $key, $value) - { - - // Nothing of this type yet, set an empty array - if (!isset($this->result[$sub]) or !is_array($this->result[$sub])) { - $this->result[$sub] = []; - } - - // Find the first entry that doesn't have this variable - $found = false; - $count = count($this->result[$sub]); - for ($i = 0; $i != $count; $i++) { - if (!isset($this->result[$sub][$i][$key])) { - $this->result[$sub][$i][$key] = $value; - $found = true; - break; - } - } - - // Not found, create a new entry - if (!$found) { - $this->result[$sub][][$key] = $value; - } - - unset($count); - } - - /** - * Return all stored results - * - * @return array All results - */ - public function fetch() - { - - return $this->result; - } - - /** - * Return a single variable - * - * @param string $var The variable name - * - * @return mixed The variable value - */ - public function get($var) - { - - return isset($this->result[$var]) ? $this->result[$var] : null; - } -}