From 53bcb915a64d00a8cee48be0b0242070f80b57e8 Mon Sep 17 00:00:00 2001 From: Erreur32 Date: Thu, 4 Feb 2021 22:14:31 +0100 Subject: [PATCH] first commit --- GameQ/.github/FUNDING.yml | 12 - GameQ/.github/issue_label_bot.yaml | 4 - GameQ/.github/stale.yml | 19 - GameQ/Autoloader.php | 60 -- GameQ/Buffer.php | 501 ---------- GameQ/CONTRIBUTING.md | 39 - GameQ/Exception/Protocol.php | 30 - GameQ/Exception/Query.php | 30 - GameQ/Exception/Server.php | 30 - GameQ/Filters/Base.php | 58 -- GameQ/Filters/Normalize.php | 133 --- GameQ/Filters/Secondstohuman.php | 121 --- GameQ/Filters/Stripcolors.php | 115 --- GameQ/Filters/Test.php | 47 - GameQ/GameQ.php | 649 ------------- GameQ/LICENSE.lgpl | 165 ---- GameQ/Protocol.php | 500 ---------- GameQ/Protocols/Aa3.php | 53 -- GameQ/Protocols/Aapg.php | 42 - GameQ/Protocols/Arkse.php | 51 - GameQ/Protocols/Arma.php | 43 - GameQ/Protocols/Arma3.php | 181 ---- GameQ/Protocols/Armedassault2oa.php | 50 - GameQ/Protocols/Armedassault3.php | 32 - GameQ/Protocols/Ase.php | 208 ----- GameQ/Protocols/Atlas.php | 55 -- GameQ/Protocols/Batt1944.php | 68 -- GameQ/Protocols/Bf1942.php | 88 -- GameQ/Protocols/Bf2.php | 98 -- GameQ/Protocols/Bf3.php | 348 ------- GameQ/Protocols/Bf4.php | 114 --- GameQ/Protocols/Bfbc2.php | 326 ------- GameQ/Protocols/Bfh.php | 43 - GameQ/Protocols/Brink.php | 50 - GameQ/Protocols/Cod.php | 43 - GameQ/Protocols/Cod2.php | 42 - GameQ/Protocols/Cod4.php | 42 - GameQ/Protocols/Codmw3.php | 50 - GameQ/Protocols/Coduo.php | 43 - GameQ/Protocols/Codwaw.php | 43 - GameQ/Protocols/Conanexiles.php | 42 - GameQ/Protocols/Contagion.php | 42 - GameQ/Protocols/Crysis.php | 43 - GameQ/Protocols/Crysis2.php | 43 - GameQ/Protocols/Crysiswars.php | 43 - GameQ/Protocols/Cs15.php | 45 - GameQ/Protocols/Cs16.php | 69 -- GameQ/Protocols/Cs2d.php | 263 ------ GameQ/Protocols/Cscz.php | 45 - GameQ/Protocols/Csgo.php | 43 - GameQ/Protocols/Css.php | 42 - GameQ/Protocols/Dal.php | 43 - GameQ/Protocols/Dayz.php | 66 -- GameQ/Protocols/Dayzmod.php | 44 - GameQ/Protocols/Dod.php | 45 - GameQ/Protocols/Dods.php | 42 - GameQ/Protocols/Dow.php | 69 -- GameQ/Protocols/Eco.php | 123 --- GameQ/Protocols/Egs.php | 51 - GameQ/Protocols/Et.php | 43 - GameQ/Protocols/Etqw.php | 234 ----- GameQ/Protocols/Ffe.php | 43 - GameQ/Protocols/Ffow.php | 243 ----- GameQ/Protocols/Gamespy.php | 181 ---- GameQ/Protocols/Gamespy2.php | 269 ------ GameQ/Protocols/Gamespy3.php | 340 ------- GameQ/Protocols/Gamespy4.php | 34 - GameQ/Protocols/Gmod.php | 42 - GameQ/Protocols/Grav.php | 42 - GameQ/Protocols/Gta5m.php | 173 ---- GameQ/Protocols/Gtan.php | 163 ---- GameQ/Protocols/Gtar.php | 164 ---- GameQ/Protocols/Hl2dm.php | 42 - GameQ/Protocols/Http.php | 67 -- GameQ/Protocols/Hurtworld.php | 42 - GameQ/Protocols/Insurgency.php | 42 - GameQ/Protocols/Insurgencysand.php | 49 - GameQ/Protocols/Jediacademy.php | 42 - GameQ/Protocols/Jedioutcast.php | 42 - GameQ/Protocols/Justcause2.php | 127 --- GameQ/Protocols/Justcause3.php | 50 - GameQ/Protocols/Killingfloor.php | 96 -- GameQ/Protocols/Killingfloor2.php | 51 - GameQ/Protocols/L4d.php | 42 - GameQ/Protocols/L4d2.php | 42 - GameQ/Protocols/Lhmp.php | 214 ----- GameQ/Protocols/Minecraft.php | 87 -- GameQ/Protocols/Minecraftpe.php | 44 - GameQ/Protocols/Mohaa.php | 79 -- GameQ/Protocols/Mordhau.php | 53 -- GameQ/Protocols/Mta.php | 59 -- GameQ/Protocols/Mumble.php | 194 ---- GameQ/Protocols/Ns2.php | 49 - GameQ/Protocols/Pixark.php | 43 - GameQ/Protocols/Projectrealitybf2.php | 45 - GameQ/Protocols/Quake2.php | 219 ----- GameQ/Protocols/Quake3.php | 214 ----- GameQ/Protocols/Quakelive.php | 42 - GameQ/Protocols/Redorchestra2.php | 50 - GameQ/Protocols/Redorchestraostfront.php | 43 - GameQ/Protocols/Risingstorm2.php | 55 -- GameQ/Protocols/Rust.php | 43 - GameQ/Protocols/Samp.php | 279 ------ GameQ/Protocols/Serioussam.php | 75 -- GameQ/Protocols/Sevendaystodie.php | 49 - GameQ/Protocols/Ship.php | 95 -- GameQ/Protocols/Sof2.php | 49 - GameQ/Protocols/Soldat.php | 59 -- GameQ/Protocols/Source.php | 522 ----------- GameQ/Protocols/Spaceengineers.php | 42 - GameQ/Protocols/Squad.php | 53 -- GameQ/Protocols/Starmade.php | 226 ----- GameQ/Protocols/Swat4.php | 50 - GameQ/Protocols/Teamspeak2.php | 290 ------ GameQ/Protocols/Teamspeak3.php | 328 ------- GameQ/Protocols/Teeworlds.php | 181 ---- GameQ/Protocols/Terraria.php | 59 -- GameQ/Protocols/Tf2.php | 42 - GameQ/Protocols/Theforrest.php | 50 - GameQ/Protocols/Tibia.php | 142 --- GameQ/Protocols/Tshock.php | 157 ---- GameQ/Protocols/Unreal2.php | 246 ----- GameQ/Protocols/Unturned.php | 49 - GameQ/Protocols/Urbanterror.php | 49 - GameQ/Protocols/Ut.php | 73 -- GameQ/Protocols/Ut2004.php | 42 - GameQ/Protocols/Ut3.php | 133 --- GameQ/Protocols/Ventrilo.php | 877 ------------------ GameQ/Protocols/Warsow.php | 96 -- GameQ/Protocols/Won.php | 66 -- GameQ/Protocols/Wurm.php | 42 - GameQ/Query/Core.php | 164 ---- GameQ/Query/Native.php | 221 ----- GameQ/Result.php | 130 --- GameQ/Server.php | 380 -------- GameQ/composer.json | 90 -- GameQ/examples/list.php | 131 --- GameQ/expansion.php | 171 ---- GameQ/expansion_.php | 170 ---- GameQ/index.php | 152 --- GameQ/src/GameQ/Autoloader.php | 60 -- GameQ/src/GameQ/Buffer.php | 501 ---------- GameQ/src/GameQ/Exception/Protocol.php | 30 - GameQ/src/GameQ/Exception/Query.php | 30 - GameQ/src/GameQ/Exception/Server.php | 30 - GameQ/src/GameQ/Filters/Base.php | 58 -- GameQ/src/GameQ/Filters/Normalize.php | 133 --- GameQ/src/GameQ/Filters/Secondstohuman.php | 121 --- GameQ/src/GameQ/Filters/Stripcolors.php | 115 --- GameQ/src/GameQ/Filters/Test.php | 47 - GameQ/src/GameQ/GameQ.php | 649 ------------- GameQ/src/GameQ/Protocol.php | 500 ---------- GameQ/src/GameQ/Protocols/Aa3.php | 53 -- GameQ/src/GameQ/Protocols/Aapg.php | 42 - GameQ/src/GameQ/Protocols/Arkse.php | 51 - GameQ/src/GameQ/Protocols/Arma.php | 43 - GameQ/src/GameQ/Protocols/Arma3.php | 181 ---- GameQ/src/GameQ/Protocols/Armedassault2oa.php | 50 - GameQ/src/GameQ/Protocols/Armedassault3.php | 32 - GameQ/src/GameQ/Protocols/Ase.php | 208 ----- GameQ/src/GameQ/Protocols/Atlas.php | 55 -- GameQ/src/GameQ/Protocols/Batt1944.php | 68 -- GameQ/src/GameQ/Protocols/Bf1942.php | 88 -- GameQ/src/GameQ/Protocols/Bf2.php | 98 -- GameQ/src/GameQ/Protocols/Bf3.php | 348 ------- GameQ/src/GameQ/Protocols/Bf4.php | 114 --- GameQ/src/GameQ/Protocols/Bfbc2.php | 326 ------- GameQ/src/GameQ/Protocols/Bfh.php | 43 - GameQ/src/GameQ/Protocols/Brink.php | 50 - GameQ/src/GameQ/Protocols/Cod.php | 43 - GameQ/src/GameQ/Protocols/Cod2.php | 42 - GameQ/src/GameQ/Protocols/Cod4.php | 42 - GameQ/src/GameQ/Protocols/Codmw3.php | 50 - GameQ/src/GameQ/Protocols/Coduo.php | 43 - GameQ/src/GameQ/Protocols/Codwaw.php | 43 - GameQ/src/GameQ/Protocols/Conanexiles.php | 42 - GameQ/src/GameQ/Protocols/Contagion.php | 42 - GameQ/src/GameQ/Protocols/Crysis.php | 43 - GameQ/src/GameQ/Protocols/Crysis2.php | 43 - GameQ/src/GameQ/Protocols/Crysiswars.php | 43 - GameQ/src/GameQ/Protocols/Cs15.php | 45 - GameQ/src/GameQ/Protocols/Cs16.php | 69 -- GameQ/src/GameQ/Protocols/Cs2d.php | 263 ------ GameQ/src/GameQ/Protocols/Cscz.php | 45 - GameQ/src/GameQ/Protocols/Csgo.php | 43 - GameQ/src/GameQ/Protocols/Css.php | 42 - GameQ/src/GameQ/Protocols/Dal.php | 43 - GameQ/src/GameQ/Protocols/Dayz.php | 66 -- GameQ/src/GameQ/Protocols/Dayzmod.php | 44 - GameQ/src/GameQ/Protocols/Dod.php | 45 - GameQ/src/GameQ/Protocols/Dods.php | 42 - GameQ/src/GameQ/Protocols/Dow.php | 69 -- GameQ/src/GameQ/Protocols/Eco.php | 123 --- GameQ/src/GameQ/Protocols/Egs.php | 51 - GameQ/src/GameQ/Protocols/Et.php | 43 - GameQ/src/GameQ/Protocols/Etqw.php | 234 ----- GameQ/src/GameQ/Protocols/Ffe.php | 43 - GameQ/src/GameQ/Protocols/Ffow.php | 243 ----- GameQ/src/GameQ/Protocols/Gamespy.php | 181 ---- GameQ/src/GameQ/Protocols/Gamespy2.php | 269 ------ GameQ/src/GameQ/Protocols/Gamespy3.php | 340 ------- GameQ/src/GameQ/Protocols/Gamespy4.php | 34 - GameQ/src/GameQ/Protocols/Gmod.php | 42 - GameQ/src/GameQ/Protocols/Grav.php | 42 - GameQ/src/GameQ/Protocols/Gta5m.php | 173 ---- GameQ/src/GameQ/Protocols/Gtan.php | 163 ---- GameQ/src/GameQ/Protocols/Hl2dm.php | 42 - GameQ/src/GameQ/Protocols/Http.php | 67 -- GameQ/src/GameQ/Protocols/Hurtworld.php | 42 - GameQ/src/GameQ/Protocols/Insurgency.php | 42 - GameQ/src/GameQ/Protocols/Insurgencysand.php | 49 - GameQ/src/GameQ/Protocols/Jediacademy.php | 42 - GameQ/src/GameQ/Protocols/Jedioutcast.php | 42 - GameQ/src/GameQ/Protocols/Justcause2.php | 127 --- GameQ/src/GameQ/Protocols/Justcause3.php | 50 - GameQ/src/GameQ/Protocols/Killingfloor.php | 96 -- GameQ/src/GameQ/Protocols/Killingfloor2.php | 51 - GameQ/src/GameQ/Protocols/L4d.php | 42 - GameQ/src/GameQ/Protocols/L4d2.php | 42 - GameQ/src/GameQ/Protocols/Lhmp.php | 214 ----- GameQ/src/GameQ/Protocols/Minecraft.php | 87 -- GameQ/src/GameQ/Protocols/Minecraftpe.php | 44 - GameQ/src/GameQ/Protocols/Mohaa.php | 79 -- GameQ/src/GameQ/Protocols/Mordhau.php | 53 -- GameQ/src/GameQ/Protocols/Mta.php | 59 -- GameQ/src/GameQ/Protocols/Mumble.php | 194 ---- GameQ/src/GameQ/Protocols/Ns2.php | 49 - GameQ/src/GameQ/Protocols/Pixark.php | 43 - .../src/GameQ/Protocols/Projectrealitybf2.php | 45 - GameQ/src/GameQ/Protocols/Quake2.php | 219 ----- GameQ/src/GameQ/Protocols/Quake3.php | 214 ----- GameQ/src/GameQ/Protocols/Quakelive.php | 42 - GameQ/src/GameQ/Protocols/Redorchestra2.php | 50 - .../GameQ/Protocols/Redorchestraostfront.php | 43 - GameQ/src/GameQ/Protocols/Risingstorm2.php | 55 -- GameQ/src/GameQ/Protocols/Rust.php | 43 - GameQ/src/GameQ/Protocols/Samp.php | 279 ------ GameQ/src/GameQ/Protocols/Serioussam.php | 75 -- GameQ/src/GameQ/Protocols/Sevendaystodie.php | 49 - GameQ/src/GameQ/Protocols/Ship.php | 95 -- GameQ/src/GameQ/Protocols/Sof2.php | 49 - GameQ/src/GameQ/Protocols/Soldat.php | 59 -- GameQ/src/GameQ/Protocols/Source.php | 522 ----------- GameQ/src/GameQ/Protocols/Spaceengineers.php | 42 - GameQ/src/GameQ/Protocols/Squad.php | 53 -- GameQ/src/GameQ/Protocols/Starmade.php | 226 ----- GameQ/src/GameQ/Protocols/Swat4.php | 50 - GameQ/src/GameQ/Protocols/Teamspeak2.php | 290 ------ GameQ/src/GameQ/Protocols/Teamspeak3.php | 328 ------- GameQ/src/GameQ/Protocols/Teeworlds.php | 181 ---- GameQ/src/GameQ/Protocols/Terraria.php | 59 -- GameQ/src/GameQ/Protocols/Tf2.php | 42 - GameQ/src/GameQ/Protocols/Theforrest.php | 50 - GameQ/src/GameQ/Protocols/Tibia.php | 142 --- GameQ/src/GameQ/Protocols/Tshock.php | 157 ---- GameQ/src/GameQ/Protocols/Unreal2.php | 246 ----- GameQ/src/GameQ/Protocols/Unturned.php | 49 - GameQ/src/GameQ/Protocols/Urbanterror.php | 49 - GameQ/src/GameQ/Protocols/Ut.php | 73 -- GameQ/src/GameQ/Protocols/Ut2004.php | 42 - GameQ/src/GameQ/Protocols/Ut3.php | 133 --- GameQ/src/GameQ/Protocols/Ventrilo.php | 877 ------------------ GameQ/src/GameQ/Protocols/Warsow.php | 96 -- GameQ/src/GameQ/Protocols/Won.php | 66 -- GameQ/src/GameQ/Protocols/Wurm.php | 42 - GameQ/src/GameQ/Query/Core.php | 164 ---- GameQ/src/GameQ/Query/Native.php | 221 ----- GameQ/src/GameQ/Result.php | 130 --- GameQ/src/GameQ/Server.php | 380 -------- GameQ/status_expansion.php | 206 ---- GameQ/status_livonia.php | 200 ---- README.md | 3 + .../dayz2json_parser_sql.php | 21 +- .../regex_statserver_json.php | 2 +- table.sql => SQL/table.sql | 0 config.php | 6 +- consql.php | 1 + index.php | 40 +- 278 files changed, 42 insertions(+), 31514 deletions(-) delete mode 100644 GameQ/.github/FUNDING.yml delete mode 100644 GameQ/.github/issue_label_bot.yaml delete mode 100644 GameQ/.github/stale.yml delete mode 100644 GameQ/Autoloader.php delete mode 100644 GameQ/Buffer.php delete mode 100644 GameQ/CONTRIBUTING.md delete mode 100644 GameQ/Exception/Protocol.php delete mode 100644 GameQ/Exception/Query.php delete mode 100644 GameQ/Exception/Server.php delete mode 100644 GameQ/Filters/Base.php delete mode 100644 GameQ/Filters/Normalize.php delete mode 100644 GameQ/Filters/Secondstohuman.php delete mode 100644 GameQ/Filters/Stripcolors.php delete mode 100644 GameQ/Filters/Test.php delete mode 100644 GameQ/GameQ.php delete mode 100644 GameQ/LICENSE.lgpl delete mode 100644 GameQ/Protocol.php delete mode 100644 GameQ/Protocols/Aa3.php delete mode 100644 GameQ/Protocols/Aapg.php delete mode 100644 GameQ/Protocols/Arkse.php delete mode 100644 GameQ/Protocols/Arma.php delete mode 100644 GameQ/Protocols/Arma3.php delete mode 100644 GameQ/Protocols/Armedassault2oa.php delete mode 100644 GameQ/Protocols/Armedassault3.php delete mode 100644 GameQ/Protocols/Ase.php delete mode 100644 GameQ/Protocols/Atlas.php delete mode 100644 GameQ/Protocols/Batt1944.php delete mode 100644 GameQ/Protocols/Bf1942.php delete mode 100644 GameQ/Protocols/Bf2.php delete mode 100644 GameQ/Protocols/Bf3.php delete mode 100644 GameQ/Protocols/Bf4.php delete mode 100644 GameQ/Protocols/Bfbc2.php delete mode 100644 GameQ/Protocols/Bfh.php delete mode 100644 GameQ/Protocols/Brink.php delete mode 100644 GameQ/Protocols/Cod.php delete mode 100644 GameQ/Protocols/Cod2.php delete mode 100644 GameQ/Protocols/Cod4.php delete mode 100644 GameQ/Protocols/Codmw3.php delete mode 100644 GameQ/Protocols/Coduo.php delete mode 100644 GameQ/Protocols/Codwaw.php delete mode 100644 GameQ/Protocols/Conanexiles.php delete mode 100644 GameQ/Protocols/Contagion.php delete mode 100644 GameQ/Protocols/Crysis.php delete mode 100644 GameQ/Protocols/Crysis2.php delete mode 100644 GameQ/Protocols/Crysiswars.php delete mode 100644 GameQ/Protocols/Cs15.php delete mode 100644 GameQ/Protocols/Cs16.php delete mode 100644 GameQ/Protocols/Cs2d.php delete mode 100644 GameQ/Protocols/Cscz.php delete mode 100644 GameQ/Protocols/Csgo.php delete mode 100644 GameQ/Protocols/Css.php delete mode 100644 GameQ/Protocols/Dal.php delete mode 100644 GameQ/Protocols/Dayz.php delete mode 100644 GameQ/Protocols/Dayzmod.php delete mode 100644 GameQ/Protocols/Dod.php delete mode 100644 GameQ/Protocols/Dods.php delete mode 100644 GameQ/Protocols/Dow.php delete mode 100644 GameQ/Protocols/Eco.php delete mode 100644 GameQ/Protocols/Egs.php delete mode 100644 GameQ/Protocols/Et.php delete mode 100644 GameQ/Protocols/Etqw.php delete mode 100644 GameQ/Protocols/Ffe.php delete mode 100644 GameQ/Protocols/Ffow.php delete mode 100644 GameQ/Protocols/Gamespy.php delete mode 100644 GameQ/Protocols/Gamespy2.php delete mode 100644 GameQ/Protocols/Gamespy3.php delete mode 100644 GameQ/Protocols/Gamespy4.php delete mode 100644 GameQ/Protocols/Gmod.php delete mode 100644 GameQ/Protocols/Grav.php delete mode 100644 GameQ/Protocols/Gta5m.php delete mode 100644 GameQ/Protocols/Gtan.php delete mode 100644 GameQ/Protocols/Gtar.php delete mode 100644 GameQ/Protocols/Hl2dm.php delete mode 100644 GameQ/Protocols/Http.php delete mode 100644 GameQ/Protocols/Hurtworld.php delete mode 100644 GameQ/Protocols/Insurgency.php delete mode 100644 GameQ/Protocols/Insurgencysand.php delete mode 100644 GameQ/Protocols/Jediacademy.php delete mode 100644 GameQ/Protocols/Jedioutcast.php delete mode 100644 GameQ/Protocols/Justcause2.php delete mode 100644 GameQ/Protocols/Justcause3.php delete mode 100644 GameQ/Protocols/Killingfloor.php delete mode 100644 GameQ/Protocols/Killingfloor2.php delete mode 100644 GameQ/Protocols/L4d.php delete mode 100644 GameQ/Protocols/L4d2.php delete mode 100644 GameQ/Protocols/Lhmp.php delete mode 100644 GameQ/Protocols/Minecraft.php delete mode 100644 GameQ/Protocols/Minecraftpe.php delete mode 100644 GameQ/Protocols/Mohaa.php delete mode 100644 GameQ/Protocols/Mordhau.php delete mode 100644 GameQ/Protocols/Mta.php delete mode 100644 GameQ/Protocols/Mumble.php delete mode 100644 GameQ/Protocols/Ns2.php delete mode 100644 GameQ/Protocols/Pixark.php delete mode 100644 GameQ/Protocols/Projectrealitybf2.php delete mode 100644 GameQ/Protocols/Quake2.php delete mode 100644 GameQ/Protocols/Quake3.php delete mode 100644 GameQ/Protocols/Quakelive.php delete mode 100644 GameQ/Protocols/Redorchestra2.php delete mode 100644 GameQ/Protocols/Redorchestraostfront.php delete mode 100644 GameQ/Protocols/Risingstorm2.php delete mode 100644 GameQ/Protocols/Rust.php delete mode 100644 GameQ/Protocols/Samp.php delete mode 100644 GameQ/Protocols/Serioussam.php delete mode 100644 GameQ/Protocols/Sevendaystodie.php delete mode 100644 GameQ/Protocols/Ship.php delete mode 100644 GameQ/Protocols/Sof2.php delete mode 100644 GameQ/Protocols/Soldat.php delete mode 100644 GameQ/Protocols/Source.php delete mode 100644 GameQ/Protocols/Spaceengineers.php delete mode 100644 GameQ/Protocols/Squad.php delete mode 100644 GameQ/Protocols/Starmade.php delete mode 100644 GameQ/Protocols/Swat4.php delete mode 100644 GameQ/Protocols/Teamspeak2.php delete mode 100644 GameQ/Protocols/Teamspeak3.php delete mode 100644 GameQ/Protocols/Teeworlds.php delete mode 100644 GameQ/Protocols/Terraria.php delete mode 100644 GameQ/Protocols/Tf2.php delete mode 100644 GameQ/Protocols/Theforrest.php delete mode 100644 GameQ/Protocols/Tibia.php delete mode 100644 GameQ/Protocols/Tshock.php delete mode 100644 GameQ/Protocols/Unreal2.php delete mode 100644 GameQ/Protocols/Unturned.php delete mode 100644 GameQ/Protocols/Urbanterror.php delete mode 100644 GameQ/Protocols/Ut.php delete mode 100644 GameQ/Protocols/Ut2004.php delete mode 100644 GameQ/Protocols/Ut3.php delete mode 100644 GameQ/Protocols/Ventrilo.php delete mode 100644 GameQ/Protocols/Warsow.php delete mode 100644 GameQ/Protocols/Won.php delete mode 100644 GameQ/Protocols/Wurm.php delete mode 100644 GameQ/Query/Core.php delete mode 100644 GameQ/Query/Native.php delete mode 100644 GameQ/Result.php delete mode 100644 GameQ/Server.php delete mode 100644 GameQ/composer.json delete mode 100644 GameQ/examples/list.php delete mode 100644 GameQ/expansion.php delete mode 100644 GameQ/expansion_.php delete mode 100644 GameQ/index.php delete mode 100644 GameQ/src/GameQ/Autoloader.php delete mode 100644 GameQ/src/GameQ/Buffer.php delete mode 100644 GameQ/src/GameQ/Exception/Protocol.php delete mode 100644 GameQ/src/GameQ/Exception/Query.php delete mode 100644 GameQ/src/GameQ/Exception/Server.php delete mode 100644 GameQ/src/GameQ/Filters/Base.php delete mode 100644 GameQ/src/GameQ/Filters/Normalize.php delete mode 100644 GameQ/src/GameQ/Filters/Secondstohuman.php delete mode 100644 GameQ/src/GameQ/Filters/Stripcolors.php delete mode 100644 GameQ/src/GameQ/Filters/Test.php delete mode 100644 GameQ/src/GameQ/GameQ.php delete mode 100644 GameQ/src/GameQ/Protocol.php delete mode 100644 GameQ/src/GameQ/Protocols/Aa3.php delete mode 100644 GameQ/src/GameQ/Protocols/Aapg.php delete mode 100644 GameQ/src/GameQ/Protocols/Arkse.php delete mode 100644 GameQ/src/GameQ/Protocols/Arma.php delete mode 100644 GameQ/src/GameQ/Protocols/Arma3.php delete mode 100644 GameQ/src/GameQ/Protocols/Armedassault2oa.php delete mode 100644 GameQ/src/GameQ/Protocols/Armedassault3.php delete mode 100644 GameQ/src/GameQ/Protocols/Ase.php delete mode 100644 GameQ/src/GameQ/Protocols/Atlas.php delete mode 100644 GameQ/src/GameQ/Protocols/Batt1944.php delete mode 100644 GameQ/src/GameQ/Protocols/Bf1942.php delete mode 100644 GameQ/src/GameQ/Protocols/Bf2.php delete mode 100644 GameQ/src/GameQ/Protocols/Bf3.php delete mode 100644 GameQ/src/GameQ/Protocols/Bf4.php delete mode 100644 GameQ/src/GameQ/Protocols/Bfbc2.php delete mode 100644 GameQ/src/GameQ/Protocols/Bfh.php delete mode 100644 GameQ/src/GameQ/Protocols/Brink.php delete mode 100644 GameQ/src/GameQ/Protocols/Cod.php delete mode 100644 GameQ/src/GameQ/Protocols/Cod2.php delete mode 100644 GameQ/src/GameQ/Protocols/Cod4.php delete mode 100644 GameQ/src/GameQ/Protocols/Codmw3.php delete mode 100644 GameQ/src/GameQ/Protocols/Coduo.php delete mode 100644 GameQ/src/GameQ/Protocols/Codwaw.php delete mode 100644 GameQ/src/GameQ/Protocols/Conanexiles.php delete mode 100644 GameQ/src/GameQ/Protocols/Contagion.php delete mode 100644 GameQ/src/GameQ/Protocols/Crysis.php delete mode 100644 GameQ/src/GameQ/Protocols/Crysis2.php delete mode 100644 GameQ/src/GameQ/Protocols/Crysiswars.php delete mode 100644 GameQ/src/GameQ/Protocols/Cs15.php delete mode 100644 GameQ/src/GameQ/Protocols/Cs16.php delete mode 100644 GameQ/src/GameQ/Protocols/Cs2d.php delete mode 100644 GameQ/src/GameQ/Protocols/Cscz.php delete mode 100644 GameQ/src/GameQ/Protocols/Csgo.php delete mode 100644 GameQ/src/GameQ/Protocols/Css.php delete mode 100644 GameQ/src/GameQ/Protocols/Dal.php delete mode 100644 GameQ/src/GameQ/Protocols/Dayz.php delete mode 100644 GameQ/src/GameQ/Protocols/Dayzmod.php delete mode 100644 GameQ/src/GameQ/Protocols/Dod.php delete mode 100644 GameQ/src/GameQ/Protocols/Dods.php delete mode 100644 GameQ/src/GameQ/Protocols/Dow.php delete mode 100644 GameQ/src/GameQ/Protocols/Eco.php delete mode 100644 GameQ/src/GameQ/Protocols/Egs.php delete mode 100644 GameQ/src/GameQ/Protocols/Et.php delete mode 100644 GameQ/src/GameQ/Protocols/Etqw.php delete mode 100644 GameQ/src/GameQ/Protocols/Ffe.php delete mode 100644 GameQ/src/GameQ/Protocols/Ffow.php delete mode 100644 GameQ/src/GameQ/Protocols/Gamespy.php delete mode 100644 GameQ/src/GameQ/Protocols/Gamespy2.php delete mode 100644 GameQ/src/GameQ/Protocols/Gamespy3.php delete mode 100644 GameQ/src/GameQ/Protocols/Gamespy4.php delete mode 100644 GameQ/src/GameQ/Protocols/Gmod.php delete mode 100644 GameQ/src/GameQ/Protocols/Grav.php delete mode 100644 GameQ/src/GameQ/Protocols/Gta5m.php delete mode 100644 GameQ/src/GameQ/Protocols/Gtan.php delete mode 100644 GameQ/src/GameQ/Protocols/Hl2dm.php delete mode 100644 GameQ/src/GameQ/Protocols/Http.php delete mode 100644 GameQ/src/GameQ/Protocols/Hurtworld.php delete mode 100644 GameQ/src/GameQ/Protocols/Insurgency.php delete mode 100644 GameQ/src/GameQ/Protocols/Insurgencysand.php delete mode 100644 GameQ/src/GameQ/Protocols/Jediacademy.php delete mode 100644 GameQ/src/GameQ/Protocols/Jedioutcast.php delete mode 100644 GameQ/src/GameQ/Protocols/Justcause2.php delete mode 100644 GameQ/src/GameQ/Protocols/Justcause3.php delete mode 100644 GameQ/src/GameQ/Protocols/Killingfloor.php delete mode 100644 GameQ/src/GameQ/Protocols/Killingfloor2.php delete mode 100644 GameQ/src/GameQ/Protocols/L4d.php delete mode 100644 GameQ/src/GameQ/Protocols/L4d2.php delete mode 100644 GameQ/src/GameQ/Protocols/Lhmp.php delete mode 100644 GameQ/src/GameQ/Protocols/Minecraft.php delete mode 100644 GameQ/src/GameQ/Protocols/Minecraftpe.php delete mode 100644 GameQ/src/GameQ/Protocols/Mohaa.php delete mode 100644 GameQ/src/GameQ/Protocols/Mordhau.php delete mode 100644 GameQ/src/GameQ/Protocols/Mta.php delete mode 100644 GameQ/src/GameQ/Protocols/Mumble.php delete mode 100644 GameQ/src/GameQ/Protocols/Ns2.php delete mode 100644 GameQ/src/GameQ/Protocols/Pixark.php delete mode 100644 GameQ/src/GameQ/Protocols/Projectrealitybf2.php delete mode 100644 GameQ/src/GameQ/Protocols/Quake2.php delete mode 100644 GameQ/src/GameQ/Protocols/Quake3.php delete mode 100644 GameQ/src/GameQ/Protocols/Quakelive.php delete mode 100644 GameQ/src/GameQ/Protocols/Redorchestra2.php delete mode 100644 GameQ/src/GameQ/Protocols/Redorchestraostfront.php delete mode 100644 GameQ/src/GameQ/Protocols/Risingstorm2.php delete mode 100644 GameQ/src/GameQ/Protocols/Rust.php delete mode 100644 GameQ/src/GameQ/Protocols/Samp.php delete mode 100644 GameQ/src/GameQ/Protocols/Serioussam.php delete mode 100644 GameQ/src/GameQ/Protocols/Sevendaystodie.php delete mode 100644 GameQ/src/GameQ/Protocols/Ship.php delete mode 100644 GameQ/src/GameQ/Protocols/Sof2.php delete mode 100644 GameQ/src/GameQ/Protocols/Soldat.php delete mode 100644 GameQ/src/GameQ/Protocols/Source.php delete mode 100644 GameQ/src/GameQ/Protocols/Spaceengineers.php delete mode 100644 GameQ/src/GameQ/Protocols/Squad.php delete mode 100644 GameQ/src/GameQ/Protocols/Starmade.php delete mode 100644 GameQ/src/GameQ/Protocols/Swat4.php delete mode 100644 GameQ/src/GameQ/Protocols/Teamspeak2.php delete mode 100644 GameQ/src/GameQ/Protocols/Teamspeak3.php delete mode 100644 GameQ/src/GameQ/Protocols/Teeworlds.php delete mode 100644 GameQ/src/GameQ/Protocols/Terraria.php delete mode 100644 GameQ/src/GameQ/Protocols/Tf2.php delete mode 100644 GameQ/src/GameQ/Protocols/Theforrest.php delete mode 100644 GameQ/src/GameQ/Protocols/Tibia.php delete mode 100644 GameQ/src/GameQ/Protocols/Tshock.php delete mode 100644 GameQ/src/GameQ/Protocols/Unreal2.php delete mode 100644 GameQ/src/GameQ/Protocols/Unturned.php delete mode 100644 GameQ/src/GameQ/Protocols/Urbanterror.php delete mode 100644 GameQ/src/GameQ/Protocols/Ut.php delete mode 100644 GameQ/src/GameQ/Protocols/Ut2004.php delete mode 100644 GameQ/src/GameQ/Protocols/Ut3.php delete mode 100644 GameQ/src/GameQ/Protocols/Ventrilo.php delete mode 100644 GameQ/src/GameQ/Protocols/Warsow.php delete mode 100644 GameQ/src/GameQ/Protocols/Won.php delete mode 100644 GameQ/src/GameQ/Protocols/Wurm.php delete mode 100644 GameQ/src/GameQ/Query/Core.php delete mode 100644 GameQ/src/GameQ/Query/Native.php delete mode 100644 GameQ/src/GameQ/Result.php delete mode 100644 GameQ/src/GameQ/Server.php delete mode 100644 GameQ/status_expansion.php delete mode 100644 GameQ/status_livonia.php rename dayz2json_parser_sql.php => SQL/dayz2json_parser_sql.php (77%) rename regex_statserver_json.php => SQL/regex_statserver_json.php (99%) rename table.sql => SQL/table.sql (100%) diff --git a/GameQ/.github/FUNDING.yml b/GameQ/.github/FUNDING.yml deleted file mode 100644 index ab0b19c..0000000 --- a/GameQ/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: ["https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VAU2KADATP5PU"] diff --git a/GameQ/.github/issue_label_bot.yaml b/GameQ/.github/issue_label_bot.yaml deleted file mode 100644 index fffb9aa..0000000 --- a/GameQ/.github/issue_label_bot.yaml +++ /dev/null @@ -1,4 +0,0 @@ -label-alias: - bug: 'Bug' - feature_request: 'Feature Request' - question: 'Support' diff --git a/GameQ/.github/stale.yml b/GameQ/.github/stale.yml deleted file mode 100644 index befa7b4..0000000 --- a/GameQ/.github/stale.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 28 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 14 -# Issues with these labels will never be considered stale -exemptLabels: - - Bug - - Feature Request - - Support -# Label to use when marking an issue as stale -staleLabel: Stale -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false - diff --git a/GameQ/Autoloader.php b/GameQ/Autoloader.php deleted file mode 100644 index 7c8eb41..0000000 --- a/GameQ/Autoloader.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * - * - */ - -/** - * A simple PSR-4 spec auto loader to allow GameQ to function the same as if it were loaded via Composer - * - * To use this just include this file in your script and the GameQ namespace will be made available - * - * i.e. require_once('/path/to/src/GameQ/Autoloader.php'); - * - * See: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md - * - * @codeCoverageIgnore - */ -spl_autoload_register(function ($class) { - - // project-specific namespace prefix - $prefix = 'GameQ\\'; - - // base directory for the namespace prefix - $base_dir = __DIR__ . DIRECTORY_SEPARATOR; - - // does the class use the namespace prefix? - $len = strlen($prefix); - - if (strncmp($prefix, $class, $len) !== 0) { - // no, move to the next registered autoloader - return; - } - - // get the relative class name - $relative_class = substr($class, $len); - - // replace the namespace prefix with the base directory, replace namespace - // separators with directory separators in the relative class name, append - // with .php - $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php'; - - // if the file exists, require it - if (file_exists($file)) { - require $file; - } -}); diff --git a/GameQ/Buffer.php b/GameQ/Buffer.php deleted file mode 100644 index e9e1552..0000000 --- a/GameQ/Buffer.php +++ /dev/null @@ -1,501 +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 $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 ($p = strpos($this->data, $delim, min($this->index, $this->length))) { - $pos[] = $p; - } - } - - // 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() - { - - // 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 = 'Lint'; - } - - // Unpack the number - $int = unpack($type, $this->read(4)); - - 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']; - } -} diff --git a/GameQ/CONTRIBUTING.md b/GameQ/CONTRIBUTING.md deleted file mode 100644 index c504042..0000000 --- a/GameQ/CONTRIBUTING.md +++ /dev/null @@ -1,39 +0,0 @@ -# Contributing - -Contributions are **welcome** and will be fully **credited**. - -## Pull Requests - -- **Document any change in behavior** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. - -- **Create feature branches** - Don't ask us to pull from your master branch. - -- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. - -## Coding Standard - -- The **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** is to be used for all code. -- **[PHPMD](http://phpmd.org/)** is used to help keep the code clean but exceptions can exist. - -- Use the following commands to check your code before committing it: - -```sh -$ vendor/bin/phpcs src tests --extensions=php --ignore=bootstrap --report=checkstyle --report-file=build/logs/checkstyle.xml --standard=build/config/phpcs.xml -v -$ vendor/bin/phpmd src,tests xml build/config/phpmd.xml -``` - - -## Tests - -- **Add tests!** - Your patch won't be accepted if it doesn't have tests. - -- Run tests by calling `phpunit` -```sh -$ vendor/bin/phpunit -``` - -The coding standard, mess detection and tests are validated by [Travis CI](.travis.yml). - -# Can't Contribute? -If you do not feel comfortable writing your own changes feel free open up a [new issue](https://github.com/Austinb/GameQ/issues/new) for -to add a game or feature. \ No newline at end of file diff --git a/GameQ/Exception/Protocol.php b/GameQ/Exception/Protocol.php deleted file mode 100644 index 035fc6d..0000000 --- a/GameQ/Exception/Protocol.php +++ /dev/null @@ -1,30 +0,0 @@ -. - * - * - */ - -namespace GameQ\Exception; - -/** - * Exception - * - * @author Austin Bischoff - */ -class Protocol extends \Exception -{ -} diff --git a/GameQ/Exception/Query.php b/GameQ/Exception/Query.php deleted file mode 100644 index cc69f39..0000000 --- a/GameQ/Exception/Query.php +++ /dev/null @@ -1,30 +0,0 @@ -. - * - * - */ - -namespace GameQ\Exception; - -/** - * Exception - * - * @author Austin Bischoff - */ -class Query extends \Exception -{ -} diff --git a/GameQ/Exception/Server.php b/GameQ/Exception/Server.php deleted file mode 100644 index 4024551..0000000 --- a/GameQ/Exception/Server.php +++ /dev/null @@ -1,30 +0,0 @@ -. - * - * - */ - -namespace GameQ\Exception; - -/** - * Exception - * - * @author Austin Bischoff - */ -class Server extends \Exception -{ -} diff --git a/GameQ/Filters/Base.php b/GameQ/Filters/Base.php deleted file mode 100644 index 1a3f4e5..0000000 --- a/GameQ/Filters/Base.php +++ /dev/null @@ -1,58 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Abstract base class which all filters must inherit - * - * @author Austin Bischoff - */ -abstract class Base -{ - - /** - * Holds the options for this instance of the filter - * - * @type array - */ - protected $options = []; - - /** - * Construct - * - * @param array $options - */ - public function __construct(array $options = []) - { - - $this->options = $options; - } - - /** - * Apply the filter to the data - * - * @param array $result - * @param \GameQ\Server $server - * - * @return mixed - */ - abstract public function apply(array $result, Server $server); -} diff --git a/GameQ/Filters/Normalize.php b/GameQ/Filters/Normalize.php deleted file mode 100644 index 5771c92..0000000 --- a/GameQ/Filters/Normalize.php +++ /dev/null @@ -1,133 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Class Normalize - * - * @package GameQ\Filters - */ -class Normalize extends Base -{ - - /** - * Holds the protocol specific normalize information - * - * @type array - */ - protected $normalize = []; - - /** - * Apply this filter - * - * @param array $result - * @param \GameQ\Server $server - * - * @return array - */ - public function apply(array $result, Server $server) - { - - // No result passed so just return - if (empty($result)) { - return $result; - } - - //$data = [ ]; - //$data['raw'][$server->id()] = $result; - - // Grab the normalize for this protocol for the specific server - $this->normalize = $server->protocol()->getNormalize(); - - // Do general information - $result = array_merge($result, $this->check('general', $result)); - - // Do player information - if (isset($result['players']) && count($result['players']) > 0) { - // Iterate - foreach ($result['players'] as $key => $player) { - $result['players'][$key] = array_merge($player, $this->check('player', $player)); - } - } else { - $result['players'] = []; - } - - // Do team information - if (isset($result['teams']) && count($result['teams']) > 0) { - // Iterate - foreach ($result['teams'] as $key => $team) { - $result['teams'][$key] = array_merge($team, $this->check('team', $team)); - } - } else { - $result['teams'] = []; - } - - //$data['filtered'][$server->id()] = $result; - /*file_put_contents( - sprintf('%s/../../../tests/Filters/Providers/Normalize/%s_1.json', __DIR__, $server->protocol()->getProtocol()), - json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) - );*/ - - // Return the normalized result - return $result; - } - - /** - * Check a section for normalization - * - * @param $section - * @param $data - * - * @return array - */ - protected function check($section, $data) - { - - // Normalized return array - $normalized = []; - - if (isset($this->normalize[$section]) && !empty($this->normalize[$section])) { - foreach ($this->normalize[$section] as $property => $raw) { - // Default the value for the new key as null - $value = null; - - if (is_array($raw)) { - // Iterate over the raw property we want to use - foreach ($raw as $check) { - if (array_key_exists($check, $data)) { - $value = $data[$check]; - break; - } - } - } else { - // String - if (array_key_exists($raw, $data)) { - $value = $data[$raw]; - } - } - - $normalized['gq_' . $property] = $value; - } - } - - return $normalized; - } -} diff --git a/GameQ/Filters/Secondstohuman.php b/GameQ/Filters/Secondstohuman.php deleted file mode 100644 index 1b413f7..0000000 --- a/GameQ/Filters/Secondstohuman.php +++ /dev/null @@ -1,121 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Class Secondstohuman - * - * This class converts seconds into a human readable time string 'hh:mm:ss'. This is mainly for converting - * a player's connected time into a readable string. Note that most game servers DO NOT return a player's connected - * time. Source (A2S) based games generally do but not always. This class can also be used to convert other time - * responses into readable time - * - * @package GameQ\Filters - * @author Austin Bischoff - */ -class Secondstohuman extends Base -{ - - /** - * The options key for setting the data key(s) to look for to convert - */ - const OPTION_TIMEKEYS = 'timekeys'; - - /** - * The result key added when applying this filter to a result - */ - const RESULT_KEY = 'gq_%s_human'; - - /** - * Holds the default 'time' keys from the response array. This is key is usually 'time' from A2S responses - * - * @var array - */ - protected $timeKeysDefault = ['time']; - - /** - * Secondstohuman constructor. - * - * @param array $options - */ - public function __construct(array $options = []) - { - // Check for passed keys - if (!array_key_exists(self::OPTION_TIMEKEYS, $options)) { - // Use default - $options[self::OPTION_TIMEKEYS] = $this->timeKeysDefault; - } else { - // Used passed key(s) and make sure it is an array - $options[self::OPTION_TIMEKEYS] = (!is_array($options[self::OPTION_TIMEKEYS])) ? - [$options[self::OPTION_TIMEKEYS]] : $options[self::OPTION_TIMEKEYS]; - } - - parent::__construct($options); - } - - /** - * Apply this filter to the result data - * - * @param array $result - * @param Server $server - * - * @return array - */ - public function apply(array $result, Server $server) - { - // Send the results off to be iterated and return the updated result - return $this->iterate($result); - } - - /** - * Home grown iterate function. Would like to replace this with an internal PHP method(s) but could not find a way - * to make the iterate classes add new keys to the response. They all seemed to be read-only. - * - * @todo: See if there is a more internal way of handling this instead of foreach looping and recursive calling - * - * @param array $result - * - * @return array - */ - protected function iterate(array &$result) - { - // Iterate over the results - foreach ($result as $key => $value) { - // Offload to itself if we have another array - if (is_array($value)) { - // Iterate and update the result - $result[$key] = $this->iterate($value); - } elseif (in_array($key, $this->options[self::OPTION_TIMEKEYS])) { - // Make sure the value is a float (throws E_WARNING in PHP 7.1+) - $value = floatval($value); - // We match one of the keys we are wanting to convert so add it and move on - $result[sprintf(self::RESULT_KEY, $key)] = sprintf( - "%02d:%02d:%02d", - floor($value / 3600), - ($value / 60) % 60, - $value % 60 - ); - } - } - - return $result; - } -} diff --git a/GameQ/Filters/Stripcolors.php b/GameQ/Filters/Stripcolors.php deleted file mode 100644 index 5895304..0000000 --- a/GameQ/Filters/Stripcolors.php +++ /dev/null @@ -1,115 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Class Strip Colors - * - * Strip color codes from UT and Quake based games - * - * @package GameQ\Filters - */ -class Stripcolors extends Base -{ - - /** - * Apply this filter - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * - * @param array $result - * @param \GameQ\Server $server - * - * @return array - */ - public function apply(array $result, Server $server) - { - - // No result passed so just return - if (empty($result)) { - return $result; - } - - //$data = []; - //$data['raw'][ $server->id() ] = $result; - - // Switch based on the base (not game) protocol - switch ($server->protocol()->getProtocol()) { - case 'quake2': - case 'quake3': - case 'doom3': - array_walk_recursive($result, [$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($result, [$this, 'stripUnreal']); - break; - case 'source': - array_walk_recursive($result, [$this, 'stripSource']); - break; - } - - /*$data['filtered'][ $server->id() ] = $result; - file_put_contents( - sprintf( - '%s/../../../tests/Filters/Providers/Stripcolors\%s_1.json', - __DIR__, - $server->protocol()->getProtocol() - ), - json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) - );*/ - - // Return the stripped result - return $result; - } - - /** - * Strip color codes from quake based games - * - * @param string $string - */ - protected function stripQuake(&$string) - { - $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 - * - * @param string $string - */ - protected function stripSource(&$string) - { - $string = strip_tags($string); - } -} diff --git a/GameQ/Filters/Test.php b/GameQ/Filters/Test.php deleted file mode 100644 index 836ddf3..0000000 --- a/GameQ/Filters/Test.php +++ /dev/null @@ -1,47 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Class Test - * - * This is a test filter to be used for testing purposes only. - * - * @package GameQ\Filters - */ -class Test extends Base -{ - /** - * Apply the filter. For this we just return whatever is sent - * - * @SuppressWarnings(PHPMD) - * - * @param array $result - * @param \GameQ\Server $server - * - * @return array - */ - public function apply(array $result, Server $server) - { - - return $result; - } -} diff --git a/GameQ/GameQ.php b/GameQ/GameQ.php deleted file mode 100644 index d3dd9ea..0000000 --- a/GameQ/GameQ.php +++ /dev/null @@ -1,649 +0,0 @@ -. - */ - -namespace GameQ; - -use GameQ\Exception\Protocol as ProtocolException; -use GameQ\Exception\Query as QueryException; - -/** - * Base GameQ Class - * - * This class should be the only one that is included when you use GameQ to query - * any games servers. - * - * Requirements: See wiki or README for more information on the requirements - * - PHP 5.4.14+ - * * Bzip2 - http://www.php.net/manual/en/book.bzip2.php - * - * @author Austin Bischoff - * - * @property bool $debug - * @property string $capture_packets_file - * @property int $stream_timeout - * @property int $timeout - * @property int $write_wait - */ -class GameQ -{ - /* - * Constants - */ - const PROTOCOLS_DIRECTORY = __DIR__ . '/Protocols'; - - /* Static Section */ - - /** - * Holds the instance of itself - * - * @type self - */ - protected static $instance = null; - - /** - * Create a new instance of this class - * - * @return \GameQ\GameQ - */ - public static function factory() - { - - // Create a new instance - self::$instance = new self(); - - // Return this new instance - return self::$instance; - } - - /* Dynamic Section */ - - /** - * Default options - * - * @type array - */ - protected $options = [ - 'debug' => false, - 'timeout' => 3, // Seconds - 'filters' => [ - // Default normalize - 'normalize_d751713988987e9331980363e24189ce' => [ - 'filter' => 'normalize', - 'options' => [], - ], - ], - // Advanced settings - 'stream_timeout' => 200000, // See http://www.php.net/manual/en/function.stream-select.php for more info - 'write_wait' => 500, - // How long (in micro-seconds) to pause between writing to server sockets, helps cpu usage - - // Used for generating protocol test data - 'capture_packets_file' => null, - ]; - - /** - * Array of servers being queried - * - * @type array - */ - protected $servers = []; - - /** - * The query library to use. Default is Native - * - * @type string - */ - protected $queryLibrary = 'GameQ\\Query\\Native'; - - /** - * Holds the instance of the queryLibrary - * - * @type \GameQ\Query\Core|null - */ - protected $query = null; - - /** - * GameQ constructor. - * - * Do some checks as needed so this will operate - */ - public function __construct() - { - // Check for missing utf8_encode function - if (!function_exists('utf8_encode')) { - throw new \Exception("PHP's utf8_encode() function is required - " - . "http://php.net/manual/en/function.utf8-encode.php. Check your php installation."); - } - } - - /** - * Get an option's value - * - * @param mixed $option - * - * @return mixed|null - */ - public function __get($option) - { - - return isset($this->options[$option]) ? $this->options[$option] : null; - } - - /** - * Set an option's value - * - * @param mixed $option - * @param mixed $value - * - * @return bool - */ - public function __set($option, $value) - { - - $this->options[$option] = $value; - - return true; - } - - /** - * Chainable call to __set, uses set as the actual setter - * - * @param mixed $var - * @param mixed $value - * - * @return $this - */ - public function setOption($var, $value) - { - - // Use magic - $this->{$var} = $value; - - return $this; // Make chainable - } - - /** - * Add a single server - * - * @param array $server_info - * - * @return $this - */ - public function addServer(array $server_info = []) - { - - // Add and validate the server - $this->servers[uniqid()] = new Server($server_info); - - return $this; // Make calls chainable - } - - /** - * Add multiple servers in a single call - * - * @param array $servers - * - * @return $this - */ - public function addServers(array $servers = []) - { - - // Loop through all the servers and add them - foreach ($servers as $server_info) { - $this->addServer($server_info); - } - - return $this; // Make calls chainable - } - - /** - * Add a set of servers from a file or an array of files. - * Supported formats: - * JSON - * - * @param array $files - * - * @return $this - * @throws \Exception - */ - public function addServersFromFiles($files = []) - { - - // Since we expect an array let us turn a string (i.e. single file) into an array - if (!is_array($files)) { - $files = [$files]; - } - - // Iterate over the file(s) and add them - foreach ($files as $file) { - // Check to make sure the file exists and we can read it - if (!file_exists($file) || !is_readable($file)) { - continue; - } - - // See if this file is JSON - if (($servers = json_decode(file_get_contents($file), true)) === null - && json_last_error() !== JSON_ERROR_NONE - ) { - // Type not supported - continue; - } - - // Add this list of servers - $this->addServers($servers); - } - - return $this; - } - - /** - * Clear all of the defined servers - * - * @return $this - */ - public function clearServers() - { - - // Reset all the servers - $this->servers = []; - - return $this; // Make Chainable - } - - /** - * Add a filter to the processing list - * - * @param string $filterName - * @param array $options - * - * @return $this - */ - public function addFilter($filterName, $options = []) - { - // Create the filter hash so we can run multiple versions of the same filter - $filterHash = sprintf('%s_%s', strtolower($filterName), md5(json_encode($options))); - - // Add the filter - $this->options['filters'][$filterHash] = [ - 'filter' => strtolower($filterName), - 'options' => $options, - ]; - - unset($filterHash); - - return $this; - } - - /** - * Remove an added filter - * - * @param string $filterHash - * - * @return $this - */ - public function removeFilter($filterHash) - { - // Make lower case - $filterHash = strtolower($filterHash); - - // Remove this filter if it has been defined - if (array_key_exists($filterHash, $this->options['filters'])) { - unset($this->options['filters'][$filterHash]); - } - - unset($filterHash); - - return $this; - } - - /** - * Return the list of applied filters - * - * @return array - */ - public function listFilters() - { - return $this->options['filters']; - } - - /** - * Main method used to actually process all of the added servers and return the information - * - * @return array - * @throws \Exception - */ - public function process() - { - - // Initialize the query library we are using - $class = new \ReflectionClass($this->queryLibrary); - - // Set the query pointer to the new instance of the library - $this->query = $class->newInstance(); - - unset($class); - - // Define the return - $results = []; - - // @todo: Add break up into loop to split large arrays into smaller chunks - - // Do server challenge(s) first, if any - $this->doChallenges(); - - // Do packets for server(s) and get query responses - $this->doQueries(); - - // Now we should have some information to process for each server - foreach ($this->servers as $server) { - /* @var $server \GameQ\Server */ - - // Parse the responses for this server - $result = $this->doParseResponse($server); - - // Apply the filters - $result = array_merge($result, $this->doApplyFilters($result, $server)); - - // Sort the keys so they are alphabetical and nicer to look at - ksort($result); - - // Add the result to the results array - $results[$server->id()] = $result; - } - - return $results; - } - - /** - * Do server challenges, where required - */ - protected function doChallenges() - { - - // Initialize the sockets for reading - $sockets = []; - - // By default we don't have any challenges to process - $server_challenge = false; - - // Do challenge packets - foreach ($this->servers as $server_id => $server) { - /* @var $server \GameQ\Server */ - - // This protocol has a challenge packet that needs to be sent - if ($server->protocol()->hasChallenge()) { - // We have a challenge, set the flag - $server_challenge = true; - - // Let's make a clone of the query class - $socket = clone $this->query; - - // Set the information for this query socket - $socket->set( - $server->protocol()->transport(), - $server->ip, - $server->port_query, - $this->timeout - ); - - try { - // Now write the challenge packet to the socket. - $socket->write($server->protocol()->getPacket(Protocol::PACKET_CHALLENGE)); - - // Add the socket information so we can reference it easily - $sockets[(int)$socket->get()] = [ - 'server_id' => $server_id, - 'socket' => $socket, - ]; - } catch (QueryException $e) { - // Check to see if we are in debug, if so bubble up the exception - if ($this->debug) { - throw new \Exception($e->getMessage(), $e->getCode(), $e); - } - } - - unset($socket); - - // Let's sleep shortly so we are not hammering out calls rapid fire style hogging cpu - usleep($this->write_wait); - } - } - - // We have at least one server with a challenge, we need to listen for responses - if ($server_challenge) { - // Now we need to listen for and grab challenge response(s) - $responses = call_user_func_array( - [$this->query, 'getResponses'], - [$sockets, $this->timeout, $this->stream_timeout] - ); - - // Iterate over the challenge responses - foreach ($responses as $socket_id => $response) { - // Back out the server_id we need to update the challenge response for - $server_id = $sockets[$socket_id]['server_id']; - - // Make this into a buffer so it is easier to manipulate - $challenge = new Buffer(implode('', $response)); - - // Grab the server instance - /* @var $server \GameQ\Server */ - $server = $this->servers[$server_id]; - - // Apply the challenge - $server->protocol()->challengeParseAndApply($challenge); - - // Add this socket to be reused, has to be reused in GameSpy3 for example - $server->socketAdd($sockets[$socket_id]['socket']); - - // Clear - unset($server); - } - } - } - - /** - * Run the actual queries and get the response(s) - */ - protected function doQueries() - { - - // Initialize the array of sockets - $sockets = []; - - // Iterate over the server list - foreach ($this->servers as $server_id => $server) { - /* @var $server \GameQ\Server */ - - // Invoke the beforeSend method - $server->protocol()->beforeSend($server); - - // Get all the non-challenge packets we need to send - $packets = $server->protocol()->getPacket('!' . Protocol::PACKET_CHALLENGE); - - if (count($packets) == 0) { - // Skip nothing else to do for some reason. - continue; - } - - // Try to use an existing socket - if (($socket = $server->socketGet()) === null) { - // Let's make a clone of the query class - $socket = clone $this->query; - - // Set the information for this query socket - $socket->set( - $server->protocol()->transport(), - $server->ip, - $server->port_query, - $this->timeout - ); - } - - try { - // Iterate over all the packets we need to send - foreach ($packets as $packet_data) { - // Now write the packet to the socket. - $socket->write($packet_data); - - // Let's sleep shortly so we are not hammering out calls rapid fire style - usleep($this->write_wait); - } - - unset($packets); - - // Add the socket information so we can reference it easily - $sockets[(int)$socket->get()] = [ - 'server_id' => $server_id, - 'socket' => $socket, - ]; - } catch (QueryException $e) { - // Check to see if we are in debug, if so bubble up the exception - if ($this->debug) { - throw new \Exception($e->getMessage(), $e->getCode(), $e); - } - - break; - } - - // Clean up the sockets, if any left over - $server->socketCleanse(); - } - - // Now we need to listen for and grab response(s) - $responses = call_user_func_array( - [$this->query, 'getResponses'], - [$sockets, $this->timeout, $this->stream_timeout] - ); - - // Iterate over the responses - foreach ($responses as $socket_id => $response) { - // Back out the server_id - $server_id = $sockets[$socket_id]['server_id']; - - // Grab the server instance - /* @var $server \GameQ\Server */ - $server = $this->servers[$server_id]; - - // Save the response from this packet - $server->protocol()->packetResponse($response); - - unset($server); - } - - // Now we need to close all of the sockets - foreach ($sockets as $socketInfo) { - /* @var $socket \GameQ\Query\Core */ - $socket = $socketInfo['socket']; - - // Close the socket - $socket->close(); - - unset($socket); - } - - unset($sockets); - } - - /** - * Parse the response for a specific server - * - * @param \GameQ\Server $server - * - * @return array - * @throws \Exception - */ - protected function doParseResponse(Server $server) - { - - try { - // @codeCoverageIgnoreStart - // We want to save this server's response to a file (useful for unit testing) - if (!is_null($this->capture_packets_file)) { - file_put_contents( - $this->capture_packets_file, - implode(PHP_EOL . '||' . PHP_EOL, $server->protocol()->packetResponse()) - ); - } - // @codeCoverageIgnoreEnd - - // Get the server response - $results = $server->protocol()->processResponse(); - - // Check for online before we do anything else - $results['gq_online'] = (count($results) > 0); - } catch (ProtocolException $e) { - // Check to see if we are in debug, if so bubble up the exception - if ($this->debug) { - throw new \Exception($e->getMessage(), $e->getCode(), $e); - } - - // We ignore this server - $results = [ - 'gq_online' => false, - ]; - } - - // Now add some default stuff - $results['gq_address'] = (isset($results['gq_address'])) ? $results['gq_address'] : $server->ip(); - $results['gq_port_client'] = $server->portClient(); - $results['gq_port_query'] = (isset($results['gq_port_query'])) ? $results['gq_port_query'] : $server->portQuery(); - $results['gq_protocol'] = $server->protocol()->getProtocol(); - $results['gq_type'] = (string)$server->protocol(); - $results['gq_name'] = $server->protocol()->nameLong(); - $results['gq_transport'] = $server->protocol()->transport(); - - // Process the join link - if (!isset($results['gq_joinlink']) || empty($results['gq_joinlink'])) { - $results['gq_joinlink'] = $server->getJoinLink(); - } - - return $results; - } - - /** - * Apply any filters to the results - * - * @param array $results - * @param \GameQ\Server $server - * - * @return array - */ - protected function doApplyFilters(array $results, Server $server) - { - - // Loop over the filters - foreach ($this->options['filters'] as $filterOptions) { - // Try to do this filter - try { - // Make a new reflection class - $class = new \ReflectionClass(sprintf('GameQ\\Filters\\%s', ucfirst($filterOptions['filter']))); - - // Create a new instance of the filter class specified - $filter = $class->newInstanceArgs([$filterOptions['options']]); - - // Apply the filter to the data - $results = $filter->apply($results, $server); - } catch (\ReflectionException $e) { - // Invalid, skip it - continue; - } - } - - return $results; - } -} diff --git a/GameQ/LICENSE.lgpl b/GameQ/LICENSE.lgpl deleted file mode 100644 index 02bbb60..0000000 --- a/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/GameQ/Protocol.php b/GameQ/Protocol.php deleted file mode 100644 index 6d94a45..0000000 --- a/GameQ/Protocol.php +++ /dev/null @@ -1,500 +0,0 @@ -. - * - * - */ - -namespace GameQ; - -/** - * Handles the core functionality for the protocols - * - * @SuppressWarnings(PHPMD.NumberOfChildren) - * - * @author Austin Bischoff - */ -abstract class Protocol -{ - - /** - * 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'; - - const TRANSPORT_SSL = 'ssl'; - - const TRANSPORT_TLS = 'tls'; - - /** - * Short name of the protocol - * - * @type string - */ - protected $name = 'unknown'; - - /** - * The longer, fancier name for the protocol - * - * @type string - */ - protected $name_long = 'unknown'; - - /** - * The difference between the client port and query port - * - * @type int - */ - protected $port_diff = 0; - - /** - * The transport method to use to actually send the data - * Default is UDP - * - * @type string - */ - protected $transport = self::TRANSPORT_UDP; - - /** - * The protocol type used when querying the server - * - * @type string - */ - protected $protocol = 'unknown'; - - /** - * Holds the valid packet types this protocol has available. - * - * @type array - */ - protected $packets = []; - - /** - * Holds the response headers and the method to use to process them. - * - * @type array - */ - protected $responses = []; - - /** - * Holds the list of methods to run when parsing the packet response(s) data. These - * methods should provide all the return information. - * - * @type array - */ - protected $process_methods = []; - - /** - * The packet responses received - * - * @type array - */ - protected $packets_response = []; - - /** - * Holds the instance of the result class - * - * @type null - */ - protected $result = null; - - /** - * Options for this protocol - * - * @type array - */ - protected $options = []; - - /** - * Define the state of this class - * - * @type int - */ - protected $state = self::STATE_STABLE; - - /** - * Holds specific normalize settings - * - * @todo: Remove this ugly bulk by moving specific ones to their specific game(s) - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => [ - 'listenserver', - 'dedic', - 'bf2dedicated', - 'netserverdedicated', - 'bf2142dedicated', - 'dedicated', - ], - 'gametype' => ['ggametype', 'sigametype', 'matchtype'], - 'hostname' => ['svhostname', 'servername', 'siname', 'name'], - 'mapname' => ['map', 'simap'], - 'maxplayers' => ['svmaxclients', 'simaxplayers', 'maxclients', 'max_players'], - 'mod' => ['game', 'gamedir', 'gamevariant'], - 'numplayers' => ['clients', 'sinumplayers', 'num_players'], - 'password' => ['protected', 'siusepass', 'sineedpass', 'pswrd', 'gneedpass', 'auth', 'passsord'], - ], - // Indvidual - 'player' => [ - 'name' => ['nick', 'player', 'playername', 'name'], - 'kills' => ['kills'], - 'deaths' => ['deaths'], - 'score' => ['kills', 'frags', 'skill', 'score'], - 'ping' => ['ping'], - ], - // Team - 'team' => [ - 'name' => ['name', 'teamname', 'team_t'], - 'score' => ['score', 'score_t'], - ], - ]; - - /** - * Quick join link - * - * @type string - */ - protected $join_link = ''; - - /** - * @param array $options - */ - public function __construct(array $options = []) - { - - // Set the options for this specific instance of the class - $this->options = $options; - } - - /** - * String name of this class - * - * @return string - */ - public function __toString() - { - - return $this->name; - } - - /** - * Get the port difference between the server's client (game) and query ports - * - * @return int - */ - public function portDiff() - { - - return $this->port_diff; - } - - /** - * "Find" the query port based off of the client port and port_diff - * - * This method is meant to be overloaded for more complex maths or lookup tables - * - * @param int $clientPort - * - * @return int - */ - public function findQueryPort($clientPort) - { - - return $clientPort + $this->port_diff; - } - - /** - * Return the join_link as defined by the protocol class - * - * @return string - */ - public function joinLink() - { - - return $this->join_link; - } - - /** - * Short (callable) name of this class - * - * @return string - */ - public function name() - { - - return $this->name; - } - - /** - * Long name of this class - * - * @return string - */ - public function nameLong() - { - - return $this->name_long; - } - - /** - * Return the status of this Protocol Class - * - * @return int - */ - public function state() - { - - return $this->state; - } - - /** - * Return the protocol property - * - * @return string - */ - public function getProtocol() - { - - return $this->protocol; - } - - /** - * Get/set the transport type for this protocol - * - * @param string|null $type - * - * @return string - */ - public function transport($type = null) - { - - // Act as setter - if (!is_null($type)) { - $this->transport = $type; - } - - return $this->transport; - } - - /** - * Set the options for the protocol call - * - * @param array $options - * - * @return array - */ - public function options($options = []) - { - - // Act as setter - if (!empty($options)) { - $this->options = $options; - } - - return $this->options; - } - - - /* - * Packet Section - */ - - /** - * Return specific packet(s) - * - * @param array $type - * - * @return array - */ - public function getPacket($type = []) - { - - $packets = []; - - - // We want an array of packets back - if (is_array($type) && !empty($type)) { - // 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; - } - } - } elseif ($type == '!challenge') { - // Loop the packets - foreach ($this->packets as $packet_type => $packet_data) { - // Dont want challenge packets - if ($packet_type != self::PACKET_CHALLENGE) { - $packets[$packet_type] = $packet_data; - } - } - } elseif (is_string($type)) { - // Return specific packet type - $packets = $this->packets[$type]; - } else { - // Return all packets - $packets = $this->packets; - } - - // Return the packets - return $packets; - } - - /** - * Get/set the packet response - * - * @param array|null $response - * - * @return array - */ - public function packetResponse(array $response = null) - { - - // Act as setter - if (!empty($response)) { - $this->packets_response = $response; - } - - return $this->packets_response; - } - - - /* - * Challenge section - */ - - /** - * Determine whether or not this protocol has a challenge needed before querying - * - * @return bool - */ - public function hasChallenge() - { - - return (isset($this->packets[self::PACKET_CHALLENGE]) && !empty($this->packets[self::PACKET_CHALLENGE])); - } - - /** - * Parse the challenge response and add it to the buffer items that need it. - * This should be overloaded by extending class - * - * @codeCoverageIgnore - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param \GameQ\Buffer $challenge_buffer - * - * @return bool - */ - public function challengeParseAndApply(Buffer $challenge_buffer) - { - - return true; - } - - /** - * Apply the challenge string to all the packets that need it. - * - * @param string $challenge_string - * - * @return bool - */ - protected function challengeApply($challenge_string) - { - - // Let's loop through 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; - } - - /** - * Get the normalize settings for the protocol - * - * @return array - */ - public function getNormalize() - { - - return $this->normalize; - } - - /* - * General - */ - - /** - * Generic method to allow protocol classes to do work right before the query is sent - * - * @codeCoverageIgnore - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param \GameQ\Server $server - */ - public function beforeSend(Server $server) - { - } - - /** - * Method called to process query response data. Each extending class has to have one of these functions. - * - * @return mixed - */ - abstract public function processResponse(); -} diff --git a/GameQ/Protocols/Aa3.php b/GameQ/Protocols/Aa3.php deleted file mode 100644 index 6ffd412..0000000 --- a/GameQ/Protocols/Aa3.php +++ /dev/null @@ -1,53 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Aa3 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Aa3 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'aa3'; - - /** - * 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/GameQ/Protocols/Aapg.php b/GameQ/Protocols/Aapg.php deleted file mode 100644 index a207d4f..0000000 --- a/GameQ/Protocols/Aapg.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Aapg - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Aapg extends Aa3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'aapg'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "America's Army: Proving Grounds"; -} diff --git a/GameQ/Protocols/Arkse.php b/GameQ/Protocols/Arkse.php deleted file mode 100644 index 3193c5a..0000000 --- a/GameQ/Protocols/Arkse.php +++ /dev/null @@ -1,51 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class ARK: Survival Evolved - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Arkse extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'arkse'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "ARK: Survival Evolved"; - - /** - * query_port = client_port + 19238 - * 27015 = 7777 + 19238 - * - * @type int - */ - protected $port_diff = 19238; -} diff --git a/GameQ/Protocols/Arma.php b/GameQ/Protocols/Arma.php deleted file mode 100644 index 2653872..0000000 --- a/GameQ/Protocols/Arma.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Arma - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Arma extends Gamespy2 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'arma'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "ArmA Armed Assault"; -} diff --git a/GameQ/Protocols/Arma3.php b/GameQ/Protocols/Arma3.php deleted file mode 100644 index 2718587..0000000 --- a/GameQ/Protocols/Arma3.php +++ /dev/null @@ -1,181 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Class Armed Assault 3 - * - * Rules protocol reference: https://community.bistudio.com/wiki/Arma_3_ServerBrowserProtocol2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - * @author Memphis017 - */ -class Arma3 extends Source -{ - /** - * Defines the names for the specific game DLCs - * - * @var array - */ - protected $dlcNames = [ - 'af82811b' => 'Karts', - '94f76a1a' => 'Marksmen', - 'd0356eec' => 'Helicopters', - '19984a71' => 'Zeus', - '7fb4b1f3' => 'Apex', - '49c2c12b' => 'Jets', - '7e766e18' => 'Laws of War', - '99d71f90' => 'Malden', - 'a8b10cdf' => 'Tac-Ops', - '37680ce8' => 'Tanks', - '43f9c377' => 'Contact', - 'c4979557' => 'Enoch', - ]; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'arma3'; - - /** - * Longer string name of this protocol class - * - * @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()); - $result->add('overflow', $responseBuffer->readInt8()); - $dlcBit = decbin($responseBuffer->readInt8()); // Grab DLC bit 1 and use it later - $dlcBit2 = decbin($responseBuffer->readInt8()); // Grab DLC bit 2 and use it later - $dlcCount = substr_count($dlcBit, '1') + substr_count($dlcBit2, '1'); // Count the DLCs - - // 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 DLC bit so we can pull in the info for the DLC (if enabled) - for ($x = 0; $x < $dlcCount; $x++) { - $dlcHash = dechex($responseBuffer->readInt32()); - isset($this->dlcNames[$dlcHash]) ? - $result->addSub('dlcs', 'name', $this->dlcNames[$dlcHash]) - : $result->addSub('dlcs', 'name', 'Unknown'); - $result->addSub('dlcs', 'hash', $dlcHash); - } - - // No longer needed - unset($dlcBit, $dlcBit2, $dlcCount, $dlcHash); - - // Grab the mod count - $modCount = $responseBuffer->readInt8(); - - // Add mod count - $result->add('mod_count', $modCount); - - // Loop the mod count and add them - for ($x = 0; $x < $modCount; $x++) { - // Add the mod to the list - $result->addSub('mods', 'hash', dechex($responseBuffer->readInt32())); - $result->addSub('mods', 'steam_id', hexdec($responseBuffer->readPascalString(0, true))); - $result->addSub('mods', 'name', $responseBuffer->readPascalString(0, true)); - } - - unset($modCount, $x); - - // 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/GameQ/Protocols/Armedassault2oa.php b/GameQ/Protocols/Armedassault2oa.php deleted file mode 100644 index e527a38..0000000 --- a/GameQ/Protocols/Armedassault2oa.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/Protocols/Armedassault3.php b/GameQ/Protocols/Armedassault3.php deleted file mode 100644 index 5bbca42..0000000 --- a/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/GameQ/Protocols/Ase.php b/GameQ/Protocols/Ase.php deleted file mode 100644 index cb5c6a4..0000000 --- a/GameQ/Protocols/Ase.php +++ /dev/null @@ -1,208 +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)); - - // Burn the header - $buffer->skip(4); - - // 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/GameQ/Protocols/Atlas.php b/GameQ/Protocols/Atlas.php deleted file mode 100644 index 83406ba..0000000 --- a/GameQ/Protocols/Atlas.php +++ /dev/null @@ -1,55 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Atlas - * - * @package GameQ\Protocols - * @author Wilson Jesus <> - */ -class Atlas extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'atlas'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Atlas"; - - /** - * query_port = client_port + 51800 - * 57561 = 5761 + 51800 - * - * this is the default value for the stock game server, both ports - * can be independently changed from the stock ones, - * making the port_diff logic useless. - * - * @type int - */ - protected $port_diff = 51800; -} diff --git a/GameQ/Protocols/Batt1944.php b/GameQ/Protocols/Batt1944.php deleted file mode 100644 index f0ff38e..0000000 --- a/GameQ/Protocols/Batt1944.php +++ /dev/null @@ -1,68 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Battalion 1944 - * - * @package GameQ\Protocols - * @author TacTicToe66 - */ -class Batt1944 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'batt1944'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Battalion 1944"; - - /** - * query_port = client_port + 3 - * - * @type int - */ - protected $port_diff = 3; - - /** - * Normalize main fields - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'bat_gamemode_s', - 'hostname' => 'bat_name_s', - 'mapname' => 'bat_map_s', - 'maxplayers' => 'bat_max_players_i', - 'numplayers' => 'bat_player_count_s', - 'password' => 'bat_has_password_s', - ], - ]; -} diff --git a/GameQ/Protocols/Bf1942.php b/GameQ/Protocols/Bf1942.php deleted file mode 100644 index 4cf06c5..0000000 --- a/GameQ/Protocols/Bf1942.php +++ /dev/null @@ -1,88 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/Protocols/Bf2.php b/GameQ/Protocols/Bf2.php deleted file mode 100644 index 0610f9d..0000000 --- a/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/GameQ/Protocols/Bf3.php b/GameQ/Protocols/Bf3.php deleted file mode 100644 index 9084515..0000000 --- a/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/GameQ/Protocols/Bf4.php b/GameQ/Protocols/Bf4.php deleted file mode 100644 index 6951752..0000000 --- a/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/GameQ/Protocols/Bfbc2.php b/GameQ/Protocols/Bfbc2.php deleted file mode 100644 index b7167a0..0000000 --- a/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/GameQ/Protocols/Bfh.php b/GameQ/Protocols/Bfh.php deleted file mode 100644 index 067d77f..0000000 --- a/GameQ/Protocols/Bfh.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Battlefield Hardline Protocol class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Bfh extends Bf4 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'bfh'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Battlefield Hardline"; -} diff --git a/GameQ/Protocols/Brink.php b/GameQ/Protocols/Brink.php deleted file mode 100644 index 2022652..0000000 --- a/GameQ/Protocols/Brink.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Brink - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Brink extends Source -{ - /** - * 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/GameQ/Protocols/Cod.php b/GameQ/Protocols/Cod.php deleted file mode 100644 index 2425ea6..0000000 --- a/GameQ/Protocols/Cod.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Call of Duty Protocol Class - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Cod extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cod'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Call of Duty"; -} diff --git a/GameQ/Protocols/Cod2.php b/GameQ/Protocols/Cod2.php deleted file mode 100644 index 79be7ca..0000000 --- a/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/GameQ/Protocols/Cod4.php b/GameQ/Protocols/Cod4.php deleted file mode 100644 index 9838d9c..0000000 --- a/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/GameQ/Protocols/Codmw3.php b/GameQ/Protocols/Codmw3.php deleted file mode 100644 index 1049b60..0000000 --- a/GameQ/Protocols/Codmw3.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/Protocols/Coduo.php b/GameQ/Protocols/Coduo.php deleted file mode 100644 index 2dd9a18..0000000 --- a/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/GameQ/Protocols/Codwaw.php b/GameQ/Protocols/Codwaw.php deleted file mode 100644 index f730678..0000000 --- a/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/GameQ/Protocols/Conanexiles.php b/GameQ/Protocols/Conanexiles.php deleted file mode 100644 index a097e1d..0000000 --- a/GameQ/Protocols/Conanexiles.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Conanexiles - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Conanexiles extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'conanexiles'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Conan Exiles"; -} diff --git a/GameQ/Protocols/Contagion.php b/GameQ/Protocols/Contagion.php deleted file mode 100644 index 64d0b76..0000000 --- a/GameQ/Protocols/Contagion.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Contagion - * - * @package GameQ\Protocols - * @author Nikolay Ipanyuk - * @author Austin Bischoff - */ -class Contagion extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'contagion'; - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Contagion"; -} diff --git a/GameQ/Protocols/Crysis.php b/GameQ/Protocols/Crysis.php deleted file mode 100644 index e09a673..0000000 --- a/GameQ/Protocols/Crysis.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/Protocols/Crysis2.php b/GameQ/Protocols/Crysis2.php deleted file mode 100644 index 75c6614..0000000 --- a/GameQ/Protocols/Crysis2.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/Protocols/Crysiswars.php b/GameQ/Protocols/Crysiswars.php deleted file mode 100644 index 44dcdcf..0000000 --- a/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/GameQ/Protocols/Cs15.php b/GameQ/Protocols/Cs15.php deleted file mode 100644 index ba37524..0000000 --- a/GameQ/Protocols/Cs15.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Counter-Strike 1.5 Protocol Class - * - * @author Nikolay Ipanyuk - * @author Austin Bischoff - * - * @package GameQ\Protocols - */ -class Cs15 extends Won -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cs15'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Counter-Strike 1.5"; -} diff --git a/GameQ/Protocols/Cs16.php b/GameQ/Protocols/Cs16.php deleted file mode 100644 index 25a6602..0000000 --- a/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/GameQ/Protocols/Cs2d.php b/GameQ/Protocols/Cs2d.php deleted file mode 100644 index 0f238fd..0000000 --- a/GameQ/Protocols/Cs2d.php +++ /dev/null @@ -1,263 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Counter-Strike 2d Protocol Class - * - * Note: - * Unable to make player information calls work as the protocol does not like parallel requests - * - * @author Austin Bischoff - */ -class Cs2d extends Protocol -{ - - /** - * Array of packets we want to query. - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\x01\x00\xFB\x01", - //self::PACKET_STATUS => "\x01\x00\x03\x10\x21\xFB\x01\x75\x00", - self::PACKET_PLAYERS => "\x01\x00\xFB\x05", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\x01\x00\xFB\x01" => "processDetails", - "\x01\x00\xFB\x05" => "processPlayers", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'cs2d'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cs2d'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Counter-Strike 2d"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "cs2d://%s:%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'game_mode', - 'hostname' => 'hostname', - 'mapname' => 'mapname', - 'maxplayers' => 'max_players', - 'mod' => 'game_dir', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'deaths' => 'deaths', - 'score' => 'score', - ], - ]; - - /** - * Process the response for the Tibia server - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // We have a merged packet, try to split it back up - if (count($this->packets_response) == 1) { - // Temp buffer to make string manipulation easier - $buffer = new Buffer($this->packets_response[0]); - - // Grab the header and set the packet we need to split with - $packet = (($buffer->lookAhead(4) === $this->packets[self::PACKET_PLAYERS]) ? - self::PACKET_STATUS : self::PACKET_PLAYERS); - - // Explode the merged packet as the response - $responses = explode(substr($this->packets[$packet], 2), $buffer->getData()); - - // Try to rebuild the second packet to the same as if it was sent as two separate responses - $responses[1] = $this->packets[$packet] . ((count($responses) === 2) ? $responses[1] : ""); - - unset($buffer); - } else { - $responses = $this->packets_response; - } - - // 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 ($responses as $response) { - $buffer = new Buffer($response); - - // Pull out the header - $header = $buffer->read(4); - - // 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; - } - - /** - * Handles processing the details data into a usable format - * - * @param Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processDetails(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - // First int is the server flags - $serverFlags = $buffer->readInt8(); - - // Read server flags - $result->add('password', (int)$this->readFlag($serverFlags, 0)); - $result->add('registered_only', (int)$this->readFlag($serverFlags, 1)); - $result->add('fog_of_war', (int)$this->readFlag($serverFlags, 2)); - $result->add('friendly_fire', (int)$this->readFlag($serverFlags, 3)); - $result->add('bots_enabled', (int)$this->readFlag($serverFlags, 5)); - $result->add('lua_scripts', (int)$this->readFlag($serverFlags, 6)); - - // Read the rest of the buffer data - $result->add('servername', utf8_encode($buffer->readPascalString(0))); - $result->add('mapname', utf8_encode($buffer->readPascalString(0))); - $result->add('num_players', $buffer->readInt8()); - $result->add('max_players', $buffer->readInt8()); - $result->add('game_mode', $buffer->readInt8()); - $result->add('num_bots', (($this->readFlag($serverFlags, 5)) ? $buffer->readInt8() : 0)); - $result->add('dedicated', 1); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the player data into a usable format - * - * @param Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // First entry is the number of players in this list. Don't care - $buffer->read(); - - // Parse players - while ($buffer->getLength()) { - // Player id - if (($id = $buffer->readInt8()) !== 0) { - // Add the results - $result->addPlayer('id', $id); - $result->addPlayer('name', utf8_encode($buffer->readPascalString(0))); - $result->addPlayer('team', $buffer->readInt8()); - $result->addPlayer('score', $buffer->readInt32()); - $result->addPlayer('deaths', $buffer->readInt32()); - } - } - - unset($buffer, $id); - - return $result->fetch(); - } - - /** - * Read flags from stored value - * - * @param $flags - * @param $offset - * - * @return bool - */ - protected function readFlag($flags, $offset) - { - return !!($flags & (1 << $offset)); - } -} diff --git a/GameQ/Protocols/Cscz.php b/GameQ/Protocols/Cscz.php deleted file mode 100644 index b539128..0000000 --- a/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/GameQ/Protocols/Csgo.php b/GameQ/Protocols/Csgo.php deleted file mode 100644 index 41af735..0000000 --- a/GameQ/Protocols/Csgo.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Csgo - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Csgo extends Source -{ - - /** - * 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/GameQ/Protocols/Css.php b/GameQ/Protocols/Css.php deleted file mode 100644 index be75da3..0000000 --- a/GameQ/Protocols/Css.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Css - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Css extends 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/GameQ/Protocols/Dal.php b/GameQ/Protocols/Dal.php deleted file mode 100644 index 6b05037..0000000 --- a/GameQ/Protocols/Dal.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Dark and Light - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dal extends Arkse -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'dal'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Dark and Light"; -} diff --git a/GameQ/Protocols/Dayz.php b/GameQ/Protocols/Dayz.php deleted file mode 100644 index 01c7c28..0000000 --- a/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/GameQ/Protocols/Dayzmod.php b/GameQ/Protocols/Dayzmod.php deleted file mode 100644 index 2ce1076..0000000 --- a/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/GameQ/Protocols/Dod.php b/GameQ/Protocols/Dod.php deleted file mode 100644 index 0c7baf6..0000000 --- a/GameQ/Protocols/Dod.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Dod - * - * Based off of CS 1.6 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dod extends Cs16 -{ - - /** - * 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/GameQ/Protocols/Dods.php b/GameQ/Protocols/Dods.php deleted file mode 100644 index 898d75b..0000000 --- a/GameQ/Protocols/Dods.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Dods - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dods extends 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/GameQ/Protocols/Dow.php b/GameQ/Protocols/Dow.php deleted file mode 100644 index b66512a..0000000 --- a/GameQ/Protocols/Dow.php +++ /dev/null @@ -1,69 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; - -/** - * Class Dow - * - * Apparently the player response is incomplete as there is no information being returned for that packet - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dow extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'dow'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Days of War"; - - /** - * Normalize main fields - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'G_s', - 'hostname' => 'ONM_s', - 'mapname' => 'MPN_s', - 'maxplayers' => 'P_i', - 'numplayers' => 'N_i', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'score' => 'score', - 'time' => 'time', - ], - ]; -} diff --git a/GameQ/Protocols/Eco.php b/GameQ/Protocols/Eco.php deleted file mode 100644 index a2292e9..0000000 --- a/GameQ/Protocols/Eco.php +++ /dev/null @@ -1,123 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Exception\Protocol as Exception; -use GameQ\Result; - -/** - * ECO Global Survival Protocol Class - * - * @author Austin Bischoff - */ -class Eco extends Http -{ - /** - * Packets to send - * - * @var array - */ - protected $packets = [ - self::PACKET_STATUS => "GET /frontpage HTTP/1.0\r\nAccept: */*\r\n\r\n", - ]; - - /** - * Http protocol is SSL - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'eco'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'eco'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "ECO Global Survival"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; - - /** - * Normalize some items - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'description', - 'maxplayers' => 'totalplayers', - 'numplayers' => 'onlineplayers', - 'password' => 'haspassword', - ], - ]; - - /** - * 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 Eco server is invalid."); - } - - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - foreach ($json->Info as $info => $setting) { - $result->add(strtolower($info), $setting); - } - - return $result->fetch(); - } -} diff --git a/GameQ/Protocols/Egs.php b/GameQ/Protocols/Egs.php deleted file mode 100644 index 4f82aa8..0000000 --- a/GameQ/Protocols/Egs.php +++ /dev/null @@ -1,51 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Empyrion - Galactic Survival - * - * @package GameQ\Protocols - * @author Austin Bischoff - * @author TacTicToe66 - */ -class EgS extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'egs'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Empyrion - Galactic Survival"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/Protocols/Et.php b/GameQ/Protocols/Et.php deleted file mode 100644 index 63b5beb..0000000 --- a/GameQ/Protocols/Et.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Wolfenstein Enemy Territory Protocol Class - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Et extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'et'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Wolfenstein Enemy Territory"; -} diff --git a/GameQ/Protocols/Etqw.php b/GameQ/Protocols/Etqw.php deleted file mode 100644 index 1f3a446..0000000 --- a/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/GameQ/Protocols/Ffe.php b/GameQ/Protocols/Ffe.php deleted file mode 100644 index c0947bd..0000000 --- a/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/GameQ/Protocols/Ffow.php b/GameQ/Protocols/Ffow.php deleted file mode 100644 index 00c33d4..0000000 --- a/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/GameQ/Protocols/Gamespy.php b/GameQ/Protocols/Gamespy.php deleted file mode 100644 index b1a1e4f..0000000 --- a/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/GameQ/Protocols/Gamespy2.php b/GameQ/Protocols/Gamespy2.php deleted file mode 100644 index c7788d9..0000000 --- a/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/GameQ/Protocols/Gamespy3.php b/GameQ/Protocols/Gamespy3.php deleted file mode 100644 index 2df0a4b..0000000 --- a/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/GameQ/Protocols/Gamespy4.php b/GameQ/Protocols/Gamespy4.php deleted file mode 100644 index e28755f..0000000 --- a/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/GameQ/Protocols/Gmod.php b/GameQ/Protocols/Gmod.php deleted file mode 100644 index 6596724..0000000 --- a/GameQ/Protocols/Gmod.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Gmod - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Gmod extends Source -{ - /** - * 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/GameQ/Protocols/Grav.php b/GameQ/Protocols/Grav.php deleted file mode 100644 index e025075..0000000 --- a/GameQ/Protocols/Grav.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Grav Online Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Grav extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'grav'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "GRAV Online"; -} diff --git a/GameQ/Protocols/Gta5m.php b/GameQ/Protocols/Gta5m.php deleted file mode 100644 index 0f0c50a..0000000 --- a/GameQ/Protocols/Gta5m.php +++ /dev/null @@ -1,173 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Exception\Protocol as Exception; -use GameQ\Protocol; -use GameQ\Result; - -/** - * GTA Five M Protocol Class - * - * Server base can be found at https://fivem.net/ - * - * Based on code found at https://github.com/LiquidObsidian/fivereborn-query - * - * @author Austin Bischoff - */ -class Gta5m 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\xFF\xFF\xFFgetinfo xxx", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\xFF\xFF\xFF\xFFinfoResponse" => "processStatus", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'gta5m'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'gta5m'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "GTA Five M"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'gametype', - 'hostname' => 'hostname', - 'mapname' => 'mapname', - 'maxplayers' => 'sv_maxclients', - 'mod' => 'gamename', - 'numplayers' => 'clients', - 'password' => 'privateClients', - ], - ]; - - /** - * 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(PHP_EOL); - - // Figure out which packet response this is - if (empty($response_type) || !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(); - - // 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); - - $itemCount = count($data); - - // Now lets loop the array - for ($x = 0; $x < $itemCount; $x += 2) { - // Set some local vars - $key = $data[$x]; - $val = $data[$x + 1]; - - if (in_array($key, ['challenge'])) { - continue; // skip - } - - // Regular variable so just add the value. - $result->add($key, $val); - } - - /*var_dump($data); - var_dump($result->fetch()); - - exit;*/ - - return $result->fetch(); - } -} diff --git a/GameQ/Protocols/Gtan.php b/GameQ/Protocols/Gtan.php deleted file mode 100644 index f7b531e..0000000 --- a/GameQ/Protocols/Gtan.php +++ /dev/null @@ -1,163 +0,0 @@ -. - */ -namespace GameQ\Protocols; - -use GameQ\Exception\Protocol as Exception; -use GameQ\Result; -use GameQ\Server; - -/** - * Grand Theft Auto Network Protocol Class - * https://stats.gtanet.work/ - * - * Result from this call should be a header + JSON response - * - * References: - * - https://master.gtanet.work/apiservers - * - * @author Austin Bischoff - */ -class Gtan extends Http -{ - /** - * Packets to send - * - * @var array - */ - protected $packets = [ - //self::PACKET_STATUS => "GET /apiservers HTTP/1.0\r\nHost: master.gtanet.work\r\nAccept: */*\r\n\r\n", - self::PACKET_STATUS => "GET /gtan/api.php?ip=%s&raw HTTP/1.0\r\nHost: multiplayerhosting.info\r\nAccept: */*\r\n\r\n", - ]; - - /** - * Http protocol is SSL - * - * @var string - */ - protected $transport = self::TRANSPORT_SSL; - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'gtan'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'gtan'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Grand Theft Auto Network"; - - /** - * Holds the real ip so we can overwrite it back - * - * @var string - */ - protected $realIp = null; - - protected $realPortQuery = null; - - /** - * Normalize some items - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'hostname', - 'mapname' => 'map', - 'mod' => 'mod', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - ]; - - public function beforeSend(Server $server) - { - // 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, $server->ip . ':' . $server->port_query); - } - - $this->realIp = $server->ip; - $this->realPortQuery = $server->port_query; - - // Override the existing settings - //$server->ip = 'master.gtanet.work'; - $server->ip = 'multiplayerhosting.info'; - $server->port_query = 443; - } - - /** - * Process the response - * - * @return array - * @throws Exception - */ - public function processResponse() - { - // No response, assume offline - if (empty($this->packets_response)) { - return [ - 'gq_address' => $this->realIp, - 'gq_port_query' => $this->realPortQuery, - ]; - } - - // 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 Gtan protocol is invalid."); - } - - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - $result->add('gq_address', $this->realIp); - $result->add('gq_port_query', $this->realPortQuery); - - // Add server items - $result->add('hostname', $json->ServerName); - $result->add('serverversion', $json->ServerVersion); - $result->add('map', ((!empty($json->Map)) ? $json->Map : 'Los Santos/Blaine Country')); - $result->add('mod', $json->Gamemode); - $result->add('password', (int)$json->Passworded); - $result->add('numplayers', $json->CurrentPlayers); - $result->add('maxplayers', $json->MaxPlayers); - - return $result->fetch(); - } -} diff --git a/GameQ/Protocols/Gtar.php b/GameQ/Protocols/Gtar.php deleted file mode 100644 index 2121e07..0000000 --- a/GameQ/Protocols/Gtar.php +++ /dev/null @@ -1,164 +0,0 @@ -. - */ -namespace GameQ\Protocols; - -use GameQ\Exception\Protocol as Exception; -use GameQ\Result; -use GameQ\Server; - -/** - * Grand Theft Auto Rage Protocol Class - * https://rage.mp/masterlist/ - * - * Result from this call should be a header + JSON response - * - * @author K700 - * @author Austin Bischoff - */ -class Gtar extends Http -{ - /** - * Packets to send - * - * @var array - */ - protected $packets = [ - self::PACKET_STATUS => "GET /master/ HTTP/1.0\r\nHost: cdn.rage.mp\r\nAccept: */*\r\n\r\n", - ]; - - /** - * Http protocol is SSL - * - * @var string - */ - protected $transport = self::TRANSPORT_SSL; - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'gtar'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'gtar'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Grand Theft Auto Rage"; - - /** - * Holds the real ip so we can overwrite it back - * - * @var string - */ - protected $realIp = null; - - protected $realPortQuery = null; - - /** - * Normalize some items - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'hostname', - 'mod' => 'mod', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - ], - ]; - - public function beforeSend(Server $server) - { - // 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, $server->ip . ':' . $server->port_query); - } - - $this->realIp = $server->ip; - $this->realPortQuery = $server->port_query; - - // Override the existing settings - $server->ip = 'cdn.rage.mp'; - $server->port_query = 443; - } - - /** - * Process the response - * - * @return array - * @throws Exception - */ - public function processResponse() - { - // No response, assume offline - if (empty($this->packets_response)) { - return [ - 'gq_address' => $this->realIp, - 'gq_port_query' => $this->realPortQuery, - ]; - } - - // 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 Gtar protocol is invalid."); - } - - $address = $this->realIp.':'.$this->realPortQuery; - $server = $json->$address; - - if (empty($server)) { - return [ - 'gq_address' => $this->realIp, - 'gq_port_query' => $this->realPortQuery, - ]; - } - - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - $result->add('gq_address', $this->realIp); - $result->add('gq_port_query', $this->realPortQuery); - - // Add server items - $result->add('hostname', $server->name); - $result->add('mod', $server->gamemode); - $result->add('numplayers', $server->players); - $result->add('maxplayers', $server->maxplayers); - - return $result->fetch(); - } -} diff --git a/GameQ/Protocols/Hl2dm.php b/GameQ/Protocols/Hl2dm.php deleted file mode 100644 index 15f881a..0000000 --- a/GameQ/Protocols/Hl2dm.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Hl2dm - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Hl2dm extends Source -{ - /** - * 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/GameQ/Protocols/Http.php b/GameQ/Protocols/Http.php deleted file mode 100644 index 2a86d8d..0000000 --- a/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/GameQ/Protocols/Hurtworld.php b/GameQ/Protocols/Hurtworld.php deleted file mode 100644 index fa54654..0000000 --- a/GameQ/Protocols/Hurtworld.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Hurtworld - * - * @package GameQ\Protocols - * @author Nikolay Ipanyuk - * @author Austin Bischoff - */ -class Hurtworld extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'hurtworld'; - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Hurtworld"; -} diff --git a/GameQ/Protocols/Insurgency.php b/GameQ/Protocols/Insurgency.php deleted file mode 100644 index 77b8329..0000000 --- a/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/GameQ/Protocols/Insurgencysand.php b/GameQ/Protocols/Insurgencysand.php deleted file mode 100644 index 407d6e2..0000000 --- a/GameQ/Protocols/Insurgencysand.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Insurgency Sandstorm Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Insurgencysand extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'insurgencysand'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Insurgency: Sandstorm"; - - /** - * query_port = client_port + 29 - * - * @type int - */ - protected $port_diff = 29; -} diff --git a/GameQ/Protocols/Jediacademy.php b/GameQ/Protocols/Jediacademy.php deleted file mode 100644 index a051a3a..0000000 --- a/GameQ/Protocols/Jediacademy.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Jedi Academy Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Jediacademy extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'jediacademy'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Star Wars Jedi Knight: Jedi Academy"; -} diff --git a/GameQ/Protocols/Jedioutcast.php b/GameQ/Protocols/Jedioutcast.php deleted file mode 100644 index 1afd9af..0000000 --- a/GameQ/Protocols/Jedioutcast.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Jedi Outcast Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Jedioutcast extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'jedioutcast'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Star Wars Jedi Knight II: Jedi Outcast"; -} diff --git a/GameQ/Protocols/Justcause2.php b/GameQ/Protocols/Justcause2.php deleted file mode 100644 index 648cb6d..0000000 --- a/GameQ/Protocols/Justcause2.php +++ /dev/null @@ -1,127 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Just Cause 2 Multiplayer Protocol Class - * - * Special thanks to Woet for some insight on packing - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Justcause2 extends Gamespy4 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'justcause2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Just Cause 2 Multiplayer"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "steam://connect/%s:%d/"; - - /** - * Change the packets used - * - * @var 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\x02", - ]; - - /** - * Override the packet split - * - * @var string - */ - protected $packetSplit = "/\\x00\\x00\\x00/m"; - - /** - * 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' => 'name', - 'ping' => 'ping', - ], - ]; - - /** - * Overload so we can add in some static data points - * - * @param Buffer $buffer - * @param Result $result - */ - protected function processDetails(Buffer &$buffer, Result &$result) - { - parent::processDetails($buffer, $result); - - // Add in map - $result->add('mapname', 'Panau'); - $result->add('dedicated', 'true'); - } - - /** - * Override the parent, this protocol is returned differently - * - * @param Buffer $buffer - * @param Result $result - * - * @see Gamespy3::processPlayersAndTeams() - */ - protected function processPlayersAndTeams(Buffer &$buffer, Result &$result) - { - // Loop until we run out of data - while ($buffer->getLength()) { - $result->addPlayer('name', $buffer->readString()); - $result->addPlayer('steamid', $buffer->readString()); - $result->addPlayer('ping', $buffer->readInt16()); - } - } -} diff --git a/GameQ/Protocols/Justcause3.php b/GameQ/Protocols/Justcause3.php deleted file mode 100644 index c4e901d..0000000 --- a/GameQ/Protocols/Justcause3.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Just Cause 3 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Justcause3 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'justcause3'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Just Cause 3"; - - /** - * Query port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/Protocols/Killingfloor.php b/GameQ/Protocols/Killingfloor.php deleted file mode 100644 index 9cc1964..0000000 --- a/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/GameQ/Protocols/Killingfloor2.php b/GameQ/Protocols/Killingfloor2.php deleted file mode 100644 index a134f25..0000000 --- a/GameQ/Protocols/Killingfloor2.php +++ /dev/null @@ -1,51 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Killing floor - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Killingfloor2 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'killing floor 2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Killing Floor 2"; - - /** - * query_port = client_port + 19238 - * 27015 = 7777 + 19238 - * - * @type int - */ - protected $port_diff = 19238; -} diff --git a/GameQ/Protocols/L4d.php b/GameQ/Protocols/L4d.php deleted file mode 100644 index 596452a..0000000 --- a/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/GameQ/Protocols/L4d2.php b/GameQ/Protocols/L4d2.php deleted file mode 100644 index 475514c..0000000 --- a/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/GameQ/Protocols/Lhmp.php b/GameQ/Protocols/Lhmp.php deleted file mode 100644 index 3d5e81f..0000000 --- a/GameQ/Protocols/Lhmp.php +++ /dev/null @@ -1,214 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Lost Heaven Protocol class - * - * Reference: http://lh-mp.eu/wiki/index.php/Query_System - * - * @author Austin Bischoff - */ -class Lhmp 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 => "LHMPo", - self::PACKET_PLAYERS => "LHMPp", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "LHMPo" => "processDetails", - "LHMPp" => "processPlayers", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'lhmp'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'lhmp'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Lost Heaven"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'gamemode', - 'hostname' => 'servername', - 'mapname' => 'mapname', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - ], - ]; - - /** - * 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 '{$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 Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processDetails(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - $result->add('protocol', $buffer->readString()); - $result->add('password', $buffer->readString()); - $result->add('numplayers', $buffer->readInt16()); - $result->add('maxplayers', $buffer->readInt16()); - $result->add('servername', utf8_encode($buffer->readPascalString())); - $result->add('gamemode', $buffer->readPascalString()); - $result->add('website', utf8_encode($buffer->readPascalString())); - $result->add('mapname', utf8_encode($buffer->readPascalString())); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the player data into a usable format - * - * @param Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Get the number of players - $result->add('numplayers', $buffer->readInt16()); - - // Parse players - while ($buffer->getLength()) { - // Player id - if (($id = $buffer->readInt16()) !== 0) { - // Add the results - $result->addPlayer('id', $id); - $result->addPlayer('name', utf8_encode($buffer->readPascalString())); - } - } - - unset($buffer, $id); - - return $result->fetch(); - } -} diff --git a/GameQ/Protocols/Minecraft.php b/GameQ/Protocols/Minecraft.php deleted file mode 100644 index a895cb8..0000000 --- a/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/GameQ/Protocols/Minecraftpe.php b/GameQ/Protocols/Minecraftpe.php deleted file mode 100644 index 21d1186..0000000 --- a/GameQ/Protocols/Minecraftpe.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Minecraft PE (BE) Protocol Class - * - * @package GameQ\Protocols - * - * @author Austin Bischoff - */ -class Minecraftpe extends Minecraft -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'minecraftpe'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "MinecraftPE"; -} diff --git a/GameQ/Protocols/Mohaa.php b/GameQ/Protocols/Mohaa.php deleted file mode 100644 index 66ddd7e..0000000 --- a/GameQ/Protocols/Mohaa.php +++ /dev/null @@ -1,79 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/Protocols/Mordhau.php b/GameQ/Protocols/Mordhau.php deleted file mode 100644 index fa305ce..0000000 --- a/GameQ/Protocols/Mordhau.php +++ /dev/null @@ -1,53 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class MORDHAU - * - * @package GameQ\Protocols - * @author Wilson Jesus <> - */ -class Mordhau extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'mordhau'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "MORDHAU"; - - #protected $port = 7777; - - /** - * query_port = client_port + 19238 - * 27015 = 7777 + 19238 - * - * @type int - */ - #protected $port_diff = 19238; -} diff --git a/GameQ/Protocols/Mta.php b/GameQ/Protocols/Mta.php deleted file mode 100644 index b95dc4c..0000000 --- a/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/GameQ/Protocols/Mumble.php b/GameQ/Protocols/Mumble.php deleted file mode 100644 index 299389c..0000000 --- a/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/GameQ/Protocols/Ns2.php b/GameQ/Protocols/Ns2.php deleted file mode 100644 index 4c32392..0000000 --- a/GameQ/Protocols/Ns2.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Ns2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Ns2 extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ns2'; - - /** - * 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/GameQ/Protocols/Pixark.php b/GameQ/Protocols/Pixark.php deleted file mode 100644 index 2e67af0..0000000 --- a/GameQ/Protocols/Pixark.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class PixARK - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Pixark extends Arkse -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'pixark'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "PixARK"; -} diff --git a/GameQ/Protocols/Projectrealitybf2.php b/GameQ/Protocols/Projectrealitybf2.php deleted file mode 100644 index 6f4b5ce..0000000 --- a/GameQ/Protocols/Projectrealitybf2.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Projectrealitybf2 - * - * Based off of BF2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Projectrealitybf2 extends Bf2 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'projectrealitybf2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Project Reality: Battlefield 2"; -} diff --git a/GameQ/Protocols/Quake2.php b/GameQ/Protocols/Quake2.php deleted file mode 100644 index f0366c2..0000000 --- a/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/GameQ/Protocols/Quake3.php b/GameQ/Protocols/Quake3.php deleted file mode 100644 index 6269b92..0000000 --- a/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/GameQ/Protocols/Quakelive.php b/GameQ/Protocols/Quakelive.php deleted file mode 100644 index d5df350..0000000 --- a/GameQ/Protocols/Quakelive.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Quake Live - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Quakelive extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'quakelive'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Quake Live"; -} diff --git a/GameQ/Protocols/Redorchestra2.php b/GameQ/Protocols/Redorchestra2.php deleted file mode 100644 index 6733016..0000000 --- a/GameQ/Protocols/Redorchestra2.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Redorchestra2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Redorchestra2 extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'redorchestra2'; - - /** - * 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/GameQ/Protocols/Redorchestraostfront.php b/GameQ/Protocols/Redorchestraostfront.php deleted file mode 100644 index 4c83b7e..0000000 --- a/GameQ/Protocols/Redorchestraostfront.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Red Orchestra: Ostfront 41-45 Class - * - * @package GameQ\Protocols - * @author naXe - * @author Austin Bischoff - */ -class Redorchestraostfront extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'redorchestraostfront'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Red Orchestra: Ostfront 41-45"; -} diff --git a/GameQ/Protocols/Risingstorm2.php b/GameQ/Protocols/Risingstorm2.php deleted file mode 100644 index ddb82a5..0000000 --- a/GameQ/Protocols/Risingstorm2.php +++ /dev/null @@ -1,55 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Rising Storm 2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Risingstorm2 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'rising storm 2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Rising Storm 2"; - - /** - * Query port is always 27015 - * - * @param int $clientPort - * - * @return int - */ - public function findQueryPort($clientPort) - { - return 27015; - } -} diff --git a/GameQ/Protocols/Rust.php b/GameQ/Protocols/Rust.php deleted file mode 100644 index 81b0cce..0000000 --- a/GameQ/Protocols/Rust.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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"; -} diff --git a/GameQ/Protocols/Samp.php b/GameQ/Protocols/Samp.php deleted file mode 100644 index cf01f83..0000000 --- a/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/GameQ/Protocols/Serioussam.php b/GameQ/Protocols/Serioussam.php deleted file mode 100644 index 32e0a10..0000000 --- a/GameQ/Protocols/Serioussam.php +++ /dev/null @@ -1,75 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Serious Sam Protocol Class - * - * @author ZCaliptium - */ -class SeriousSam extends Gamespy -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'serioussam'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Serious Sam"; - - /** - * 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', - 'mod' => 'activemod', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'player', - 'ping' => 'ping', - 'score' => 'frags', - ], - ]; -} diff --git a/GameQ/Protocols/Sevendaystodie.php b/GameQ/Protocols/Sevendaystodie.php deleted file mode 100644 index a5ddbf2..0000000 --- a/GameQ/Protocols/Sevendaystodie.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class 7 Days to Die - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Sevendaystodie extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'sevendaystodie'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "7 Days to Die"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/Protocols/Ship.php b/GameQ/Protocols/Ship.php deleted file mode 100644 index 9c3bee9..0000000 --- a/GameQ/Protocols/Ship.php +++ /dev/null @@ -1,95 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Class Ship - * - * @package GameQ\Protocols - * - * @author Nikolay Ipanyuk - * @author Austin Bischoff - */ -class Ship extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ship'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "The Ship"; - - /** - * Specific player parse for The Ship - * - * Player response has unknown data after the last real player - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // We need to read the number of players because this response has other data at the end usually - $num_players = $buffer->readInt8(); - - // Player count - $result->add('num_players', $num_players); - - // No players, no work - if ($num_players == 0) { - return $result->fetch(); - } - - // Players list - for ($player = 0; $player < $num_players; $player++) { - $result->addPlayer('id', $buffer->readInt8()); - $result->addPlayer('name', $buffer->readString()); - $result->addPlayer('score', $buffer->readInt32Signed()); - $result->addPlayer('time', $buffer->readFloat32()); - } - - // Extra data - if ($buffer->getLength() > 0) { - for ($player = 0; $player < $num_players; $player++) { - $result->addPlayer('deaths', $buffer->readInt32Signed()); - $result->addPlayer('money', $buffer->readInt32Signed()); - } - } - - unset($buffer); - - return $result->fetch(); - } -} diff --git a/GameQ/Protocols/Sof2.php b/GameQ/Protocols/Sof2.php deleted file mode 100644 index 96a4db2..0000000 --- a/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/GameQ/Protocols/Soldat.php b/GameQ/Protocols/Soldat.php deleted file mode 100644 index a9dbbc4..0000000 --- a/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/GameQ/Protocols/Source.php b/GameQ/Protocols/Source.php deleted file mode 100644 index 9e4cb5d..0000000 --- a/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", - 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/GameQ/Protocols/Spaceengineers.php b/GameQ/Protocols/Spaceengineers.php deleted file mode 100644 index ddf8567..0000000 --- a/GameQ/Protocols/Spaceengineers.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Space Engineers Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Spaceengineers extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'spaceengineers'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Space Engineers"; -} diff --git a/GameQ/Protocols/Squad.php b/GameQ/Protocols/Squad.php deleted file mode 100644 index 3c02188..0000000 --- a/GameQ/Protocols/Squad.php +++ /dev/null @@ -1,53 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Squad - * - * Port reference: http://forums.joinsquad.com/topic/9559-query-ports/ - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Squad extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'squad'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Squad"; - - /** - * query_port = client_port + 19378 - * 27165 = 7787 + 19378 - * - * @type int - */ - protected $port_diff = 19378; -} diff --git a/GameQ/Protocols/Starmade.php b/GameQ/Protocols/Starmade.php deleted file mode 100644 index 09a033f..0000000 --- a/GameQ/Protocols/Starmade.php +++ /dev/null @@ -1,226 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * StarMade Protocol Class - * - * StarMade server query protocol class - * - * Credit to Robin Promesberger for providing Java based querying as a roadmap - * - * @author Austin Bischoff - */ -class Starmade extends Protocol -{ - - /** - * Array of packets we want to query. - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\x00\x00\x00\x09\x2a\xff\xff\x01\x6f\x00\x00\x00\x00", - ]; - - /** - * 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 = 'starmade'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'starmade'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "StarMade"; - - /** - * 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', - 'hostname' => 'hostname', - 'maxplayers' => 'max_players', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - ]; - - /** - * Process the response for the StarMade server - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // Implode the packets, not sure if there is any split logic for multiple packets - $buffer = new Buffer(implode('', $this->packets_response), Buffer::NUMBER_TYPE_BIGENDIAN); - - // Get the passed length in the data side of the packet - $buffer->readInt32Signed(); - - // Read off the timestamp (in milliseconds) - $buffer->readInt64(); - - // Burn the check id == 42 - $buffer->readInt8(); - - // Read packetId, unused - $buffer->readInt16Signed(); - - // Read commandId, unused - $buffer->readInt8Signed(); - - // Read type, unused - $buffer->readInt8Signed(); - - $parsed = $this->parseServerParameters($buffer); - - // Set the result to a new result instance - $result = new Result(); - - // Best guess info version is the type of response to expect. As of this commit the version is "2". - $result->add('info_version', $parsed[0]); - $result->add('version', $parsed[1]); - $result->add('hostname', $parsed[2]); - $result->add('game_descr', $parsed[3]); - $result->add('start_time', $parsed[4]); - $result->add('num_players', $parsed[5]); - $result->add('max_players', $parsed[6]); - $result->add('dedicated', 1); // All servers are dedicated as far as I can tell - $result->add('password', 0); // Unsure if you can password servers, cant read that value - //$result->add('map', 'Unknown'); - - unset($parsed); - - return $result->fetch(); - } - - /** - * Parse the server response parameters - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * - * @param \GameQ\Buffer $buffer - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - protected function parseServerParameters(Buffer &$buffer) - { - - // Init the parsed data array - $parsed = []; - - // Read the number of parameters to parse - $parameterSize = $buffer->readInt32Signed(); - - // Iterate over the parameter size - for ($i = 0; $i < $parameterSize; $i++) { - // Read the type of return this is - $dataType = $buffer->readInt8Signed(); - - switch ($dataType) { - // 32-bit int - case 1: - $parsed[$i] = $buffer->readInt32Signed(); - break; - - // 64-bit int - case 2: - $parsed[$i] = $buffer->readInt64(); - break; - - // Float - case 3: - $parsed[$i] = $buffer->readFloat32(); - break; - - // String - case 4: - // The first 2 bytes are the string length - $strLength = $buffer->readInt16Signed(); - - // Read the above length from the buffer - $parsed[$i] = $buffer->read($strLength); - - unset($strLength); - break; - - // Boolean - case 5: - $parsed[$i] = (bool)$buffer->readInt8Signed(); - break; - - // 8-bit int - case 6: - $parsed[$i] = $buffer->readInt8Signed(); - break; - - // 16-bit int - case 7: - $parsed[$i] = $buffer->readInt16Signed(); - break; - - // Array - case 8: - // Not implemented - throw new Exception("StarMade array parsing is not implemented!"); - } - } - - return $parsed; - } -} diff --git a/GameQ/Protocols/Swat4.php b/GameQ/Protocols/Swat4.php deleted file mode 100644 index 7b8e120..0000000 --- a/GameQ/Protocols/Swat4.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Swat4 - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Swat4 extends Gamespy2 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'swat4'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "SWAT 4"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/Protocols/Teamspeak2.php b/GameQ/Protocols/Teamspeak2.php deleted file mode 100644 index df0d59a..0000000 --- a/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/GameQ/Protocols/Teamspeak3.php b/GameQ/Protocols/Teamspeak3.php deleted file mode 100644 index c66f6a4..0000000 --- a/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/GameQ/Protocols/Teeworlds.php b/GameQ/Protocols/Teeworlds.php deleted file mode 100644 index 1bdaa47..0000000 --- a/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/GameQ/Protocols/Terraria.php b/GameQ/Protocols/Terraria.php deleted file mode 100644 index d9455ef..0000000 --- a/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/GameQ/Protocols/Tf2.php b/GameQ/Protocols/Tf2.php deleted file mode 100644 index e08411b..0000000 --- a/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/GameQ/Protocols/Theforrest.php b/GameQ/Protocols/Theforrest.php deleted file mode 100644 index 975c3f6..0000000 --- a/GameQ/Protocols/Theforrest.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Theforrest - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Theforrest extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'theforrest'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "The Forrest"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/Protocols/Tibia.php b/GameQ/Protocols/Tibia.php deleted file mode 100644 index 8702bfa..0000000 --- a/GameQ/Protocols/Tibia.php +++ /dev/null @@ -1,142 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Tibia Protocol Class - * - * Tibia server query protocol class - * - * Credit to Ahmad Fatoum for providing Perl based querying as a roadmap - * - * @author Yive - * @author Austin Bischoff - */ -class Tibia extends Protocol -{ - - /** - * Array of packets we want to query. - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\x06\x00\xFF\xFF\x69\x6E\x66\x6F", - ]; - - /** - * 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 = 'tibia'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'tibia'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Tibia"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "otserv://%s/%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'server', - 'hostname' => 'servername', - 'motd' => 'motd', - 'maxplayers' => 'players_max', - 'numplayers' => 'players_online', - 'map' => 'map_name', - ], - ]; - - /** - * Process the response for the Tibia server - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - // Merge the response packets - $xmlString = implode('', $this->packets_response); - - // Check to make sure this is will decode into a valid XML Document - if (($xmlDoc = @simplexml_load_string($xmlString)) === false) { - throw new Exception(__METHOD__ . " Unable to load XML string."); - } - - // Set the result to a new result instance - $result = new Result(); - - // All servers are dedicated as far as I can tell - $result->add('dedicated', 1); - - // Iterate over the info - foreach (['serverinfo', 'owner', 'map', 'npcs', 'monsters', 'players'] as $property) { - foreach ($xmlDoc->{$property}->attributes() as $key => $value) { - if (!in_array($property, ['serverinfo'])) { - $key = $property . '_' . $key; - } - - // Add the result - $result->add($key, (string)$value); - } - } - - $result->add("motd", (string)$xmlDoc->motd); - - unset($xmlDoc, $xmlDoc); - - return $result->fetch(); - } -} diff --git a/GameQ/Protocols/Tshock.php b/GameQ/Protocols/Tshock.php deleted file mode 100644 index 551a09e..0000000 --- a/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/GameQ/Protocols/Unreal2.php b/GameQ/Protocols/Unreal2.php deleted file mode 100644 index 0ef0675..0000000 --- a/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/GameQ/Protocols/Unturned.php b/GameQ/Protocols/Unturned.php deleted file mode 100644 index 4829b37..0000000 --- a/GameQ/Protocols/Unturned.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Unturned Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Unturned extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'unturned'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Unturned"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/Protocols/Urbanterror.php b/GameQ/Protocols/Urbanterror.php deleted file mode 100644 index 682f91e..0000000 --- a/GameQ/Protocols/Urbanterror.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Urban Terror Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Urbanterror extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'urbanterror'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Urban Terror"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "urt://%s:%d/"; -} diff --git a/GameQ/Protocols/Ut.php b/GameQ/Protocols/Ut.php deleted file mode 100644 index 75722ce..0000000 --- a/GameQ/Protocols/Ut.php +++ /dev/null @@ -1,73 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Unreal Tournament Protocol Class - * - * @author Austin Bischoff - */ -class Ut extends Gamespy -{ - - /** - * 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/GameQ/Protocols/Ut2004.php b/GameQ/Protocols/Ut2004.php deleted file mode 100644 index 953089f..0000000 --- a/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/GameQ/Protocols/Ut3.php b/GameQ/Protocols/Ut3.php deleted file mode 100644 index b55cc34..0000000 --- a/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/GameQ/Protocols/Ventrilo.php b/GameQ/Protocols/Ventrilo.php deleted file mode 100644 index 8a1e0e8..0000000 --- a/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 ($i = 1; $i <= $characterCount; $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; - } - } - - $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 ($i = 1; $i <= $characterCount; $i++) { - $chars[$i] -= ($table[$a2] + (($i - 1) % 72)) & 0xFF; - $a2 = ($a2 + $a1) & 0xFF; - $data .= chr($chars[$i]); - } - //@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/GameQ/Protocols/Warsow.php b/GameQ/Protocols/Warsow.php deleted file mode 100644 index f1d629a..0000000 --- a/GameQ/Protocols/Warsow.php +++ /dev/null @@ -1,96 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Warsow Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Warsow extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'warsow'; - - /** - * 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 function processPlayers(Buffer $buffer) - { - // 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 space - $playerInfo->skip(1); - - // Add team - $result->addPlayer('team', $playerInfo->read()); - - // Clear - unset($playerInfo); - } - - // Clear - unset($buffer); - - return $result->fetch(); - } -} diff --git a/GameQ/Protocols/Won.php b/GameQ/Protocols/Won.php deleted file mode 100644 index bef0984..0000000 --- a/GameQ/Protocols/Won.php +++ /dev/null @@ -1,66 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * World Opponent Network (WON) class - * - * Pre-cursor to the A2S (source) protocol system - * - * @author Nikolay Ipanyuk - * @author Austin Bischoff - * - * @package GameQ\Protocols - */ -class Won extends Source -{ - - /** - * 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 => "\xFF\xFF\xFF\xFFdetails\x00", - self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFFplayers", - self::PACKET_RULES => "\xFF\xFF\xFF\xFFrules", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'won'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'won'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "World Opponent Network"; -} diff --git a/GameQ/Protocols/Wurm.php b/GameQ/Protocols/Wurm.php deleted file mode 100644 index c593652..0000000 --- a/GameQ/Protocols/Wurm.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Wurm Unlimited Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Wurm extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'wurm'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Wurm Unlimited"; -} diff --git a/GameQ/Query/Core.php b/GameQ/Query/Core.php deleted file mode 100644 index 5eb08ad..0000000 --- a/GameQ/Query/Core.php +++ /dev/null @@ -1,164 +0,0 @@ -. - */ - -namespace GameQ\Query; - -/** - * Core for the query mechanisms - * - * @author Austin Bischoff - */ -abstract class Core -{ - - /** - * The socket used by this resource - * - * @type null|resource - */ - public $socket = null; - - /** - * The transport type (udp, tcp, etc...) - * See http://php.net/manual/en/transports.php for the supported list - * - * @type string - */ - protected $transport = null; - - /** - * Connection IP address - * - * @type string - */ - protected $ip = null; - - /** - * Connection port - * - * @type int - */ - protected $port = null; - - /** - * The time in seconds to wait before timing out while connecting to the socket - * - * @type int - */ - protected $timeout = 3; // Seconds - - /** - * Socket is blocking? - * - * @type bool - */ - protected $blocking = false; - - /** - * Called when the class is cloned - */ - public function __clone() - { - - // Reset the properties for this class when cloned - $this->reset(); - } - - /** - * Set the connection information for the socket - * - * @param string $transport - * @param string $ip - * @param int $port - * @param int $timeout seconds - * @param bool $blocking - */ - public function set($transport, $ip, $port, $timeout = 3, $blocking = false) - { - - $this->transport = $transport; - - $this->ip = $ip; - - $this->port = $port; - - $this->timeout = $timeout; - - $this->blocking = $blocking; - } - - /** - * Reset this instance's properties - */ - public function reset() - { - - $this->transport = null; - - $this->ip = null; - - $this->port = null; - - $this->timeout = 3; - - $this->blocking = false; - } - - /** - * Create a new socket - * - * @return void - */ - abstract protected function create(); - - /** - * Get the socket - * - * @return mixed - */ - abstract public function get(); - - /** - * Write data to the socket - * - * @param string $data - * - * @return int The number of bytes written - */ - abstract public function write($data); - - /** - * Close the socket - * - * @return void - */ - abstract public function close(); - - /** - * Read the responses from the socket(s) - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param array $sockets - * @param int $timeout - * @param int $stream_timeout - * - * @return array - */ - abstract public function getResponses(array $sockets, $timeout, $stream_timeout); -} diff --git a/GameQ/Query/Native.php b/GameQ/Query/Native.php deleted file mode 100644 index b078c9c..0000000 --- a/GameQ/Query/Native.php +++ /dev/null @@ -1,221 +0,0 @@ -. - */ - -namespace GameQ\Query; - -use GameQ\Exception\Query as Exception; - -/** - * Native way of querying servers - * - * @author Austin Bischoff - */ -class Native extends Core -{ - /** - * Get the current socket or create one and return - * - * @return resource|null - * @throws \GameQ\Exception\Query - */ - public function get() - { - - // No socket for this server, make one - if (is_null($this->socket)) { - $this->create(); - } - - return $this->socket; - } - - /** - * Write data to the socket - * - * @param string $data - * - * @return int The number of bytes written - * @throws \GameQ\Exception\Query - */ - public function write($data) - { - - try { - // No socket for this server, make one - if (is_null($this->socket)) { - $this->create(); - } - - // Send the packet - return fwrite($this->socket, $data); - } catch (\Exception $e) { - throw new Exception($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * Close the current socket - */ - public function close() - { - - if ($this->socket) { - fclose($this->socket); - $this->socket = null; - } - } - - /** - * Create a new socket for this query - * - * @throws \GameQ\Exception\Query - */ - protected function create() - { - - // Create the remote address - $remote_addr = sprintf("%s://%s:%d", $this->transport, $this->ip, $this->port); - - // Create context - $context = stream_context_create([ - 'socket' => [ - 'bindto' => '0:0', // Bind to any available IP and OS decided port - ], - ]); - - // Define these first - $errno = null; - $errstr = null; - - // Create the socket - if (($this->socket = - @stream_socket_client($remote_addr, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context)) - !== false - ) { - // Set the read timeout on the streams - stream_set_timeout($this->socket, $this->timeout); - - // Set blocking mode - stream_set_blocking($this->socket, $this->blocking); - } else { - // Reset socket - $this->socket = null; - - // Something bad happened, throw query exception - throw new Exception( - __METHOD__ . " - Error creating socket to server {$this->ip}:{$this->port}. Error: " . $errstr, - $errno - ); - } - } - - /** - * Pull the responses out of the stream - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * - * @param array $sockets - * @param int $timeout - * @param int $stream_timeout - * - * @return array Raw responses - */ - public function getResponses(array $sockets, $timeout, $stream_timeout) - { - - // Set the loop to active - $loop_active = true; - - // Will hold the responses read from the sockets - $responses = []; - - // To store the sockets - $sockets_tmp = []; - - // Loop and pull out all the actual sockets we need to listen on - foreach ($sockets as $socket_id => $socket_data) { - // Get the socket - /* @var $socket \GameQ\Query\Core */ - $socket = $socket_data['socket']; - - // Append the actual socket we are listening to - $sockets_tmp[$socket_id] = $socket->get(); - - unset($socket); - } - - // Init some variables - $read = $sockets_tmp; - $write = null; - $except = null; - - // Check to see if $read is empty, if so stream_select() will throw a warning - if (empty($read)) { - return $responses; - } - - // This is when it should stop - $time_stop = microtime(true) + $timeout; - - // Let's loop until we break something. - while ($loop_active && microtime(true) < $time_stop) { - // Check to make sure $read is not empty, if so we are done - if (empty($read)) { - break; - } - - // Now lets listen for some streams, but do not cross the streams! - $streams = stream_select($read, $write, $except, 0, $stream_timeout); - - // We had error or no streams left, kill the loop - if ($streams === false || ($streams <= 0)) { - break; - } - - // Loop the sockets that received data back - foreach ($read as $socket) { - /* @var $socket resource */ - - // See if we have a response - if (($response = fread($socket, 8192)) === false) { - continue; // No response yet so lets continue. - } - - // Check to see if the response is empty, if so we are done with this server - if (strlen($response) == 0) { - // Remove this server from any future read loops - unset($sockets_tmp[(int)$socket]); - continue; - } - - // Add the response we got back - $responses[(int)$socket][] = $response; - } - - // Because stream_select modifies read we need to reset it each time to the original array of sockets - $read = $sockets_tmp; - } - - // Free up some memory - unset($streams, $read, $write, $except, $sockets_tmp, $time_stop, $response); - - // Return all of the responses, may be empty if something went wrong - return $responses; - } -} diff --git a/GameQ/Result.php b/GameQ/Result.php deleted file mode 100644 index 7023f17..0000000 --- a/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; - } -} diff --git a/GameQ/Server.php b/GameQ/Server.php deleted file mode 100644 index dff8f77..0000000 --- a/GameQ/Server.php +++ /dev/null @@ -1,380 +0,0 @@ -. - */ - -namespace GameQ; - -use GameQ\Exception\Server as Exception; - -/** - * Server class to represent each server entity - * - * @author Austin Bischoff - */ -class Server -{ - - /* - * Server array keys - */ - const SERVER_TYPE = 'type'; - - const SERVER_HOST = 'host'; - - const SERVER_ID = 'id'; - - const SERVER_OPTIONS = 'options'; - - /* - * Server options keys - */ - - /* - * Use this option when the query_port and client connect ports are different - */ - const SERVER_OPTIONS_QUERY_PORT = 'query_port'; - - /** - * The protocol class for this server - * - * @type \GameQ\Protocol - */ - protected $protocol = null; - - /** - * Id of this server - * - * @type string - */ - public $id = null; - - /** - * IP Address of this server - * - * @type string - */ - public $ip = null; - - /** - * The server's client port (connect port) - * - * @type int - */ - public $port_client = null; - - /** - * The server's query port - * - * @type int - */ - public $port_query = null; - - /** - * Holds other server specific options - * - * @type array - */ - protected $options = []; - - /** - * Holds the sockets already open for this server - * - * @type array - */ - protected $sockets = []; - - /** - * Construct the class with the passed options - * - * @param array $server_info - * - * @throws \GameQ\Exception\Server - */ - public function __construct(array $server_info = []) - { - - // Check for server type - if (!array_key_exists(self::SERVER_TYPE, $server_info) || empty($server_info[self::SERVER_TYPE])) { - throw new Exception("Missing server info key '" . self::SERVER_TYPE . "'!"); - } - - // Check for server host - if (!array_key_exists(self::SERVER_HOST, $server_info) || empty($server_info[self::SERVER_HOST])) { - throw new Exception("Missing server info key '" . self::SERVER_HOST . "'!"); - } - - // IP address and port check - $this->checkAndSetIpPort($server_info[self::SERVER_HOST]); - - // Check for server id - if (array_key_exists(self::SERVER_ID, $server_info) && !empty($server_info[self::SERVER_ID])) { - // Set the server id - $this->id = $server_info[self::SERVER_ID]; - } else { - // Make an id so each server has an id when returned - $this->id = sprintf('%s:%d', $this->ip, $this->port_client); - } - - // Check and set server options - if (array_key_exists(self::SERVER_OPTIONS, $server_info)) { - // Set the options - $this->options = $server_info[self::SERVER_OPTIONS]; - } - - try { - // Make the protocol class for this type - $class = new \ReflectionClass( - sprintf('GameQ\\Protocols\\%s', ucfirst(strtolower($server_info[self::SERVER_TYPE]))) - ); - - $this->protocol = $class->newInstanceArgs([$this->options]); - } catch (\ReflectionException $e) { - throw new Exception("Unable to locate Protocols class for '{$server_info[self::SERVER_TYPE]}'!"); - } - - // Check and set any server options - $this->checkAndSetServerOptions(); - - unset($server_info, $class); - } - - /** - * Check and set the ip address for this server - * - * @param $ip_address - * - * @throws \GameQ\Exception\Server - */ - protected function checkAndSetIpPort($ip_address) - { - - // Test for IPv6 - if (substr_count($ip_address, ':') > 1) { - // See if we have a port, input should be in the format [::1]:27015 or similar - if (strstr($ip_address, ']:')) { - // Explode to get port - $server_addr = explode(':', $ip_address); - - // Port is the last item in the array, remove it and save - $this->port_client = (int)array_pop($server_addr); - - // The rest is the address, recombine - $this->ip = implode(':', $server_addr); - - unset($server_addr); - } else { - // Just the IPv6 address, no port defined, fail - throw new Exception( - "The host address '{$ip_address}' is missing the port. All " - . "servers must have a port defined!" - ); - } - - // Now let's validate the IPv6 value sent, remove the square brackets ([]) first - if (!filter_var(trim($this->ip, '[]'), FILTER_VALIDATE_IP, ['flags' => FILTER_FLAG_IPV6,])) { - throw new Exception("The IPv6 address '{$this->ip}' is invalid."); - } - } else { - // We have IPv4 with a port defined - if (strstr($ip_address, ':')) { - list($this->ip, $this->port_client) = explode(':', $ip_address); - - // Type case the port - $this->port_client = (int)$this->port_client; - } else { - // No port, fail - throw new Exception( - "The host address '{$ip_address}' is missing the port. All " - . "servers must have a port defined!" - ); - } - - // 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) - ) { - // 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."); - } - } - } - - /** - * Check and set any server specific options - */ - protected function checkAndSetServerOptions() - { - - // Specific query port defined - if (array_key_exists(self::SERVER_OPTIONS_QUERY_PORT, $this->options)) { - $this->port_query = (int)$this->options[self::SERVER_OPTIONS_QUERY_PORT]; - } else { - // Do math based on the protocol class - $this->port_query = $this->protocol->findQueryPort($this->port_client); - } - } - - /** - * Set an option for this server - * - * @param $key - * @param $value - * - * @return $this - */ - public function setOption($key, $value) - { - - $this->options[$key] = $value; - - return $this; // Make chainable - } - - /** - * Return set option value - * - * @param mixed $key - * - * @return mixed - */ - public function getOption($key) - { - - return (array_key_exists($key, $this->options)) ? $this->options[$key] : null; - } - - /** - * Get the ID for this server - * - * @return string - */ - public function id() - { - - return $this->id; - } - - /** - * Get the IP address for this server - * - * @return string - */ - public function ip() - { - - return $this->ip; - } - - /** - * Get the client port for this server - * - * @return int - */ - public function portClient() - { - - return $this->port_client; - } - - /** - * Get the query port for this server - * - * @return int - */ - public function portQuery() - { - - return $this->port_query; - } - - /** - * Return the protocol class for this server - * - * @return \GameQ\Protocol - */ - public function protocol() - { - - return $this->protocol; - } - - /** - * Get the join link for this server - * - * @return string - */ - public function getJoinLink() - { - - return sprintf($this->protocol->joinLink(), $this->ip, $this->portClient()); - } - - /* - * Socket holding - */ - - /** - * Add a socket for this server to be reused - * - * @codeCoverageIgnore - * - * @param \GameQ\Query\Core $socket - */ - public function socketAdd(Query\Core $socket) - { - - $this->sockets[] = $socket; - } - - /** - * Get a socket from the list to reuse, if any are available - * - * @codeCoverageIgnore - * - * @return \GameQ\Query\Core|null - */ - public function socketGet() - { - - $socket = null; - - if (count($this->sockets) > 0) { - $socket = array_pop($this->sockets); - } - - return $socket; - } - - /** - * Clear any sockets still listed and attempt to close them - * - * @codeCoverageIgnore - */ - public function socketCleanse() - { - - // Close all of the sockets available - foreach ($this->sockets as $socket) { - /* @var $socket \GameQ\Query\Core */ - $socket->close(); - } - - // Reset the sockets list - $this->sockets = []; - } -} diff --git a/GameQ/composer.json b/GameQ/composer.json deleted file mode 100644 index f05819b..0000000 --- a/GameQ/composer.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "name": "austinb/gameq", - "description": "GameQ Gameserver Library", - "keywords": [ - "gameq", - "serverstatus" - ], - "version": "v3.0.15", - "license": "LGPL-3.0+", - "authors": [ - { - "name": "Austin Bischoff", - "email": "austin.bischoff@gmail.com", - "role": "Packagist/Composer Maintainer, Developer", - "homepage": "https://github.com/Austinb" - }, - { - "name": "Christoph Kretzschmar", - "email": "blackskyliner@googlemail.com", - "role": "Developer", - "homepage": "https://github.com/Blackskyliner" - }, - { - "name": "Marcel Bößendörfer", - "email": "m.boessendoerfer@marbis.net", - "role": "Developer", - "homepage": "https://github.com/nitrado" - }, - { - "name": "Alexander Hambalgo", - "role": "Developer", - "homepage": "http://balgo.users.sourceforge.net/" - }, - { - "name": "Holger", - "role": "Developer", - "homepage": "http://icet33.users.sourceforge.net/" - }, - { - "name": "Sebastian Weidenbach", - "role": "Developer", - "homepage": "http://sebastianwe.users.sourceforge.net/" - } - ], - "support": { - "source": "https://github.com/Austinb/GameQ/v3", - "issues": "https://github.com/Austinb/GameQ/issues", - "wiki": "https://github.com/Austinb/GameQ/wiki" - }, - "require": { - "php": ">=5.6.40", - "ext-bz2": "*", - "ext-xml": "*" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8 || ^6.0 || ^7.0", - "phpunit/php-invoker": "*", - "phpmd/phpmd": "@stable", - "squizlabs/php_codesniffer": "3.*@stable", - "corneltek/getoptionkit": "~2", - "php-coveralls/php-coveralls": "^1.1 || ^2.1" - }, - "autoload": { - "psr-4": { - "GameQ\\": "src/GameQ/" - } - }, - "autoload-dev": { - "psr-4": { - "GameQ\\Tests\\": "tests" - } - }, - "scripts": { - "test": [ - "@test-phpcs", - "@test-phpmd", - "@test-php" - ], - "test-php": "vendor/bin/phpunit", - "test-phpcs": "vendor/bin/phpcs src tests --extensions=php --ignore=bootstrap --report=checkstyle --report-file=build/logs/checkstyle.xml --standard=build/config/phpcs.xml -v", - "test-phpmd": "vendor/bin/phpmd src,tests xml build/config/phpmd.xml" - }, - "scripts-descriptions": { - "test": "Run all tests!", - "test-php": "Run phpunit tests", - "test-phpcs": "Run PHP Code Style checks", - "test-phpmd": "Run PHP Mess Detector checks" - } -} diff --git a/GameQ/examples/list.php b/GameQ/examples/list.php deleted file mode 100644 index 6d143cf..0000000 --- a/GameQ/examples/list.php +++ /dev/null @@ -1,131 +0,0 @@ -read())) { - if (!is_file($protocols_path . $entry)) { - continue; - } - - // Lets get some info on the class - $reflection = new ReflectionClass('\\GameQ\\Protocols\\' . pathinfo($entry, PATHINFO_FILENAME)); - - // Check to make sure we can actually load the class - if (!$reflection->IsInstantiable()) { - continue; - } - - // Load up the class so we can get info - $class = $reflection->newInstance(); - - // Add it to the list - $protocols[ $class->name() ] = [ - 'name' => $class->nameLong(), - 'state' => $class->state(), - ]; - - // Unset the class - unset($class); -} - -// Close the directory -unset($dir); - -ksort($protocols); - -?> - - - - GameQ v3 - Supported Games - - - - -

GameQ v3 - Supported Games ()

- - - - - - - - - - $info) { - - - switch ($info['state']) { - case 1: - $state = 'Testing'; - break; - - case 2: - $state = 'Beta'; - break; - - case 3: - $state = 'Stable'; - break; - - case 4: - $state = 'Deprecated'; - break; - } - - $cls = empty($cls) ? ' class="uneven"' : ''; - printf("\n", $cls, - htmlentities($info['name']), - $gameq, - $state - ); - } - ?> - -
Game NameGameQ IdentifierState
%s%s%s
- - diff --git a/GameQ/expansion.php b/GameQ/expansion.php deleted file mode 100644 index e15eae2..0000000 --- a/GameQ/expansion.php +++ /dev/null @@ -1,171 +0,0 @@ -addServer([ - 'type' => 'dayz', - 'host' => '82.64.214.194:3201', - 'options' => [ - 'query_port' => 27021, - ], -]); - - -// 'type' => 'dayz', -// 'host' => '82.64.214.194:2303', -// 'options' => [ -// 'query_port' => 27023, -// ], - - - - -// Define the servers you wish you query -$GameQ = new \GameQ\GameQ(); // or //$GameQ = \GameQ\GameQ::factory(); - -$GameQ->setOption('timeout', 3); // 3 seconds -$results = $GameQ->process(); - -//print_r($results); - //echo "

// var dump

"; - //var_dump(json_decode($readjson, true)); -//echo "

// echo

"; -// echo $readjson
"; - //$data1 = json_decode("$readjson", true); -//echo "

//Print data1

" ; - //print_r($data1); -//echo "
"; - - -$data = json_decode($readjson); -// class -$name = $data->{'name'}; -$map = $data->{'map'}; -$password = $data->{'password'}; -$game = $data->{'raw'}->{'game'}; -$secure = $data->{'raw'}->{'secure'}; -$numplayers = $data->{'raw'}->{'numplayers'}; -$version = $data->{'raw'}->{'version'}; -$tags = $data->{'raw'}->{'tags'}; - -//$dedicated = $data->{'raw'}->{'rules'}->{'dedicated'}; -//$island = $data->{'raw'}->{'rules'}->{'island'}; - - -$connect = $data->{'connect'}; -$ping = $data->{'ping'}; -$time = "$tags[38]$tags[39]:$tags[41]$tags[42]"; -$battleye = substr($tags,0,8); -$hive = substr($tags,18,8); -$players = $data->{'players'}; - -//if(empty($players)) -// $players = "0"; -//if (empty($players)) { "0"; } -//$playersuser = substr($players,0,8); -//$players = $data->{'array_filter($players)'}; -//$player = $data->{'players'}; - -?> - - - - - Dayz ToX Server: <?php echo"${name}"; ?> - - - - - - - - - - - - - - - - - - - - - - - -
Server Name IP server Ping Player Info Joueurs Version
- -
- - - - - Player: - - - - - - - -
print_r ";print_r($players); - -?> -
- - - - - - - - diff --git a/GameQ/expansion_.php b/GameQ/expansion_.php deleted file mode 100644 index d2c3af9..0000000 --- a/GameQ/expansion_.php +++ /dev/null @@ -1,170 +0,0 @@ -addServer([ - 'type' => 'dayz', - 'host' => '82.64.214.194:3201', - 'options' => [ - 'query_port' => 27021, - ] -]); - - -// 'type' => 'dayz', -// 'host' => '82.64.214.194:2303', -// 'options' => [ -// 'query_port' => 27023, -// ], - - -// Define the servers you wish you query -#$GameQ = new \GameQ\GameQ(); // or //$GameQ = \GameQ\GameQ::factory(); -$GameQ->setOption('timeout', 3); // 3 seconds - -$results = $GameQ->process(); - -//print_r($results); - //echo "

// var dump

"; - //var_dump(json_decode($readjson, true)); -//echo "

// echo

"; -// echo $readjson
"; - //$data1 = json_decode("$readjson", true); -//echo "

//Print data1

" ; - //print_r($data1); -//echo "
"; - - -$data = json_decode($readjson); -// class -$name = $data->{'name'}; -$map = $data->{'map'}; -$password = $data->{'password'}; -$game = $data->{'raw'}->{'game'}; -$secure = $data->{'raw'}->{'secure'}; -$numplayers = $data->{'raw'}->{'numplayers'}; -$version = $data->{'raw'}->{'version'}; -$tags = $data->{'raw'}->{'tags'}; - -//$dedicated = $data->{'raw'}->{'rules'}->{'dedicated'}; -//$island = $data->{'raw'}->{'rules'}->{'island'}; - - -$connect = $data->{'connect'}; -$ping = $data->{'ping'}; -$time = "$tags[38]$tags[39]:$tags[41]$tags[42]"; -$battleye = substr($tags,0,8); -$hive = substr($tags,18,8); -$players = $data->{'players'}; - -//if(empty($players)) -// $players = "0"; -//if (empty($players)) { "0"; } -//$playersuser = substr($players,0,8); -//$players = $data->{'array_filter($players)'}; -//$player = $data->{'players'}; - -?> - - - - - Dayz ToX Server: <?php echo"${name}"; ?> - - - - - - - - - - - - - - - - - - - - - - - -
Server Name IP server Ping Player Info Joueurs Version
- -
- - - - - Player: - - - - - - - -
print_r ";print_r($players); - -?> -
- - - - - - - - diff --git a/GameQ/index.php b/GameQ/index.php deleted file mode 100644 index 2dccf42..0000000 --- a/GameQ/index.php +++ /dev/null @@ -1,152 +0,0 @@ -addServer([ - 'type' => 'dayz', - 'host' => '82.64.214.194:3222', - 'options' => [ - 'query_port' => 27022, - ], -]); - -// Define the servers you wish you query -//$GameQ = new \GameQ\GameQ(); // or //$GameQ = \GameQ\GameQ::factory(); - -$GameQ->setOption('timeout', 3); // 3 seconds -$results = $GameQ->process(); - -$data = json_decode($readjson); -// class -$name = $data->{'name'}; -$map = $data->{'map'}; -$password = $data->{'password'}; -$game = $data->{'raw'}->{'game'}; -$secure = $data->{'raw'}->{'secure'}; -$numplayers = $data->{'raw'}->{'numplayers'}; -$version = $data->{'raw'}->{'version'}; -$tags = $data->{'raw'}->{'tags'}; - -//$dedicated = $data->{'raw'}->{'rules'}->{'dedicated'}; -//$island = $data->{'raw'}->{'rules'}->{'island'}; - - -$connect = $data->{'connect'}; -$ping = $data->{'ping'}; -$time = "$tags[38]$tags[39]:$tags[41]$tags[42]"; -$battleye = substr($tags,0,8); -$hive = substr($tags,18,8); -$players = $data->{'players'}; - -//if(empty($players)) -// $players = "0"; -//if (empty($players)) { "0"; } -//$playersuser = substr($players,0,8); -//$players = $data->{'array_filter($players)'}; -//$player = $data->{'players'}; - -?> - - - - - Dayz ToX Server: <?php echo"${name}"; ?> - - - - - - -
- - - - - - - - - - - - - - - - -
Server Name IP server Ping Player Info Joueurs Version
- -
- - - - - - Player: - - - - - - -
print_r ";print_r($players); - -?> -
- - - - - - - - diff --git a/GameQ/src/GameQ/Autoloader.php b/GameQ/src/GameQ/Autoloader.php deleted file mode 100644 index 7c8eb41..0000000 --- a/GameQ/src/GameQ/Autoloader.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * - * - */ - -/** - * A simple PSR-4 spec auto loader to allow GameQ to function the same as if it were loaded via Composer - * - * To use this just include this file in your script and the GameQ namespace will be made available - * - * i.e. require_once('/path/to/src/GameQ/Autoloader.php'); - * - * See: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md - * - * @codeCoverageIgnore - */ -spl_autoload_register(function ($class) { - - // project-specific namespace prefix - $prefix = 'GameQ\\'; - - // base directory for the namespace prefix - $base_dir = __DIR__ . DIRECTORY_SEPARATOR; - - // does the class use the namespace prefix? - $len = strlen($prefix); - - if (strncmp($prefix, $class, $len) !== 0) { - // no, move to the next registered autoloader - return; - } - - // get the relative class name - $relative_class = substr($class, $len); - - // replace the namespace prefix with the base directory, replace namespace - // separators with directory separators in the relative class name, append - // with .php - $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php'; - - // if the file exists, require it - if (file_exists($file)) { - require $file; - } -}); diff --git a/GameQ/src/GameQ/Buffer.php b/GameQ/src/GameQ/Buffer.php deleted file mode 100644 index e9e1552..0000000 --- a/GameQ/src/GameQ/Buffer.php +++ /dev/null @@ -1,501 +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 $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 ($p = strpos($this->data, $delim, min($this->index, $this->length))) { - $pos[] = $p; - } - } - - // 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() - { - - // 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 = 'Lint'; - } - - // Unpack the number - $int = unpack($type, $this->read(4)); - - 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']; - } -} diff --git a/GameQ/src/GameQ/Exception/Protocol.php b/GameQ/src/GameQ/Exception/Protocol.php deleted file mode 100644 index 035fc6d..0000000 --- a/GameQ/src/GameQ/Exception/Protocol.php +++ /dev/null @@ -1,30 +0,0 @@ -. - * - * - */ - -namespace GameQ\Exception; - -/** - * Exception - * - * @author Austin Bischoff - */ -class Protocol extends \Exception -{ -} diff --git a/GameQ/src/GameQ/Exception/Query.php b/GameQ/src/GameQ/Exception/Query.php deleted file mode 100644 index cc69f39..0000000 --- a/GameQ/src/GameQ/Exception/Query.php +++ /dev/null @@ -1,30 +0,0 @@ -. - * - * - */ - -namespace GameQ\Exception; - -/** - * Exception - * - * @author Austin Bischoff - */ -class Query extends \Exception -{ -} diff --git a/GameQ/src/GameQ/Exception/Server.php b/GameQ/src/GameQ/Exception/Server.php deleted file mode 100644 index 4024551..0000000 --- a/GameQ/src/GameQ/Exception/Server.php +++ /dev/null @@ -1,30 +0,0 @@ -. - * - * - */ - -namespace GameQ\Exception; - -/** - * Exception - * - * @author Austin Bischoff - */ -class Server extends \Exception -{ -} diff --git a/GameQ/src/GameQ/Filters/Base.php b/GameQ/src/GameQ/Filters/Base.php deleted file mode 100644 index 1a3f4e5..0000000 --- a/GameQ/src/GameQ/Filters/Base.php +++ /dev/null @@ -1,58 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Abstract base class which all filters must inherit - * - * @author Austin Bischoff - */ -abstract class Base -{ - - /** - * Holds the options for this instance of the filter - * - * @type array - */ - protected $options = []; - - /** - * Construct - * - * @param array $options - */ - public function __construct(array $options = []) - { - - $this->options = $options; - } - - /** - * Apply the filter to the data - * - * @param array $result - * @param \GameQ\Server $server - * - * @return mixed - */ - abstract public function apply(array $result, Server $server); -} diff --git a/GameQ/src/GameQ/Filters/Normalize.php b/GameQ/src/GameQ/Filters/Normalize.php deleted file mode 100644 index 5771c92..0000000 --- a/GameQ/src/GameQ/Filters/Normalize.php +++ /dev/null @@ -1,133 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Class Normalize - * - * @package GameQ\Filters - */ -class Normalize extends Base -{ - - /** - * Holds the protocol specific normalize information - * - * @type array - */ - protected $normalize = []; - - /** - * Apply this filter - * - * @param array $result - * @param \GameQ\Server $server - * - * @return array - */ - public function apply(array $result, Server $server) - { - - // No result passed so just return - if (empty($result)) { - return $result; - } - - //$data = [ ]; - //$data['raw'][$server->id()] = $result; - - // Grab the normalize for this protocol for the specific server - $this->normalize = $server->protocol()->getNormalize(); - - // Do general information - $result = array_merge($result, $this->check('general', $result)); - - // Do player information - if (isset($result['players']) && count($result['players']) > 0) { - // Iterate - foreach ($result['players'] as $key => $player) { - $result['players'][$key] = array_merge($player, $this->check('player', $player)); - } - } else { - $result['players'] = []; - } - - // Do team information - if (isset($result['teams']) && count($result['teams']) > 0) { - // Iterate - foreach ($result['teams'] as $key => $team) { - $result['teams'][$key] = array_merge($team, $this->check('team', $team)); - } - } else { - $result['teams'] = []; - } - - //$data['filtered'][$server->id()] = $result; - /*file_put_contents( - sprintf('%s/../../../tests/Filters/Providers/Normalize/%s_1.json', __DIR__, $server->protocol()->getProtocol()), - json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) - );*/ - - // Return the normalized result - return $result; - } - - /** - * Check a section for normalization - * - * @param $section - * @param $data - * - * @return array - */ - protected function check($section, $data) - { - - // Normalized return array - $normalized = []; - - if (isset($this->normalize[$section]) && !empty($this->normalize[$section])) { - foreach ($this->normalize[$section] as $property => $raw) { - // Default the value for the new key as null - $value = null; - - if (is_array($raw)) { - // Iterate over the raw property we want to use - foreach ($raw as $check) { - if (array_key_exists($check, $data)) { - $value = $data[$check]; - break; - } - } - } else { - // String - if (array_key_exists($raw, $data)) { - $value = $data[$raw]; - } - } - - $normalized['gq_' . $property] = $value; - } - } - - return $normalized; - } -} diff --git a/GameQ/src/GameQ/Filters/Secondstohuman.php b/GameQ/src/GameQ/Filters/Secondstohuman.php deleted file mode 100644 index 1b413f7..0000000 --- a/GameQ/src/GameQ/Filters/Secondstohuman.php +++ /dev/null @@ -1,121 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Class Secondstohuman - * - * This class converts seconds into a human readable time string 'hh:mm:ss'. This is mainly for converting - * a player's connected time into a readable string. Note that most game servers DO NOT return a player's connected - * time. Source (A2S) based games generally do but not always. This class can also be used to convert other time - * responses into readable time - * - * @package GameQ\Filters - * @author Austin Bischoff - */ -class Secondstohuman extends Base -{ - - /** - * The options key for setting the data key(s) to look for to convert - */ - const OPTION_TIMEKEYS = 'timekeys'; - - /** - * The result key added when applying this filter to a result - */ - const RESULT_KEY = 'gq_%s_human'; - - /** - * Holds the default 'time' keys from the response array. This is key is usually 'time' from A2S responses - * - * @var array - */ - protected $timeKeysDefault = ['time']; - - /** - * Secondstohuman constructor. - * - * @param array $options - */ - public function __construct(array $options = []) - { - // Check for passed keys - if (!array_key_exists(self::OPTION_TIMEKEYS, $options)) { - // Use default - $options[self::OPTION_TIMEKEYS] = $this->timeKeysDefault; - } else { - // Used passed key(s) and make sure it is an array - $options[self::OPTION_TIMEKEYS] = (!is_array($options[self::OPTION_TIMEKEYS])) ? - [$options[self::OPTION_TIMEKEYS]] : $options[self::OPTION_TIMEKEYS]; - } - - parent::__construct($options); - } - - /** - * Apply this filter to the result data - * - * @param array $result - * @param Server $server - * - * @return array - */ - public function apply(array $result, Server $server) - { - // Send the results off to be iterated and return the updated result - return $this->iterate($result); - } - - /** - * Home grown iterate function. Would like to replace this with an internal PHP method(s) but could not find a way - * to make the iterate classes add new keys to the response. They all seemed to be read-only. - * - * @todo: See if there is a more internal way of handling this instead of foreach looping and recursive calling - * - * @param array $result - * - * @return array - */ - protected function iterate(array &$result) - { - // Iterate over the results - foreach ($result as $key => $value) { - // Offload to itself if we have another array - if (is_array($value)) { - // Iterate and update the result - $result[$key] = $this->iterate($value); - } elseif (in_array($key, $this->options[self::OPTION_TIMEKEYS])) { - // Make sure the value is a float (throws E_WARNING in PHP 7.1+) - $value = floatval($value); - // We match one of the keys we are wanting to convert so add it and move on - $result[sprintf(self::RESULT_KEY, $key)] = sprintf( - "%02d:%02d:%02d", - floor($value / 3600), - ($value / 60) % 60, - $value % 60 - ); - } - } - - return $result; - } -} diff --git a/GameQ/src/GameQ/Filters/Stripcolors.php b/GameQ/src/GameQ/Filters/Stripcolors.php deleted file mode 100644 index 5895304..0000000 --- a/GameQ/src/GameQ/Filters/Stripcolors.php +++ /dev/null @@ -1,115 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Class Strip Colors - * - * Strip color codes from UT and Quake based games - * - * @package GameQ\Filters - */ -class Stripcolors extends Base -{ - - /** - * Apply this filter - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * - * @param array $result - * @param \GameQ\Server $server - * - * @return array - */ - public function apply(array $result, Server $server) - { - - // No result passed so just return - if (empty($result)) { - return $result; - } - - //$data = []; - //$data['raw'][ $server->id() ] = $result; - - // Switch based on the base (not game) protocol - switch ($server->protocol()->getProtocol()) { - case 'quake2': - case 'quake3': - case 'doom3': - array_walk_recursive($result, [$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($result, [$this, 'stripUnreal']); - break; - case 'source': - array_walk_recursive($result, [$this, 'stripSource']); - break; - } - - /*$data['filtered'][ $server->id() ] = $result; - file_put_contents( - sprintf( - '%s/../../../tests/Filters/Providers/Stripcolors\%s_1.json', - __DIR__, - $server->protocol()->getProtocol() - ), - json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) - );*/ - - // Return the stripped result - return $result; - } - - /** - * Strip color codes from quake based games - * - * @param string $string - */ - protected function stripQuake(&$string) - { - $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 - * - * @param string $string - */ - protected function stripSource(&$string) - { - $string = strip_tags($string); - } -} diff --git a/GameQ/src/GameQ/Filters/Test.php b/GameQ/src/GameQ/Filters/Test.php deleted file mode 100644 index 836ddf3..0000000 --- a/GameQ/src/GameQ/Filters/Test.php +++ /dev/null @@ -1,47 +0,0 @@ -. - */ - -namespace GameQ\Filters; - -use GameQ\Server; - -/** - * Class Test - * - * This is a test filter to be used for testing purposes only. - * - * @package GameQ\Filters - */ -class Test extends Base -{ - /** - * Apply the filter. For this we just return whatever is sent - * - * @SuppressWarnings(PHPMD) - * - * @param array $result - * @param \GameQ\Server $server - * - * @return array - */ - public function apply(array $result, Server $server) - { - - return $result; - } -} diff --git a/GameQ/src/GameQ/GameQ.php b/GameQ/src/GameQ/GameQ.php deleted file mode 100644 index d3dd9ea..0000000 --- a/GameQ/src/GameQ/GameQ.php +++ /dev/null @@ -1,649 +0,0 @@ -. - */ - -namespace GameQ; - -use GameQ\Exception\Protocol as ProtocolException; -use GameQ\Exception\Query as QueryException; - -/** - * Base GameQ Class - * - * This class should be the only one that is included when you use GameQ to query - * any games servers. - * - * Requirements: See wiki or README for more information on the requirements - * - PHP 5.4.14+ - * * Bzip2 - http://www.php.net/manual/en/book.bzip2.php - * - * @author Austin Bischoff - * - * @property bool $debug - * @property string $capture_packets_file - * @property int $stream_timeout - * @property int $timeout - * @property int $write_wait - */ -class GameQ -{ - /* - * Constants - */ - const PROTOCOLS_DIRECTORY = __DIR__ . '/Protocols'; - - /* Static Section */ - - /** - * Holds the instance of itself - * - * @type self - */ - protected static $instance = null; - - /** - * Create a new instance of this class - * - * @return \GameQ\GameQ - */ - public static function factory() - { - - // Create a new instance - self::$instance = new self(); - - // Return this new instance - return self::$instance; - } - - /* Dynamic Section */ - - /** - * Default options - * - * @type array - */ - protected $options = [ - 'debug' => false, - 'timeout' => 3, // Seconds - 'filters' => [ - // Default normalize - 'normalize_d751713988987e9331980363e24189ce' => [ - 'filter' => 'normalize', - 'options' => [], - ], - ], - // Advanced settings - 'stream_timeout' => 200000, // See http://www.php.net/manual/en/function.stream-select.php for more info - 'write_wait' => 500, - // How long (in micro-seconds) to pause between writing to server sockets, helps cpu usage - - // Used for generating protocol test data - 'capture_packets_file' => null, - ]; - - /** - * Array of servers being queried - * - * @type array - */ - protected $servers = []; - - /** - * The query library to use. Default is Native - * - * @type string - */ - protected $queryLibrary = 'GameQ\\Query\\Native'; - - /** - * Holds the instance of the queryLibrary - * - * @type \GameQ\Query\Core|null - */ - protected $query = null; - - /** - * GameQ constructor. - * - * Do some checks as needed so this will operate - */ - public function __construct() - { - // Check for missing utf8_encode function - if (!function_exists('utf8_encode')) { - throw new \Exception("PHP's utf8_encode() function is required - " - . "http://php.net/manual/en/function.utf8-encode.php. Check your php installation."); - } - } - - /** - * Get an option's value - * - * @param mixed $option - * - * @return mixed|null - */ - public function __get($option) - { - - return isset($this->options[$option]) ? $this->options[$option] : null; - } - - /** - * Set an option's value - * - * @param mixed $option - * @param mixed $value - * - * @return bool - */ - public function __set($option, $value) - { - - $this->options[$option] = $value; - - return true; - } - - /** - * Chainable call to __set, uses set as the actual setter - * - * @param mixed $var - * @param mixed $value - * - * @return $this - */ - public function setOption($var, $value) - { - - // Use magic - $this->{$var} = $value; - - return $this; // Make chainable - } - - /** - * Add a single server - * - * @param array $server_info - * - * @return $this - */ - public function addServer(array $server_info = []) - { - - // Add and validate the server - $this->servers[uniqid()] = new Server($server_info); - - return $this; // Make calls chainable - } - - /** - * Add multiple servers in a single call - * - * @param array $servers - * - * @return $this - */ - public function addServers(array $servers = []) - { - - // Loop through all the servers and add them - foreach ($servers as $server_info) { - $this->addServer($server_info); - } - - return $this; // Make calls chainable - } - - /** - * Add a set of servers from a file or an array of files. - * Supported formats: - * JSON - * - * @param array $files - * - * @return $this - * @throws \Exception - */ - public function addServersFromFiles($files = []) - { - - // Since we expect an array let us turn a string (i.e. single file) into an array - if (!is_array($files)) { - $files = [$files]; - } - - // Iterate over the file(s) and add them - foreach ($files as $file) { - // Check to make sure the file exists and we can read it - if (!file_exists($file) || !is_readable($file)) { - continue; - } - - // See if this file is JSON - if (($servers = json_decode(file_get_contents($file), true)) === null - && json_last_error() !== JSON_ERROR_NONE - ) { - // Type not supported - continue; - } - - // Add this list of servers - $this->addServers($servers); - } - - return $this; - } - - /** - * Clear all of the defined servers - * - * @return $this - */ - public function clearServers() - { - - // Reset all the servers - $this->servers = []; - - return $this; // Make Chainable - } - - /** - * Add a filter to the processing list - * - * @param string $filterName - * @param array $options - * - * @return $this - */ - public function addFilter($filterName, $options = []) - { - // Create the filter hash so we can run multiple versions of the same filter - $filterHash = sprintf('%s_%s', strtolower($filterName), md5(json_encode($options))); - - // Add the filter - $this->options['filters'][$filterHash] = [ - 'filter' => strtolower($filterName), - 'options' => $options, - ]; - - unset($filterHash); - - return $this; - } - - /** - * Remove an added filter - * - * @param string $filterHash - * - * @return $this - */ - public function removeFilter($filterHash) - { - // Make lower case - $filterHash = strtolower($filterHash); - - // Remove this filter if it has been defined - if (array_key_exists($filterHash, $this->options['filters'])) { - unset($this->options['filters'][$filterHash]); - } - - unset($filterHash); - - return $this; - } - - /** - * Return the list of applied filters - * - * @return array - */ - public function listFilters() - { - return $this->options['filters']; - } - - /** - * Main method used to actually process all of the added servers and return the information - * - * @return array - * @throws \Exception - */ - public function process() - { - - // Initialize the query library we are using - $class = new \ReflectionClass($this->queryLibrary); - - // Set the query pointer to the new instance of the library - $this->query = $class->newInstance(); - - unset($class); - - // Define the return - $results = []; - - // @todo: Add break up into loop to split large arrays into smaller chunks - - // Do server challenge(s) first, if any - $this->doChallenges(); - - // Do packets for server(s) and get query responses - $this->doQueries(); - - // Now we should have some information to process for each server - foreach ($this->servers as $server) { - /* @var $server \GameQ\Server */ - - // Parse the responses for this server - $result = $this->doParseResponse($server); - - // Apply the filters - $result = array_merge($result, $this->doApplyFilters($result, $server)); - - // Sort the keys so they are alphabetical and nicer to look at - ksort($result); - - // Add the result to the results array - $results[$server->id()] = $result; - } - - return $results; - } - - /** - * Do server challenges, where required - */ - protected function doChallenges() - { - - // Initialize the sockets for reading - $sockets = []; - - // By default we don't have any challenges to process - $server_challenge = false; - - // Do challenge packets - foreach ($this->servers as $server_id => $server) { - /* @var $server \GameQ\Server */ - - // This protocol has a challenge packet that needs to be sent - if ($server->protocol()->hasChallenge()) { - // We have a challenge, set the flag - $server_challenge = true; - - // Let's make a clone of the query class - $socket = clone $this->query; - - // Set the information for this query socket - $socket->set( - $server->protocol()->transport(), - $server->ip, - $server->port_query, - $this->timeout - ); - - try { - // Now write the challenge packet to the socket. - $socket->write($server->protocol()->getPacket(Protocol::PACKET_CHALLENGE)); - - // Add the socket information so we can reference it easily - $sockets[(int)$socket->get()] = [ - 'server_id' => $server_id, - 'socket' => $socket, - ]; - } catch (QueryException $e) { - // Check to see if we are in debug, if so bubble up the exception - if ($this->debug) { - throw new \Exception($e->getMessage(), $e->getCode(), $e); - } - } - - unset($socket); - - // Let's sleep shortly so we are not hammering out calls rapid fire style hogging cpu - usleep($this->write_wait); - } - } - - // We have at least one server with a challenge, we need to listen for responses - if ($server_challenge) { - // Now we need to listen for and grab challenge response(s) - $responses = call_user_func_array( - [$this->query, 'getResponses'], - [$sockets, $this->timeout, $this->stream_timeout] - ); - - // Iterate over the challenge responses - foreach ($responses as $socket_id => $response) { - // Back out the server_id we need to update the challenge response for - $server_id = $sockets[$socket_id]['server_id']; - - // Make this into a buffer so it is easier to manipulate - $challenge = new Buffer(implode('', $response)); - - // Grab the server instance - /* @var $server \GameQ\Server */ - $server = $this->servers[$server_id]; - - // Apply the challenge - $server->protocol()->challengeParseAndApply($challenge); - - // Add this socket to be reused, has to be reused in GameSpy3 for example - $server->socketAdd($sockets[$socket_id]['socket']); - - // Clear - unset($server); - } - } - } - - /** - * Run the actual queries and get the response(s) - */ - protected function doQueries() - { - - // Initialize the array of sockets - $sockets = []; - - // Iterate over the server list - foreach ($this->servers as $server_id => $server) { - /* @var $server \GameQ\Server */ - - // Invoke the beforeSend method - $server->protocol()->beforeSend($server); - - // Get all the non-challenge packets we need to send - $packets = $server->protocol()->getPacket('!' . Protocol::PACKET_CHALLENGE); - - if (count($packets) == 0) { - // Skip nothing else to do for some reason. - continue; - } - - // Try to use an existing socket - if (($socket = $server->socketGet()) === null) { - // Let's make a clone of the query class - $socket = clone $this->query; - - // Set the information for this query socket - $socket->set( - $server->protocol()->transport(), - $server->ip, - $server->port_query, - $this->timeout - ); - } - - try { - // Iterate over all the packets we need to send - foreach ($packets as $packet_data) { - // Now write the packet to the socket. - $socket->write($packet_data); - - // Let's sleep shortly so we are not hammering out calls rapid fire style - usleep($this->write_wait); - } - - unset($packets); - - // Add the socket information so we can reference it easily - $sockets[(int)$socket->get()] = [ - 'server_id' => $server_id, - 'socket' => $socket, - ]; - } catch (QueryException $e) { - // Check to see if we are in debug, if so bubble up the exception - if ($this->debug) { - throw new \Exception($e->getMessage(), $e->getCode(), $e); - } - - break; - } - - // Clean up the sockets, if any left over - $server->socketCleanse(); - } - - // Now we need to listen for and grab response(s) - $responses = call_user_func_array( - [$this->query, 'getResponses'], - [$sockets, $this->timeout, $this->stream_timeout] - ); - - // Iterate over the responses - foreach ($responses as $socket_id => $response) { - // Back out the server_id - $server_id = $sockets[$socket_id]['server_id']; - - // Grab the server instance - /* @var $server \GameQ\Server */ - $server = $this->servers[$server_id]; - - // Save the response from this packet - $server->protocol()->packetResponse($response); - - unset($server); - } - - // Now we need to close all of the sockets - foreach ($sockets as $socketInfo) { - /* @var $socket \GameQ\Query\Core */ - $socket = $socketInfo['socket']; - - // Close the socket - $socket->close(); - - unset($socket); - } - - unset($sockets); - } - - /** - * Parse the response for a specific server - * - * @param \GameQ\Server $server - * - * @return array - * @throws \Exception - */ - protected function doParseResponse(Server $server) - { - - try { - // @codeCoverageIgnoreStart - // We want to save this server's response to a file (useful for unit testing) - if (!is_null($this->capture_packets_file)) { - file_put_contents( - $this->capture_packets_file, - implode(PHP_EOL . '||' . PHP_EOL, $server->protocol()->packetResponse()) - ); - } - // @codeCoverageIgnoreEnd - - // Get the server response - $results = $server->protocol()->processResponse(); - - // Check for online before we do anything else - $results['gq_online'] = (count($results) > 0); - } catch (ProtocolException $e) { - // Check to see if we are in debug, if so bubble up the exception - if ($this->debug) { - throw new \Exception($e->getMessage(), $e->getCode(), $e); - } - - // We ignore this server - $results = [ - 'gq_online' => false, - ]; - } - - // Now add some default stuff - $results['gq_address'] = (isset($results['gq_address'])) ? $results['gq_address'] : $server->ip(); - $results['gq_port_client'] = $server->portClient(); - $results['gq_port_query'] = (isset($results['gq_port_query'])) ? $results['gq_port_query'] : $server->portQuery(); - $results['gq_protocol'] = $server->protocol()->getProtocol(); - $results['gq_type'] = (string)$server->protocol(); - $results['gq_name'] = $server->protocol()->nameLong(); - $results['gq_transport'] = $server->protocol()->transport(); - - // Process the join link - if (!isset($results['gq_joinlink']) || empty($results['gq_joinlink'])) { - $results['gq_joinlink'] = $server->getJoinLink(); - } - - return $results; - } - - /** - * Apply any filters to the results - * - * @param array $results - * @param \GameQ\Server $server - * - * @return array - */ - protected function doApplyFilters(array $results, Server $server) - { - - // Loop over the filters - foreach ($this->options['filters'] as $filterOptions) { - // Try to do this filter - try { - // Make a new reflection class - $class = new \ReflectionClass(sprintf('GameQ\\Filters\\%s', ucfirst($filterOptions['filter']))); - - // Create a new instance of the filter class specified - $filter = $class->newInstanceArgs([$filterOptions['options']]); - - // Apply the filter to the data - $results = $filter->apply($results, $server); - } catch (\ReflectionException $e) { - // Invalid, skip it - continue; - } - } - - return $results; - } -} diff --git a/GameQ/src/GameQ/Protocol.php b/GameQ/src/GameQ/Protocol.php deleted file mode 100644 index 6d94a45..0000000 --- a/GameQ/src/GameQ/Protocol.php +++ /dev/null @@ -1,500 +0,0 @@ -. - * - * - */ - -namespace GameQ; - -/** - * Handles the core functionality for the protocols - * - * @SuppressWarnings(PHPMD.NumberOfChildren) - * - * @author Austin Bischoff - */ -abstract class Protocol -{ - - /** - * 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'; - - const TRANSPORT_SSL = 'ssl'; - - const TRANSPORT_TLS = 'tls'; - - /** - * Short name of the protocol - * - * @type string - */ - protected $name = 'unknown'; - - /** - * The longer, fancier name for the protocol - * - * @type string - */ - protected $name_long = 'unknown'; - - /** - * The difference between the client port and query port - * - * @type int - */ - protected $port_diff = 0; - - /** - * The transport method to use to actually send the data - * Default is UDP - * - * @type string - */ - protected $transport = self::TRANSPORT_UDP; - - /** - * The protocol type used when querying the server - * - * @type string - */ - protected $protocol = 'unknown'; - - /** - * Holds the valid packet types this protocol has available. - * - * @type array - */ - protected $packets = []; - - /** - * Holds the response headers and the method to use to process them. - * - * @type array - */ - protected $responses = []; - - /** - * Holds the list of methods to run when parsing the packet response(s) data. These - * methods should provide all the return information. - * - * @type array - */ - protected $process_methods = []; - - /** - * The packet responses received - * - * @type array - */ - protected $packets_response = []; - - /** - * Holds the instance of the result class - * - * @type null - */ - protected $result = null; - - /** - * Options for this protocol - * - * @type array - */ - protected $options = []; - - /** - * Define the state of this class - * - * @type int - */ - protected $state = self::STATE_STABLE; - - /** - * Holds specific normalize settings - * - * @todo: Remove this ugly bulk by moving specific ones to their specific game(s) - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => [ - 'listenserver', - 'dedic', - 'bf2dedicated', - 'netserverdedicated', - 'bf2142dedicated', - 'dedicated', - ], - 'gametype' => ['ggametype', 'sigametype', 'matchtype'], - 'hostname' => ['svhostname', 'servername', 'siname', 'name'], - 'mapname' => ['map', 'simap'], - 'maxplayers' => ['svmaxclients', 'simaxplayers', 'maxclients', 'max_players'], - 'mod' => ['game', 'gamedir', 'gamevariant'], - 'numplayers' => ['clients', 'sinumplayers', 'num_players'], - 'password' => ['protected', 'siusepass', 'sineedpass', 'pswrd', 'gneedpass', 'auth', 'passsord'], - ], - // Indvidual - 'player' => [ - 'name' => ['nick', 'player', 'playername', 'name'], - 'kills' => ['kills'], - 'deaths' => ['deaths'], - 'score' => ['kills', 'frags', 'skill', 'score'], - 'ping' => ['ping'], - ], - // Team - 'team' => [ - 'name' => ['name', 'teamname', 'team_t'], - 'score' => ['score', 'score_t'], - ], - ]; - - /** - * Quick join link - * - * @type string - */ - protected $join_link = ''; - - /** - * @param array $options - */ - public function __construct(array $options = []) - { - - // Set the options for this specific instance of the class - $this->options = $options; - } - - /** - * String name of this class - * - * @return string - */ - public function __toString() - { - - return $this->name; - } - - /** - * Get the port difference between the server's client (game) and query ports - * - * @return int - */ - public function portDiff() - { - - return $this->port_diff; - } - - /** - * "Find" the query port based off of the client port and port_diff - * - * This method is meant to be overloaded for more complex maths or lookup tables - * - * @param int $clientPort - * - * @return int - */ - public function findQueryPort($clientPort) - { - - return $clientPort + $this->port_diff; - } - - /** - * Return the join_link as defined by the protocol class - * - * @return string - */ - public function joinLink() - { - - return $this->join_link; - } - - /** - * Short (callable) name of this class - * - * @return string - */ - public function name() - { - - return $this->name; - } - - /** - * Long name of this class - * - * @return string - */ - public function nameLong() - { - - return $this->name_long; - } - - /** - * Return the status of this Protocol Class - * - * @return int - */ - public function state() - { - - return $this->state; - } - - /** - * Return the protocol property - * - * @return string - */ - public function getProtocol() - { - - return $this->protocol; - } - - /** - * Get/set the transport type for this protocol - * - * @param string|null $type - * - * @return string - */ - public function transport($type = null) - { - - // Act as setter - if (!is_null($type)) { - $this->transport = $type; - } - - return $this->transport; - } - - /** - * Set the options for the protocol call - * - * @param array $options - * - * @return array - */ - public function options($options = []) - { - - // Act as setter - if (!empty($options)) { - $this->options = $options; - } - - return $this->options; - } - - - /* - * Packet Section - */ - - /** - * Return specific packet(s) - * - * @param array $type - * - * @return array - */ - public function getPacket($type = []) - { - - $packets = []; - - - // We want an array of packets back - if (is_array($type) && !empty($type)) { - // 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; - } - } - } elseif ($type == '!challenge') { - // Loop the packets - foreach ($this->packets as $packet_type => $packet_data) { - // Dont want challenge packets - if ($packet_type != self::PACKET_CHALLENGE) { - $packets[$packet_type] = $packet_data; - } - } - } elseif (is_string($type)) { - // Return specific packet type - $packets = $this->packets[$type]; - } else { - // Return all packets - $packets = $this->packets; - } - - // Return the packets - return $packets; - } - - /** - * Get/set the packet response - * - * @param array|null $response - * - * @return array - */ - public function packetResponse(array $response = null) - { - - // Act as setter - if (!empty($response)) { - $this->packets_response = $response; - } - - return $this->packets_response; - } - - - /* - * Challenge section - */ - - /** - * Determine whether or not this protocol has a challenge needed before querying - * - * @return bool - */ - public function hasChallenge() - { - - return (isset($this->packets[self::PACKET_CHALLENGE]) && !empty($this->packets[self::PACKET_CHALLENGE])); - } - - /** - * Parse the challenge response and add it to the buffer items that need it. - * This should be overloaded by extending class - * - * @codeCoverageIgnore - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param \GameQ\Buffer $challenge_buffer - * - * @return bool - */ - public function challengeParseAndApply(Buffer $challenge_buffer) - { - - return true; - } - - /** - * Apply the challenge string to all the packets that need it. - * - * @param string $challenge_string - * - * @return bool - */ - protected function challengeApply($challenge_string) - { - - // Let's loop through 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; - } - - /** - * Get the normalize settings for the protocol - * - * @return array - */ - public function getNormalize() - { - - return $this->normalize; - } - - /* - * General - */ - - /** - * Generic method to allow protocol classes to do work right before the query is sent - * - * @codeCoverageIgnore - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param \GameQ\Server $server - */ - public function beforeSend(Server $server) - { - } - - /** - * Method called to process query response data. Each extending class has to have one of these functions. - * - * @return mixed - */ - abstract public function processResponse(); -} diff --git a/GameQ/src/GameQ/Protocols/Aa3.php b/GameQ/src/GameQ/Protocols/Aa3.php deleted file mode 100644 index 6ffd412..0000000 --- a/GameQ/src/GameQ/Protocols/Aa3.php +++ /dev/null @@ -1,53 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Aa3 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Aa3 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'aa3'; - - /** - * 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/GameQ/src/GameQ/Protocols/Aapg.php b/GameQ/src/GameQ/Protocols/Aapg.php deleted file mode 100644 index a207d4f..0000000 --- a/GameQ/src/GameQ/Protocols/Aapg.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Aapg - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Aapg extends Aa3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'aapg'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "America's Army: Proving Grounds"; -} diff --git a/GameQ/src/GameQ/Protocols/Arkse.php b/GameQ/src/GameQ/Protocols/Arkse.php deleted file mode 100644 index 3193c5a..0000000 --- a/GameQ/src/GameQ/Protocols/Arkse.php +++ /dev/null @@ -1,51 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class ARK: Survival Evolved - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Arkse extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'arkse'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "ARK: Survival Evolved"; - - /** - * query_port = client_port + 19238 - * 27015 = 7777 + 19238 - * - * @type int - */ - protected $port_diff = 19238; -} diff --git a/GameQ/src/GameQ/Protocols/Arma.php b/GameQ/src/GameQ/Protocols/Arma.php deleted file mode 100644 index 2653872..0000000 --- a/GameQ/src/GameQ/Protocols/Arma.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Arma - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Arma extends Gamespy2 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'arma'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "ArmA Armed Assault"; -} diff --git a/GameQ/src/GameQ/Protocols/Arma3.php b/GameQ/src/GameQ/Protocols/Arma3.php deleted file mode 100644 index 2718587..0000000 --- a/GameQ/src/GameQ/Protocols/Arma3.php +++ /dev/null @@ -1,181 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Class Armed Assault 3 - * - * Rules protocol reference: https://community.bistudio.com/wiki/Arma_3_ServerBrowserProtocol2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - * @author Memphis017 - */ -class Arma3 extends Source -{ - /** - * Defines the names for the specific game DLCs - * - * @var array - */ - protected $dlcNames = [ - 'af82811b' => 'Karts', - '94f76a1a' => 'Marksmen', - 'd0356eec' => 'Helicopters', - '19984a71' => 'Zeus', - '7fb4b1f3' => 'Apex', - '49c2c12b' => 'Jets', - '7e766e18' => 'Laws of War', - '99d71f90' => 'Malden', - 'a8b10cdf' => 'Tac-Ops', - '37680ce8' => 'Tanks', - '43f9c377' => 'Contact', - 'c4979557' => 'Enoch', - ]; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'arma3'; - - /** - * Longer string name of this protocol class - * - * @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()); - $result->add('overflow', $responseBuffer->readInt8()); - $dlcBit = decbin($responseBuffer->readInt8()); // Grab DLC bit 1 and use it later - $dlcBit2 = decbin($responseBuffer->readInt8()); // Grab DLC bit 2 and use it later - $dlcCount = substr_count($dlcBit, '1') + substr_count($dlcBit2, '1'); // Count the DLCs - - // 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 DLC bit so we can pull in the info for the DLC (if enabled) - for ($x = 0; $x < $dlcCount; $x++) { - $dlcHash = dechex($responseBuffer->readInt32()); - isset($this->dlcNames[$dlcHash]) ? - $result->addSub('dlcs', 'name', $this->dlcNames[$dlcHash]) - : $result->addSub('dlcs', 'name', 'Unknown'); - $result->addSub('dlcs', 'hash', $dlcHash); - } - - // No longer needed - unset($dlcBit, $dlcBit2, $dlcCount, $dlcHash); - - // Grab the mod count - $modCount = $responseBuffer->readInt8(); - - // Add mod count - $result->add('mod_count', $modCount); - - // Loop the mod count and add them - for ($x = 0; $x < $modCount; $x++) { - // Add the mod to the list - $result->addSub('mods', 'hash', dechex($responseBuffer->readInt32())); - $result->addSub('mods', 'steam_id', hexdec($responseBuffer->readPascalString(0, true))); - $result->addSub('mods', 'name', $responseBuffer->readPascalString(0, true)); - } - - unset($modCount, $x); - - // 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/GameQ/src/GameQ/Protocols/Armedassault2oa.php b/GameQ/src/GameQ/Protocols/Armedassault2oa.php deleted file mode 100644 index e527a38..0000000 --- a/GameQ/src/GameQ/Protocols/Armedassault2oa.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/src/GameQ/Protocols/Armedassault3.php b/GameQ/src/GameQ/Protocols/Armedassault3.php deleted file mode 100644 index 5bbca42..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Ase.php b/GameQ/src/GameQ/Protocols/Ase.php deleted file mode 100644 index cb5c6a4..0000000 --- a/GameQ/src/GameQ/Protocols/Ase.php +++ /dev/null @@ -1,208 +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)); - - // Burn the header - $buffer->skip(4); - - // 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/GameQ/src/GameQ/Protocols/Atlas.php b/GameQ/src/GameQ/Protocols/Atlas.php deleted file mode 100644 index 83406ba..0000000 --- a/GameQ/src/GameQ/Protocols/Atlas.php +++ /dev/null @@ -1,55 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Atlas - * - * @package GameQ\Protocols - * @author Wilson Jesus <> - */ -class Atlas extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'atlas'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Atlas"; - - /** - * query_port = client_port + 51800 - * 57561 = 5761 + 51800 - * - * this is the default value for the stock game server, both ports - * can be independently changed from the stock ones, - * making the port_diff logic useless. - * - * @type int - */ - protected $port_diff = 51800; -} diff --git a/GameQ/src/GameQ/Protocols/Batt1944.php b/GameQ/src/GameQ/Protocols/Batt1944.php deleted file mode 100644 index f0ff38e..0000000 --- a/GameQ/src/GameQ/Protocols/Batt1944.php +++ /dev/null @@ -1,68 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Battalion 1944 - * - * @package GameQ\Protocols - * @author TacTicToe66 - */ -class Batt1944 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'batt1944'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Battalion 1944"; - - /** - * query_port = client_port + 3 - * - * @type int - */ - protected $port_diff = 3; - - /** - * Normalize main fields - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'bat_gamemode_s', - 'hostname' => 'bat_name_s', - 'mapname' => 'bat_map_s', - 'maxplayers' => 'bat_max_players_i', - 'numplayers' => 'bat_player_count_s', - 'password' => 'bat_has_password_s', - ], - ]; -} diff --git a/GameQ/src/GameQ/Protocols/Bf1942.php b/GameQ/src/GameQ/Protocols/Bf1942.php deleted file mode 100644 index 4cf06c5..0000000 --- a/GameQ/src/GameQ/Protocols/Bf1942.php +++ /dev/null @@ -1,88 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/src/GameQ/Protocols/Bf2.php b/GameQ/src/GameQ/Protocols/Bf2.php deleted file mode 100644 index 0610f9d..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Bf3.php b/GameQ/src/GameQ/Protocols/Bf3.php deleted file mode 100644 index 9084515..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Bf4.php b/GameQ/src/GameQ/Protocols/Bf4.php deleted file mode 100644 index 6951752..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Bfbc2.php b/GameQ/src/GameQ/Protocols/Bfbc2.php deleted file mode 100644 index b7167a0..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Bfh.php b/GameQ/src/GameQ/Protocols/Bfh.php deleted file mode 100644 index 067d77f..0000000 --- a/GameQ/src/GameQ/Protocols/Bfh.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Battlefield Hardline Protocol class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Bfh extends Bf4 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'bfh'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Battlefield Hardline"; -} diff --git a/GameQ/src/GameQ/Protocols/Brink.php b/GameQ/src/GameQ/Protocols/Brink.php deleted file mode 100644 index 2022652..0000000 --- a/GameQ/src/GameQ/Protocols/Brink.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Brink - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Brink extends Source -{ - /** - * 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/GameQ/src/GameQ/Protocols/Cod.php b/GameQ/src/GameQ/Protocols/Cod.php deleted file mode 100644 index 2425ea6..0000000 --- a/GameQ/src/GameQ/Protocols/Cod.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Call of Duty Protocol Class - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Cod extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cod'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Call of Duty"; -} diff --git a/GameQ/src/GameQ/Protocols/Cod2.php b/GameQ/src/GameQ/Protocols/Cod2.php deleted file mode 100644 index 79be7ca..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Cod4.php b/GameQ/src/GameQ/Protocols/Cod4.php deleted file mode 100644 index 9838d9c..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Codmw3.php b/GameQ/src/GameQ/Protocols/Codmw3.php deleted file mode 100644 index 1049b60..0000000 --- a/GameQ/src/GameQ/Protocols/Codmw3.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/src/GameQ/Protocols/Coduo.php b/GameQ/src/GameQ/Protocols/Coduo.php deleted file mode 100644 index 2dd9a18..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Codwaw.php b/GameQ/src/GameQ/Protocols/Codwaw.php deleted file mode 100644 index f730678..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Conanexiles.php b/GameQ/src/GameQ/Protocols/Conanexiles.php deleted file mode 100644 index a097e1d..0000000 --- a/GameQ/src/GameQ/Protocols/Conanexiles.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Conanexiles - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Conanexiles extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'conanexiles'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Conan Exiles"; -} diff --git a/GameQ/src/GameQ/Protocols/Contagion.php b/GameQ/src/GameQ/Protocols/Contagion.php deleted file mode 100644 index 64d0b76..0000000 --- a/GameQ/src/GameQ/Protocols/Contagion.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Contagion - * - * @package GameQ\Protocols - * @author Nikolay Ipanyuk - * @author Austin Bischoff - */ -class Contagion extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'contagion'; - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Contagion"; -} diff --git a/GameQ/src/GameQ/Protocols/Crysis.php b/GameQ/src/GameQ/Protocols/Crysis.php deleted file mode 100644 index e09a673..0000000 --- a/GameQ/src/GameQ/Protocols/Crysis.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/src/GameQ/Protocols/Crysis2.php b/GameQ/src/GameQ/Protocols/Crysis2.php deleted file mode 100644 index 75c6614..0000000 --- a/GameQ/src/GameQ/Protocols/Crysis2.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/src/GameQ/Protocols/Crysiswars.php b/GameQ/src/GameQ/Protocols/Crysiswars.php deleted file mode 100644 index 44dcdcf..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Cs15.php b/GameQ/src/GameQ/Protocols/Cs15.php deleted file mode 100644 index ba37524..0000000 --- a/GameQ/src/GameQ/Protocols/Cs15.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Counter-Strike 1.5 Protocol Class - * - * @author Nikolay Ipanyuk - * @author Austin Bischoff - * - * @package GameQ\Protocols - */ -class Cs15 extends Won -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cs15'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Counter-Strike 1.5"; -} diff --git a/GameQ/src/GameQ/Protocols/Cs16.php b/GameQ/src/GameQ/Protocols/Cs16.php deleted file mode 100644 index 25a6602..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Cs2d.php b/GameQ/src/GameQ/Protocols/Cs2d.php deleted file mode 100644 index 0f238fd..0000000 --- a/GameQ/src/GameQ/Protocols/Cs2d.php +++ /dev/null @@ -1,263 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Counter-Strike 2d Protocol Class - * - * Note: - * Unable to make player information calls work as the protocol does not like parallel requests - * - * @author Austin Bischoff - */ -class Cs2d extends Protocol -{ - - /** - * Array of packets we want to query. - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\x01\x00\xFB\x01", - //self::PACKET_STATUS => "\x01\x00\x03\x10\x21\xFB\x01\x75\x00", - self::PACKET_PLAYERS => "\x01\x00\xFB\x05", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\x01\x00\xFB\x01" => "processDetails", - "\x01\x00\xFB\x05" => "processPlayers", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'cs2d'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'cs2d'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Counter-Strike 2d"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "cs2d://%s:%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'game_mode', - 'hostname' => 'hostname', - 'mapname' => 'mapname', - 'maxplayers' => 'max_players', - 'mod' => 'game_dir', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'deaths' => 'deaths', - 'score' => 'score', - ], - ]; - - /** - * Process the response for the Tibia server - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // We have a merged packet, try to split it back up - if (count($this->packets_response) == 1) { - // Temp buffer to make string manipulation easier - $buffer = new Buffer($this->packets_response[0]); - - // Grab the header and set the packet we need to split with - $packet = (($buffer->lookAhead(4) === $this->packets[self::PACKET_PLAYERS]) ? - self::PACKET_STATUS : self::PACKET_PLAYERS); - - // Explode the merged packet as the response - $responses = explode(substr($this->packets[$packet], 2), $buffer->getData()); - - // Try to rebuild the second packet to the same as if it was sent as two separate responses - $responses[1] = $this->packets[$packet] . ((count($responses) === 2) ? $responses[1] : ""); - - unset($buffer); - } else { - $responses = $this->packets_response; - } - - // 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 ($responses as $response) { - $buffer = new Buffer($response); - - // Pull out the header - $header = $buffer->read(4); - - // 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; - } - - /** - * Handles processing the details data into a usable format - * - * @param Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processDetails(Buffer $buffer) - { - // Set the result to a new result instance - $result = new Result(); - - // First int is the server flags - $serverFlags = $buffer->readInt8(); - - // Read server flags - $result->add('password', (int)$this->readFlag($serverFlags, 0)); - $result->add('registered_only', (int)$this->readFlag($serverFlags, 1)); - $result->add('fog_of_war', (int)$this->readFlag($serverFlags, 2)); - $result->add('friendly_fire', (int)$this->readFlag($serverFlags, 3)); - $result->add('bots_enabled', (int)$this->readFlag($serverFlags, 5)); - $result->add('lua_scripts', (int)$this->readFlag($serverFlags, 6)); - - // Read the rest of the buffer data - $result->add('servername', utf8_encode($buffer->readPascalString(0))); - $result->add('mapname', utf8_encode($buffer->readPascalString(0))); - $result->add('num_players', $buffer->readInt8()); - $result->add('max_players', $buffer->readInt8()); - $result->add('game_mode', $buffer->readInt8()); - $result->add('num_bots', (($this->readFlag($serverFlags, 5)) ? $buffer->readInt8() : 0)); - $result->add('dedicated', 1); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the player data into a usable format - * - * @param Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // First entry is the number of players in this list. Don't care - $buffer->read(); - - // Parse players - while ($buffer->getLength()) { - // Player id - if (($id = $buffer->readInt8()) !== 0) { - // Add the results - $result->addPlayer('id', $id); - $result->addPlayer('name', utf8_encode($buffer->readPascalString(0))); - $result->addPlayer('team', $buffer->readInt8()); - $result->addPlayer('score', $buffer->readInt32()); - $result->addPlayer('deaths', $buffer->readInt32()); - } - } - - unset($buffer, $id); - - return $result->fetch(); - } - - /** - * Read flags from stored value - * - * @param $flags - * @param $offset - * - * @return bool - */ - protected function readFlag($flags, $offset) - { - return !!($flags & (1 << $offset)); - } -} diff --git a/GameQ/src/GameQ/Protocols/Cscz.php b/GameQ/src/GameQ/Protocols/Cscz.php deleted file mode 100644 index b539128..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Csgo.php b/GameQ/src/GameQ/Protocols/Csgo.php deleted file mode 100644 index 41af735..0000000 --- a/GameQ/src/GameQ/Protocols/Csgo.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Csgo - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Csgo extends Source -{ - - /** - * 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/GameQ/src/GameQ/Protocols/Css.php b/GameQ/src/GameQ/Protocols/Css.php deleted file mode 100644 index be75da3..0000000 --- a/GameQ/src/GameQ/Protocols/Css.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Css - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Css extends 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/GameQ/src/GameQ/Protocols/Dal.php b/GameQ/src/GameQ/Protocols/Dal.php deleted file mode 100644 index 6b05037..0000000 --- a/GameQ/src/GameQ/Protocols/Dal.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Dark and Light - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dal extends Arkse -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'dal'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Dark and Light"; -} diff --git a/GameQ/src/GameQ/Protocols/Dayz.php b/GameQ/src/GameQ/Protocols/Dayz.php deleted file mode 100644 index 01c7c28..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Dayzmod.php b/GameQ/src/GameQ/Protocols/Dayzmod.php deleted file mode 100644 index 2ce1076..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Dod.php b/GameQ/src/GameQ/Protocols/Dod.php deleted file mode 100644 index 0c7baf6..0000000 --- a/GameQ/src/GameQ/Protocols/Dod.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Dod - * - * Based off of CS 1.6 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dod extends Cs16 -{ - - /** - * 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/GameQ/src/GameQ/Protocols/Dods.php b/GameQ/src/GameQ/Protocols/Dods.php deleted file mode 100644 index 898d75b..0000000 --- a/GameQ/src/GameQ/Protocols/Dods.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Dods - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dods extends 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/GameQ/src/GameQ/Protocols/Dow.php b/GameQ/src/GameQ/Protocols/Dow.php deleted file mode 100644 index b66512a..0000000 --- a/GameQ/src/GameQ/Protocols/Dow.php +++ /dev/null @@ -1,69 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; - -/** - * Class Dow - * - * Apparently the player response is incomplete as there is no information being returned for that packet - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Dow extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'dow'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Days of War"; - - /** - * Normalize main fields - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'G_s', - 'hostname' => 'ONM_s', - 'mapname' => 'MPN_s', - 'maxplayers' => 'P_i', - 'numplayers' => 'N_i', - ], - // Individual - 'player' => [ - 'name' => 'name', - 'score' => 'score', - 'time' => 'time', - ], - ]; -} diff --git a/GameQ/src/GameQ/Protocols/Eco.php b/GameQ/src/GameQ/Protocols/Eco.php deleted file mode 100644 index a2292e9..0000000 --- a/GameQ/src/GameQ/Protocols/Eco.php +++ /dev/null @@ -1,123 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Exception\Protocol as Exception; -use GameQ\Result; - -/** - * ECO Global Survival Protocol Class - * - * @author Austin Bischoff - */ -class Eco extends Http -{ - /** - * Packets to send - * - * @var array - */ - protected $packets = [ - self::PACKET_STATUS => "GET /frontpage HTTP/1.0\r\nAccept: */*\r\n\r\n", - ]; - - /** - * Http protocol is SSL - * - * @var string - */ - protected $transport = self::TRANSPORT_TCP; - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'eco'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'eco'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "ECO Global Survival"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; - - /** - * Normalize some items - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'description', - 'maxplayers' => 'totalplayers', - 'numplayers' => 'onlineplayers', - 'password' => 'haspassword', - ], - ]; - - /** - * 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 Eco server is invalid."); - } - - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - foreach ($json->Info as $info => $setting) { - $result->add(strtolower($info), $setting); - } - - return $result->fetch(); - } -} diff --git a/GameQ/src/GameQ/Protocols/Egs.php b/GameQ/src/GameQ/Protocols/Egs.php deleted file mode 100644 index 4f82aa8..0000000 --- a/GameQ/src/GameQ/Protocols/Egs.php +++ /dev/null @@ -1,51 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Empyrion - Galactic Survival - * - * @package GameQ\Protocols - * @author Austin Bischoff - * @author TacTicToe66 - */ -class EgS extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'egs'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Empyrion - Galactic Survival"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/src/GameQ/Protocols/Et.php b/GameQ/src/GameQ/Protocols/Et.php deleted file mode 100644 index 63b5beb..0000000 --- a/GameQ/src/GameQ/Protocols/Et.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Wolfenstein Enemy Territory Protocol Class - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Et extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'et'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Wolfenstein Enemy Territory"; -} diff --git a/GameQ/src/GameQ/Protocols/Etqw.php b/GameQ/src/GameQ/Protocols/Etqw.php deleted file mode 100644 index 1f3a446..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Ffe.php b/GameQ/src/GameQ/Protocols/Ffe.php deleted file mode 100644 index c0947bd..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Ffow.php b/GameQ/src/GameQ/Protocols/Ffow.php deleted file mode 100644 index 00c33d4..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Gamespy.php b/GameQ/src/GameQ/Protocols/Gamespy.php deleted file mode 100644 index b1a1e4f..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Gamespy2.php b/GameQ/src/GameQ/Protocols/Gamespy2.php deleted file mode 100644 index c7788d9..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Gamespy3.php b/GameQ/src/GameQ/Protocols/Gamespy3.php deleted file mode 100644 index 2df0a4b..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Gamespy4.php b/GameQ/src/GameQ/Protocols/Gamespy4.php deleted file mode 100644 index e28755f..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Gmod.php b/GameQ/src/GameQ/Protocols/Gmod.php deleted file mode 100644 index 6596724..0000000 --- a/GameQ/src/GameQ/Protocols/Gmod.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Gmod - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Gmod extends Source -{ - /** - * 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/GameQ/src/GameQ/Protocols/Grav.php b/GameQ/src/GameQ/Protocols/Grav.php deleted file mode 100644 index e025075..0000000 --- a/GameQ/src/GameQ/Protocols/Grav.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Grav Online Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Grav extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'grav'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "GRAV Online"; -} diff --git a/GameQ/src/GameQ/Protocols/Gta5m.php b/GameQ/src/GameQ/Protocols/Gta5m.php deleted file mode 100644 index 0f0c50a..0000000 --- a/GameQ/src/GameQ/Protocols/Gta5m.php +++ /dev/null @@ -1,173 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Exception\Protocol as Exception; -use GameQ\Protocol; -use GameQ\Result; - -/** - * GTA Five M Protocol Class - * - * Server base can be found at https://fivem.net/ - * - * Based on code found at https://github.com/LiquidObsidian/fivereborn-query - * - * @author Austin Bischoff - */ -class Gta5m 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\xFF\xFF\xFFgetinfo xxx", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "\xFF\xFF\xFF\xFFinfoResponse" => "processStatus", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'gta5m'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'gta5m'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "GTA Five M"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'gametype', - 'hostname' => 'hostname', - 'mapname' => 'mapname', - 'maxplayers' => 'sv_maxclients', - 'mod' => 'gamename', - 'numplayers' => 'clients', - 'password' => 'privateClients', - ], - ]; - - /** - * 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(PHP_EOL); - - // Figure out which packet response this is - if (empty($response_type) || !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(); - - // 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); - - $itemCount = count($data); - - // Now lets loop the array - for ($x = 0; $x < $itemCount; $x += 2) { - // Set some local vars - $key = $data[$x]; - $val = $data[$x + 1]; - - if (in_array($key, ['challenge'])) { - continue; // skip - } - - // Regular variable so just add the value. - $result->add($key, $val); - } - - /*var_dump($data); - var_dump($result->fetch()); - - exit;*/ - - return $result->fetch(); - } -} diff --git a/GameQ/src/GameQ/Protocols/Gtan.php b/GameQ/src/GameQ/Protocols/Gtan.php deleted file mode 100644 index f7b531e..0000000 --- a/GameQ/src/GameQ/Protocols/Gtan.php +++ /dev/null @@ -1,163 +0,0 @@ -. - */ -namespace GameQ\Protocols; - -use GameQ\Exception\Protocol as Exception; -use GameQ\Result; -use GameQ\Server; - -/** - * Grand Theft Auto Network Protocol Class - * https://stats.gtanet.work/ - * - * Result from this call should be a header + JSON response - * - * References: - * - https://master.gtanet.work/apiservers - * - * @author Austin Bischoff - */ -class Gtan extends Http -{ - /** - * Packets to send - * - * @var array - */ - protected $packets = [ - //self::PACKET_STATUS => "GET /apiservers HTTP/1.0\r\nHost: master.gtanet.work\r\nAccept: */*\r\n\r\n", - self::PACKET_STATUS => "GET /gtan/api.php?ip=%s&raw HTTP/1.0\r\nHost: multiplayerhosting.info\r\nAccept: */*\r\n\r\n", - ]; - - /** - * Http protocol is SSL - * - * @var string - */ - protected $transport = self::TRANSPORT_SSL; - - /** - * The protocol being used - * - * @var string - */ - protected $protocol = 'gtan'; - - /** - * String name of this protocol class - * - * @var string - */ - protected $name = 'gtan'; - - /** - * Longer string name of this protocol class - * - * @var string - */ - protected $name_long = "Grand Theft Auto Network"; - - /** - * Holds the real ip so we can overwrite it back - * - * @var string - */ - protected $realIp = null; - - protected $realPortQuery = null; - - /** - * Normalize some items - * - * @var array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'hostname' => 'hostname', - 'mapname' => 'map', - 'mod' => 'mod', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - ]; - - public function beforeSend(Server $server) - { - // 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, $server->ip . ':' . $server->port_query); - } - - $this->realIp = $server->ip; - $this->realPortQuery = $server->port_query; - - // Override the existing settings - //$server->ip = 'master.gtanet.work'; - $server->ip = 'multiplayerhosting.info'; - $server->port_query = 443; - } - - /** - * Process the response - * - * @return array - * @throws Exception - */ - public function processResponse() - { - // No response, assume offline - if (empty($this->packets_response)) { - return [ - 'gq_address' => $this->realIp, - 'gq_port_query' => $this->realPortQuery, - ]; - } - - // 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 Gtan protocol is invalid."); - } - - $result = new Result(); - - // Server is always dedicated - $result->add('dedicated', 1); - - $result->add('gq_address', $this->realIp); - $result->add('gq_port_query', $this->realPortQuery); - - // Add server items - $result->add('hostname', $json->ServerName); - $result->add('serverversion', $json->ServerVersion); - $result->add('map', ((!empty($json->Map)) ? $json->Map : 'Los Santos/Blaine Country')); - $result->add('mod', $json->Gamemode); - $result->add('password', (int)$json->Passworded); - $result->add('numplayers', $json->CurrentPlayers); - $result->add('maxplayers', $json->MaxPlayers); - - return $result->fetch(); - } -} diff --git a/GameQ/src/GameQ/Protocols/Hl2dm.php b/GameQ/src/GameQ/Protocols/Hl2dm.php deleted file mode 100644 index 15f881a..0000000 --- a/GameQ/src/GameQ/Protocols/Hl2dm.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Hl2dm - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Hl2dm extends Source -{ - /** - * 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/GameQ/src/GameQ/Protocols/Http.php b/GameQ/src/GameQ/Protocols/Http.php deleted file mode 100644 index 2a86d8d..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Hurtworld.php b/GameQ/src/GameQ/Protocols/Hurtworld.php deleted file mode 100644 index fa54654..0000000 --- a/GameQ/src/GameQ/Protocols/Hurtworld.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Hurtworld - * - * @package GameQ\Protocols - * @author Nikolay Ipanyuk - * @author Austin Bischoff - */ -class Hurtworld extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'hurtworld'; - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Hurtworld"; -} diff --git a/GameQ/src/GameQ/Protocols/Insurgency.php b/GameQ/src/GameQ/Protocols/Insurgency.php deleted file mode 100644 index 77b8329..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Insurgencysand.php b/GameQ/src/GameQ/Protocols/Insurgencysand.php deleted file mode 100644 index 407d6e2..0000000 --- a/GameQ/src/GameQ/Protocols/Insurgencysand.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Insurgency Sandstorm Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Insurgencysand extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'insurgencysand'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Insurgency: Sandstorm"; - - /** - * query_port = client_port + 29 - * - * @type int - */ - protected $port_diff = 29; -} diff --git a/GameQ/src/GameQ/Protocols/Jediacademy.php b/GameQ/src/GameQ/Protocols/Jediacademy.php deleted file mode 100644 index a051a3a..0000000 --- a/GameQ/src/GameQ/Protocols/Jediacademy.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Jedi Academy Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Jediacademy extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'jediacademy'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Star Wars Jedi Knight: Jedi Academy"; -} diff --git a/GameQ/src/GameQ/Protocols/Jedioutcast.php b/GameQ/src/GameQ/Protocols/Jedioutcast.php deleted file mode 100644 index 1afd9af..0000000 --- a/GameQ/src/GameQ/Protocols/Jedioutcast.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Jedi Outcast Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Jedioutcast extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'jedioutcast'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Star Wars Jedi Knight II: Jedi Outcast"; -} diff --git a/GameQ/src/GameQ/Protocols/Justcause2.php b/GameQ/src/GameQ/Protocols/Justcause2.php deleted file mode 100644 index 648cb6d..0000000 --- a/GameQ/src/GameQ/Protocols/Justcause2.php +++ /dev/null @@ -1,127 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Just Cause 2 Multiplayer Protocol Class - * - * Special thanks to Woet for some insight on packing - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Justcause2 extends Gamespy4 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'justcause2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Just Cause 2 Multiplayer"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "steam://connect/%s:%d/"; - - /** - * Change the packets used - * - * @var 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\x02", - ]; - - /** - * Override the packet split - * - * @var string - */ - protected $packetSplit = "/\\x00\\x00\\x00/m"; - - /** - * 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' => 'name', - 'ping' => 'ping', - ], - ]; - - /** - * Overload so we can add in some static data points - * - * @param Buffer $buffer - * @param Result $result - */ - protected function processDetails(Buffer &$buffer, Result &$result) - { - parent::processDetails($buffer, $result); - - // Add in map - $result->add('mapname', 'Panau'); - $result->add('dedicated', 'true'); - } - - /** - * Override the parent, this protocol is returned differently - * - * @param Buffer $buffer - * @param Result $result - * - * @see Gamespy3::processPlayersAndTeams() - */ - protected function processPlayersAndTeams(Buffer &$buffer, Result &$result) - { - // Loop until we run out of data - while ($buffer->getLength()) { - $result->addPlayer('name', $buffer->readString()); - $result->addPlayer('steamid', $buffer->readString()); - $result->addPlayer('ping', $buffer->readInt16()); - } - } -} diff --git a/GameQ/src/GameQ/Protocols/Justcause3.php b/GameQ/src/GameQ/Protocols/Justcause3.php deleted file mode 100644 index c4e901d..0000000 --- a/GameQ/src/GameQ/Protocols/Justcause3.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Just Cause 3 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Justcause3 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'justcause3'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Just Cause 3"; - - /** - * Query port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/src/GameQ/Protocols/Killingfloor.php b/GameQ/src/GameQ/Protocols/Killingfloor.php deleted file mode 100644 index 9cc1964..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Killingfloor2.php b/GameQ/src/GameQ/Protocols/Killingfloor2.php deleted file mode 100644 index a134f25..0000000 --- a/GameQ/src/GameQ/Protocols/Killingfloor2.php +++ /dev/null @@ -1,51 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Killing floor - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Killingfloor2 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'killing floor 2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Killing Floor 2"; - - /** - * query_port = client_port + 19238 - * 27015 = 7777 + 19238 - * - * @type int - */ - protected $port_diff = 19238; -} diff --git a/GameQ/src/GameQ/Protocols/L4d.php b/GameQ/src/GameQ/Protocols/L4d.php deleted file mode 100644 index 596452a..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/L4d2.php b/GameQ/src/GameQ/Protocols/L4d2.php deleted file mode 100644 index 475514c..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Lhmp.php b/GameQ/src/GameQ/Protocols/Lhmp.php deleted file mode 100644 index 3d5e81f..0000000 --- a/GameQ/src/GameQ/Protocols/Lhmp.php +++ /dev/null @@ -1,214 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Lost Heaven Protocol class - * - * Reference: http://lh-mp.eu/wiki/index.php/Query_System - * - * @author Austin Bischoff - */ -class Lhmp 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 => "LHMPo", - self::PACKET_PLAYERS => "LHMPp", - ]; - - /** - * Use the response flag to figure out what method to run - * - * @type array - */ - protected $responses = [ - "LHMPo" => "processDetails", - "LHMPp" => "processPlayers", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'lhmp'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'lhmp'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Lost Heaven"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'gametype' => 'gamemode', - 'hostname' => 'servername', - 'mapname' => 'mapname', - 'maxplayers' => 'maxplayers', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'name', - ], - ]; - - /** - * 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 '{$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 Buffer $buffer - * - * @return array - * @throws Exception - */ - protected function processDetails(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - $result->add('protocol', $buffer->readString()); - $result->add('password', $buffer->readString()); - $result->add('numplayers', $buffer->readInt16()); - $result->add('maxplayers', $buffer->readInt16()); - $result->add('servername', utf8_encode($buffer->readPascalString())); - $result->add('gamemode', $buffer->readPascalString()); - $result->add('website', utf8_encode($buffer->readPascalString())); - $result->add('mapname', utf8_encode($buffer->readPascalString())); - - unset($buffer); - - return $result->fetch(); - } - - /** - * Handles processing the player data into a usable format - * - * @param Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // Get the number of players - $result->add('numplayers', $buffer->readInt16()); - - // Parse players - while ($buffer->getLength()) { - // Player id - if (($id = $buffer->readInt16()) !== 0) { - // Add the results - $result->addPlayer('id', $id); - $result->addPlayer('name', utf8_encode($buffer->readPascalString())); - } - } - - unset($buffer, $id); - - return $result->fetch(); - } -} diff --git a/GameQ/src/GameQ/Protocols/Minecraft.php b/GameQ/src/GameQ/Protocols/Minecraft.php deleted file mode 100644 index a895cb8..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Minecraftpe.php b/GameQ/src/GameQ/Protocols/Minecraftpe.php deleted file mode 100644 index 21d1186..0000000 --- a/GameQ/src/GameQ/Protocols/Minecraftpe.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Minecraft PE (BE) Protocol Class - * - * @package GameQ\Protocols - * - * @author Austin Bischoff - */ -class Minecraftpe extends Minecraft -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'minecraftpe'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "MinecraftPE"; -} diff --git a/GameQ/src/GameQ/Protocols/Mohaa.php b/GameQ/src/GameQ/Protocols/Mohaa.php deleted file mode 100644 index 66ddd7e..0000000 --- a/GameQ/src/GameQ/Protocols/Mohaa.php +++ /dev/null @@ -1,79 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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/GameQ/src/GameQ/Protocols/Mordhau.php b/GameQ/src/GameQ/Protocols/Mordhau.php deleted file mode 100644 index fa305ce..0000000 --- a/GameQ/src/GameQ/Protocols/Mordhau.php +++ /dev/null @@ -1,53 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class MORDHAU - * - * @package GameQ\Protocols - * @author Wilson Jesus <> - */ -class Mordhau extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'mordhau'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "MORDHAU"; - - #protected $port = 7777; - - /** - * query_port = client_port + 19238 - * 27015 = 7777 + 19238 - * - * @type int - */ - #protected $port_diff = 19238; -} diff --git a/GameQ/src/GameQ/Protocols/Mta.php b/GameQ/src/GameQ/Protocols/Mta.php deleted file mode 100644 index b95dc4c..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Mumble.php b/GameQ/src/GameQ/Protocols/Mumble.php deleted file mode 100644 index 299389c..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Ns2.php b/GameQ/src/GameQ/Protocols/Ns2.php deleted file mode 100644 index 4c32392..0000000 --- a/GameQ/src/GameQ/Protocols/Ns2.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Ns2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Ns2 extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ns2'; - - /** - * 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/GameQ/src/GameQ/Protocols/Pixark.php b/GameQ/src/GameQ/Protocols/Pixark.php deleted file mode 100644 index 2e67af0..0000000 --- a/GameQ/src/GameQ/Protocols/Pixark.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class PixARK - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Pixark extends Arkse -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'pixark'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "PixARK"; -} diff --git a/GameQ/src/GameQ/Protocols/Projectrealitybf2.php b/GameQ/src/GameQ/Protocols/Projectrealitybf2.php deleted file mode 100644 index 6f4b5ce..0000000 --- a/GameQ/src/GameQ/Protocols/Projectrealitybf2.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Projectrealitybf2 - * - * Based off of BF2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Projectrealitybf2 extends Bf2 -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'projectrealitybf2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Project Reality: Battlefield 2"; -} diff --git a/GameQ/src/GameQ/Protocols/Quake2.php b/GameQ/src/GameQ/Protocols/Quake2.php deleted file mode 100644 index f0366c2..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Quake3.php b/GameQ/src/GameQ/Protocols/Quake3.php deleted file mode 100644 index 6269b92..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Quakelive.php b/GameQ/src/GameQ/Protocols/Quakelive.php deleted file mode 100644 index d5df350..0000000 --- a/GameQ/src/GameQ/Protocols/Quakelive.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Quake Live - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Quakelive extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'quakelive'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Quake Live"; -} diff --git a/GameQ/src/GameQ/Protocols/Redorchestra2.php b/GameQ/src/GameQ/Protocols/Redorchestra2.php deleted file mode 100644 index 6733016..0000000 --- a/GameQ/src/GameQ/Protocols/Redorchestra2.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Redorchestra2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Redorchestra2 extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'redorchestra2'; - - /** - * 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/GameQ/src/GameQ/Protocols/Redorchestraostfront.php b/GameQ/src/GameQ/Protocols/Redorchestraostfront.php deleted file mode 100644 index 4c83b7e..0000000 --- a/GameQ/src/GameQ/Protocols/Redorchestraostfront.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Red Orchestra: Ostfront 41-45 Class - * - * @package GameQ\Protocols - * @author naXe - * @author Austin Bischoff - */ -class Redorchestraostfront extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'redorchestraostfront'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Red Orchestra: Ostfront 41-45"; -} diff --git a/GameQ/src/GameQ/Protocols/Risingstorm2.php b/GameQ/src/GameQ/Protocols/Risingstorm2.php deleted file mode 100644 index ddb82a5..0000000 --- a/GameQ/src/GameQ/Protocols/Risingstorm2.php +++ /dev/null @@ -1,55 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Rising Storm 2 - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Risingstorm2 extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'rising storm 2'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Rising Storm 2"; - - /** - * Query port is always 27015 - * - * @param int $clientPort - * - * @return int - */ - public function findQueryPort($clientPort) - { - return 27015; - } -} diff --git a/GameQ/src/GameQ/Protocols/Rust.php b/GameQ/src/GameQ/Protocols/Rust.php deleted file mode 100644 index 81b0cce..0000000 --- a/GameQ/src/GameQ/Protocols/Rust.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * 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"; -} diff --git a/GameQ/src/GameQ/Protocols/Samp.php b/GameQ/src/GameQ/Protocols/Samp.php deleted file mode 100644 index cf01f83..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Serioussam.php b/GameQ/src/GameQ/Protocols/Serioussam.php deleted file mode 100644 index 32e0a10..0000000 --- a/GameQ/src/GameQ/Protocols/Serioussam.php +++ /dev/null @@ -1,75 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Serious Sam Protocol Class - * - * @author ZCaliptium - */ -class SeriousSam extends Gamespy -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'serioussam'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Serious Sam"; - - /** - * 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', - 'mod' => 'activemod', - 'numplayers' => 'numplayers', - 'password' => 'password', - ], - // Individual - 'player' => [ - 'name' => 'player', - 'ping' => 'ping', - 'score' => 'frags', - ], - ]; -} diff --git a/GameQ/src/GameQ/Protocols/Sevendaystodie.php b/GameQ/src/GameQ/Protocols/Sevendaystodie.php deleted file mode 100644 index a5ddbf2..0000000 --- a/GameQ/src/GameQ/Protocols/Sevendaystodie.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class 7 Days to Die - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Sevendaystodie extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'sevendaystodie'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "7 Days to Die"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/src/GameQ/Protocols/Ship.php b/GameQ/src/GameQ/Protocols/Ship.php deleted file mode 100644 index 9c3bee9..0000000 --- a/GameQ/src/GameQ/Protocols/Ship.php +++ /dev/null @@ -1,95 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Class Ship - * - * @package GameQ\Protocols - * - * @author Nikolay Ipanyuk - * @author Austin Bischoff - */ -class Ship extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'ship'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "The Ship"; - - /** - * Specific player parse for The Ship - * - * Player response has unknown data after the last real player - * - * @param \GameQ\Buffer $buffer - * - * @return array - */ - protected function processPlayers(Buffer $buffer) - { - - // Set the result to a new result instance - $result = new Result(); - - // We need to read the number of players because this response has other data at the end usually - $num_players = $buffer->readInt8(); - - // Player count - $result->add('num_players', $num_players); - - // No players, no work - if ($num_players == 0) { - return $result->fetch(); - } - - // Players list - for ($player = 0; $player < $num_players; $player++) { - $result->addPlayer('id', $buffer->readInt8()); - $result->addPlayer('name', $buffer->readString()); - $result->addPlayer('score', $buffer->readInt32Signed()); - $result->addPlayer('time', $buffer->readFloat32()); - } - - // Extra data - if ($buffer->getLength() > 0) { - for ($player = 0; $player < $num_players; $player++) { - $result->addPlayer('deaths', $buffer->readInt32Signed()); - $result->addPlayer('money', $buffer->readInt32Signed()); - } - } - - unset($buffer); - - return $result->fetch(); - } -} diff --git a/GameQ/src/GameQ/Protocols/Sof2.php b/GameQ/src/GameQ/Protocols/Sof2.php deleted file mode 100644 index 96a4db2..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Soldat.php b/GameQ/src/GameQ/Protocols/Soldat.php deleted file mode 100644 index a9dbbc4..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Source.php b/GameQ/src/GameQ/Protocols/Source.php deleted file mode 100644 index 9e4cb5d..0000000 --- a/GameQ/src/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", - 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/GameQ/src/GameQ/Protocols/Spaceengineers.php b/GameQ/src/GameQ/Protocols/Spaceengineers.php deleted file mode 100644 index ddf8567..0000000 --- a/GameQ/src/GameQ/Protocols/Spaceengineers.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Space Engineers Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Spaceengineers extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'spaceengineers'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Space Engineers"; -} diff --git a/GameQ/src/GameQ/Protocols/Squad.php b/GameQ/src/GameQ/Protocols/Squad.php deleted file mode 100644 index 3c02188..0000000 --- a/GameQ/src/GameQ/Protocols/Squad.php +++ /dev/null @@ -1,53 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Squad - * - * Port reference: http://forums.joinsquad.com/topic/9559-query-ports/ - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Squad extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'squad'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Squad"; - - /** - * query_port = client_port + 19378 - * 27165 = 7787 + 19378 - * - * @type int - */ - protected $port_diff = 19378; -} diff --git a/GameQ/src/GameQ/Protocols/Starmade.php b/GameQ/src/GameQ/Protocols/Starmade.php deleted file mode 100644 index 09a033f..0000000 --- a/GameQ/src/GameQ/Protocols/Starmade.php +++ /dev/null @@ -1,226 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * StarMade Protocol Class - * - * StarMade server query protocol class - * - * Credit to Robin Promesberger for providing Java based querying as a roadmap - * - * @author Austin Bischoff - */ -class Starmade extends Protocol -{ - - /** - * Array of packets we want to query. - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\x00\x00\x00\x09\x2a\xff\xff\x01\x6f\x00\x00\x00\x00", - ]; - - /** - * 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 = 'starmade'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'starmade'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "StarMade"; - - /** - * 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', - 'hostname' => 'hostname', - 'maxplayers' => 'max_players', - 'numplayers' => 'num_players', - 'password' => 'password', - ], - ]; - - /** - * Process the response for the StarMade server - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - - // Implode the packets, not sure if there is any split logic for multiple packets - $buffer = new Buffer(implode('', $this->packets_response), Buffer::NUMBER_TYPE_BIGENDIAN); - - // Get the passed length in the data side of the packet - $buffer->readInt32Signed(); - - // Read off the timestamp (in milliseconds) - $buffer->readInt64(); - - // Burn the check id == 42 - $buffer->readInt8(); - - // Read packetId, unused - $buffer->readInt16Signed(); - - // Read commandId, unused - $buffer->readInt8Signed(); - - // Read type, unused - $buffer->readInt8Signed(); - - $parsed = $this->parseServerParameters($buffer); - - // Set the result to a new result instance - $result = new Result(); - - // Best guess info version is the type of response to expect. As of this commit the version is "2". - $result->add('info_version', $parsed[0]); - $result->add('version', $parsed[1]); - $result->add('hostname', $parsed[2]); - $result->add('game_descr', $parsed[3]); - $result->add('start_time', $parsed[4]); - $result->add('num_players', $parsed[5]); - $result->add('max_players', $parsed[6]); - $result->add('dedicated', 1); // All servers are dedicated as far as I can tell - $result->add('password', 0); // Unsure if you can password servers, cant read that value - //$result->add('map', 'Unknown'); - - unset($parsed); - - return $result->fetch(); - } - - /** - * Parse the server response parameters - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * - * @param \GameQ\Buffer $buffer - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - protected function parseServerParameters(Buffer &$buffer) - { - - // Init the parsed data array - $parsed = []; - - // Read the number of parameters to parse - $parameterSize = $buffer->readInt32Signed(); - - // Iterate over the parameter size - for ($i = 0; $i < $parameterSize; $i++) { - // Read the type of return this is - $dataType = $buffer->readInt8Signed(); - - switch ($dataType) { - // 32-bit int - case 1: - $parsed[$i] = $buffer->readInt32Signed(); - break; - - // 64-bit int - case 2: - $parsed[$i] = $buffer->readInt64(); - break; - - // Float - case 3: - $parsed[$i] = $buffer->readFloat32(); - break; - - // String - case 4: - // The first 2 bytes are the string length - $strLength = $buffer->readInt16Signed(); - - // Read the above length from the buffer - $parsed[$i] = $buffer->read($strLength); - - unset($strLength); - break; - - // Boolean - case 5: - $parsed[$i] = (bool)$buffer->readInt8Signed(); - break; - - // 8-bit int - case 6: - $parsed[$i] = $buffer->readInt8Signed(); - break; - - // 16-bit int - case 7: - $parsed[$i] = $buffer->readInt16Signed(); - break; - - // Array - case 8: - // Not implemented - throw new Exception("StarMade array parsing is not implemented!"); - } - } - - return $parsed; - } -} diff --git a/GameQ/src/GameQ/Protocols/Swat4.php b/GameQ/src/GameQ/Protocols/Swat4.php deleted file mode 100644 index 7b8e120..0000000 --- a/GameQ/src/GameQ/Protocols/Swat4.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Swat4 - * - * @package GameQ\Protocols - * - * @author Wilson Jesus <> - */ -class Swat4 extends Gamespy2 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'swat4'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "SWAT 4"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/src/GameQ/Protocols/Teamspeak2.php b/GameQ/src/GameQ/Protocols/Teamspeak2.php deleted file mode 100644 index df0d59a..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Teamspeak3.php b/GameQ/src/GameQ/Protocols/Teamspeak3.php deleted file mode 100644 index c66f6a4..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Teeworlds.php b/GameQ/src/GameQ/Protocols/Teeworlds.php deleted file mode 100644 index 1bdaa47..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Terraria.php b/GameQ/src/GameQ/Protocols/Terraria.php deleted file mode 100644 index d9455ef..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Tf2.php b/GameQ/src/GameQ/Protocols/Tf2.php deleted file mode 100644 index e08411b..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Theforrest.php b/GameQ/src/GameQ/Protocols/Theforrest.php deleted file mode 100644 index 975c3f6..0000000 --- a/GameQ/src/GameQ/Protocols/Theforrest.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Class Theforrest - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Theforrest extends Source -{ - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'theforrest'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "The Forrest"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/src/GameQ/Protocols/Tibia.php b/GameQ/src/GameQ/Protocols/Tibia.php deleted file mode 100644 index 8702bfa..0000000 --- a/GameQ/src/GameQ/Protocols/Tibia.php +++ /dev/null @@ -1,142 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Protocol; -use GameQ\Buffer; -use GameQ\Result; -use GameQ\Exception\Protocol as Exception; - -/** - * Tibia Protocol Class - * - * Tibia server query protocol class - * - * Credit to Ahmad Fatoum for providing Perl based querying as a roadmap - * - * @author Yive - * @author Austin Bischoff - */ -class Tibia extends Protocol -{ - - /** - * Array of packets we want to query. - * - * @type array - */ - protected $packets = [ - self::PACKET_STATUS => "\x06\x00\xFF\xFF\x69\x6E\x66\x6F", - ]; - - /** - * 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 = 'tibia'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'tibia'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Tibia"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "otserv://%s/%d/"; - - /** - * Normalize settings for this protocol - * - * @type array - */ - protected $normalize = [ - // General - 'general' => [ - // target => source - 'dedicated' => 'dedicated', - 'gametype' => 'server', - 'hostname' => 'servername', - 'motd' => 'motd', - 'maxplayers' => 'players_max', - 'numplayers' => 'players_online', - 'map' => 'map_name', - ], - ]; - - /** - * Process the response for the Tibia server - * - * @return array - * @throws \GameQ\Exception\Protocol - */ - public function processResponse() - { - // Merge the response packets - $xmlString = implode('', $this->packets_response); - - // Check to make sure this is will decode into a valid XML Document - if (($xmlDoc = @simplexml_load_string($xmlString)) === false) { - throw new Exception(__METHOD__ . " Unable to load XML string."); - } - - // Set the result to a new result instance - $result = new Result(); - - // All servers are dedicated as far as I can tell - $result->add('dedicated', 1); - - // Iterate over the info - foreach (['serverinfo', 'owner', 'map', 'npcs', 'monsters', 'players'] as $property) { - foreach ($xmlDoc->{$property}->attributes() as $key => $value) { - if (!in_array($property, ['serverinfo'])) { - $key = $property . '_' . $key; - } - - // Add the result - $result->add($key, (string)$value); - } - } - - $result->add("motd", (string)$xmlDoc->motd); - - unset($xmlDoc, $xmlDoc); - - return $result->fetch(); - } -} diff --git a/GameQ/src/GameQ/Protocols/Tshock.php b/GameQ/src/GameQ/Protocols/Tshock.php deleted file mode 100644 index 551a09e..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Unreal2.php b/GameQ/src/GameQ/Protocols/Unreal2.php deleted file mode 100644 index 0ef0675..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Unturned.php b/GameQ/src/GameQ/Protocols/Unturned.php deleted file mode 100644 index 4829b37..0000000 --- a/GameQ/src/GameQ/Protocols/Unturned.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Unturned Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Unturned extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'unturned'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Unturned"; - - /** - * query_port = client_port + 1 - * - * @type int - */ - protected $port_diff = 1; -} diff --git a/GameQ/src/GameQ/Protocols/Urbanterror.php b/GameQ/src/GameQ/Protocols/Urbanterror.php deleted file mode 100644 index 682f91e..0000000 --- a/GameQ/src/GameQ/Protocols/Urbanterror.php +++ /dev/null @@ -1,49 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Urban Terror Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Urbanterror extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'urbanterror'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Urban Terror"; - - /** - * The client join link - * - * @type string - */ - protected $join_link = "urt://%s:%d/"; -} diff --git a/GameQ/src/GameQ/Protocols/Ut.php b/GameQ/src/GameQ/Protocols/Ut.php deleted file mode 100644 index 75722ce..0000000 --- a/GameQ/src/GameQ/Protocols/Ut.php +++ /dev/null @@ -1,73 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Unreal Tournament Protocol Class - * - * @author Austin Bischoff - */ -class Ut extends Gamespy -{ - - /** - * 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/GameQ/src/GameQ/Protocols/Ut2004.php b/GameQ/src/GameQ/Protocols/Ut2004.php deleted file mode 100644 index 953089f..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Ut3.php b/GameQ/src/GameQ/Protocols/Ut3.php deleted file mode 100644 index b55cc34..0000000 --- a/GameQ/src/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/GameQ/src/GameQ/Protocols/Ventrilo.php b/GameQ/src/GameQ/Protocols/Ventrilo.php deleted file mode 100644 index 8a1e0e8..0000000 --- a/GameQ/src/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 ($i = 1; $i <= $characterCount; $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; - } - } - - $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 ($i = 1; $i <= $characterCount; $i++) { - $chars[$i] -= ($table[$a2] + (($i - 1) % 72)) & 0xFF; - $a2 = ($a2 + $a1) & 0xFF; - $data .= chr($chars[$i]); - } - //@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/GameQ/src/GameQ/Protocols/Warsow.php b/GameQ/src/GameQ/Protocols/Warsow.php deleted file mode 100644 index f1d629a..0000000 --- a/GameQ/src/GameQ/Protocols/Warsow.php +++ /dev/null @@ -1,96 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -use GameQ\Buffer; -use GameQ\Result; - -/** - * Warsow Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Warsow extends Quake3 -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'warsow'; - - /** - * 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 function processPlayers(Buffer $buffer) - { - // 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 space - $playerInfo->skip(1); - - // Add team - $result->addPlayer('team', $playerInfo->read()); - - // Clear - unset($playerInfo); - } - - // Clear - unset($buffer); - - return $result->fetch(); - } -} diff --git a/GameQ/src/GameQ/Protocols/Won.php b/GameQ/src/GameQ/Protocols/Won.php deleted file mode 100644 index bef0984..0000000 --- a/GameQ/src/GameQ/Protocols/Won.php +++ /dev/null @@ -1,66 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * World Opponent Network (WON) class - * - * Pre-cursor to the A2S (source) protocol system - * - * @author Nikolay Ipanyuk - * @author Austin Bischoff - * - * @package GameQ\Protocols - */ -class Won extends Source -{ - - /** - * 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 => "\xFF\xFF\xFF\xFFdetails\x00", - self::PACKET_PLAYERS => "\xFF\xFF\xFF\xFFplayers", - self::PACKET_RULES => "\xFF\xFF\xFF\xFFrules", - ]; - - /** - * The query protocol used to make the call - * - * @type string - */ - protected $protocol = 'won'; - - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'won'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "World Opponent Network"; -} diff --git a/GameQ/src/GameQ/Protocols/Wurm.php b/GameQ/src/GameQ/Protocols/Wurm.php deleted file mode 100644 index c593652..0000000 --- a/GameQ/src/GameQ/Protocols/Wurm.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace GameQ\Protocols; - -/** - * Wurm Unlimited Protocol Class - * - * @package GameQ\Protocols - * @author Austin Bischoff - */ -class Wurm extends Source -{ - /** - * String name of this protocol class - * - * @type string - */ - protected $name = 'wurm'; - - /** - * Longer string name of this protocol class - * - * @type string - */ - protected $name_long = "Wurm Unlimited"; -} diff --git a/GameQ/src/GameQ/Query/Core.php b/GameQ/src/GameQ/Query/Core.php deleted file mode 100644 index 5eb08ad..0000000 --- a/GameQ/src/GameQ/Query/Core.php +++ /dev/null @@ -1,164 +0,0 @@ -. - */ - -namespace GameQ\Query; - -/** - * Core for the query mechanisms - * - * @author Austin Bischoff - */ -abstract class Core -{ - - /** - * The socket used by this resource - * - * @type null|resource - */ - public $socket = null; - - /** - * The transport type (udp, tcp, etc...) - * See http://php.net/manual/en/transports.php for the supported list - * - * @type string - */ - protected $transport = null; - - /** - * Connection IP address - * - * @type string - */ - protected $ip = null; - - /** - * Connection port - * - * @type int - */ - protected $port = null; - - /** - * The time in seconds to wait before timing out while connecting to the socket - * - * @type int - */ - protected $timeout = 3; // Seconds - - /** - * Socket is blocking? - * - * @type bool - */ - protected $blocking = false; - - /** - * Called when the class is cloned - */ - public function __clone() - { - - // Reset the properties for this class when cloned - $this->reset(); - } - - /** - * Set the connection information for the socket - * - * @param string $transport - * @param string $ip - * @param int $port - * @param int $timeout seconds - * @param bool $blocking - */ - public function set($transport, $ip, $port, $timeout = 3, $blocking = false) - { - - $this->transport = $transport; - - $this->ip = $ip; - - $this->port = $port; - - $this->timeout = $timeout; - - $this->blocking = $blocking; - } - - /** - * Reset this instance's properties - */ - public function reset() - { - - $this->transport = null; - - $this->ip = null; - - $this->port = null; - - $this->timeout = 3; - - $this->blocking = false; - } - - /** - * Create a new socket - * - * @return void - */ - abstract protected function create(); - - /** - * Get the socket - * - * @return mixed - */ - abstract public function get(); - - /** - * Write data to the socket - * - * @param string $data - * - * @return int The number of bytes written - */ - abstract public function write($data); - - /** - * Close the socket - * - * @return void - */ - abstract public function close(); - - /** - * Read the responses from the socket(s) - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param array $sockets - * @param int $timeout - * @param int $stream_timeout - * - * @return array - */ - abstract public function getResponses(array $sockets, $timeout, $stream_timeout); -} diff --git a/GameQ/src/GameQ/Query/Native.php b/GameQ/src/GameQ/Query/Native.php deleted file mode 100644 index b078c9c..0000000 --- a/GameQ/src/GameQ/Query/Native.php +++ /dev/null @@ -1,221 +0,0 @@ -. - */ - -namespace GameQ\Query; - -use GameQ\Exception\Query as Exception; - -/** - * Native way of querying servers - * - * @author Austin Bischoff - */ -class Native extends Core -{ - /** - * Get the current socket or create one and return - * - * @return resource|null - * @throws \GameQ\Exception\Query - */ - public function get() - { - - // No socket for this server, make one - if (is_null($this->socket)) { - $this->create(); - } - - return $this->socket; - } - - /** - * Write data to the socket - * - * @param string $data - * - * @return int The number of bytes written - * @throws \GameQ\Exception\Query - */ - public function write($data) - { - - try { - // No socket for this server, make one - if (is_null($this->socket)) { - $this->create(); - } - - // Send the packet - return fwrite($this->socket, $data); - } catch (\Exception $e) { - throw new Exception($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * Close the current socket - */ - public function close() - { - - if ($this->socket) { - fclose($this->socket); - $this->socket = null; - } - } - - /** - * Create a new socket for this query - * - * @throws \GameQ\Exception\Query - */ - protected function create() - { - - // Create the remote address - $remote_addr = sprintf("%s://%s:%d", $this->transport, $this->ip, $this->port); - - // Create context - $context = stream_context_create([ - 'socket' => [ - 'bindto' => '0:0', // Bind to any available IP and OS decided port - ], - ]); - - // Define these first - $errno = null; - $errstr = null; - - // Create the socket - if (($this->socket = - @stream_socket_client($remote_addr, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context)) - !== false - ) { - // Set the read timeout on the streams - stream_set_timeout($this->socket, $this->timeout); - - // Set blocking mode - stream_set_blocking($this->socket, $this->blocking); - } else { - // Reset socket - $this->socket = null; - - // Something bad happened, throw query exception - throw new Exception( - __METHOD__ . " - Error creating socket to server {$this->ip}:{$this->port}. Error: " . $errstr, - $errno - ); - } - } - - /** - * Pull the responses out of the stream - * - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * - * @param array $sockets - * @param int $timeout - * @param int $stream_timeout - * - * @return array Raw responses - */ - public function getResponses(array $sockets, $timeout, $stream_timeout) - { - - // Set the loop to active - $loop_active = true; - - // Will hold the responses read from the sockets - $responses = []; - - // To store the sockets - $sockets_tmp = []; - - // Loop and pull out all the actual sockets we need to listen on - foreach ($sockets as $socket_id => $socket_data) { - // Get the socket - /* @var $socket \GameQ\Query\Core */ - $socket = $socket_data['socket']; - - // Append the actual socket we are listening to - $sockets_tmp[$socket_id] = $socket->get(); - - unset($socket); - } - - // Init some variables - $read = $sockets_tmp; - $write = null; - $except = null; - - // Check to see if $read is empty, if so stream_select() will throw a warning - if (empty($read)) { - return $responses; - } - - // This is when it should stop - $time_stop = microtime(true) + $timeout; - - // Let's loop until we break something. - while ($loop_active && microtime(true) < $time_stop) { - // Check to make sure $read is not empty, if so we are done - if (empty($read)) { - break; - } - - // Now lets listen for some streams, but do not cross the streams! - $streams = stream_select($read, $write, $except, 0, $stream_timeout); - - // We had error or no streams left, kill the loop - if ($streams === false || ($streams <= 0)) { - break; - } - - // Loop the sockets that received data back - foreach ($read as $socket) { - /* @var $socket resource */ - - // See if we have a response - if (($response = fread($socket, 8192)) === false) { - continue; // No response yet so lets continue. - } - - // Check to see if the response is empty, if so we are done with this server - if (strlen($response) == 0) { - // Remove this server from any future read loops - unset($sockets_tmp[(int)$socket]); - continue; - } - - // Add the response we got back - $responses[(int)$socket][] = $response; - } - - // Because stream_select modifies read we need to reset it each time to the original array of sockets - $read = $sockets_tmp; - } - - // Free up some memory - unset($streams, $read, $write, $except, $sockets_tmp, $time_stop, $response); - - // Return all of the responses, may be empty if something went wrong - return $responses; - } -} diff --git a/GameQ/src/GameQ/Result.php b/GameQ/src/GameQ/Result.php deleted file mode 100644 index 7023f17..0000000 --- a/GameQ/src/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; - } -} diff --git a/GameQ/src/GameQ/Server.php b/GameQ/src/GameQ/Server.php deleted file mode 100644 index dff8f77..0000000 --- a/GameQ/src/GameQ/Server.php +++ /dev/null @@ -1,380 +0,0 @@ -. - */ - -namespace GameQ; - -use GameQ\Exception\Server as Exception; - -/** - * Server class to represent each server entity - * - * @author Austin Bischoff - */ -class Server -{ - - /* - * Server array keys - */ - const SERVER_TYPE = 'type'; - - const SERVER_HOST = 'host'; - - const SERVER_ID = 'id'; - - const SERVER_OPTIONS = 'options'; - - /* - * Server options keys - */ - - /* - * Use this option when the query_port and client connect ports are different - */ - const SERVER_OPTIONS_QUERY_PORT = 'query_port'; - - /** - * The protocol class for this server - * - * @type \GameQ\Protocol - */ - protected $protocol = null; - - /** - * Id of this server - * - * @type string - */ - public $id = null; - - /** - * IP Address of this server - * - * @type string - */ - public $ip = null; - - /** - * The server's client port (connect port) - * - * @type int - */ - public $port_client = null; - - /** - * The server's query port - * - * @type int - */ - public $port_query = null; - - /** - * Holds other server specific options - * - * @type array - */ - protected $options = []; - - /** - * Holds the sockets already open for this server - * - * @type array - */ - protected $sockets = []; - - /** - * Construct the class with the passed options - * - * @param array $server_info - * - * @throws \GameQ\Exception\Server - */ - public function __construct(array $server_info = []) - { - - // Check for server type - if (!array_key_exists(self::SERVER_TYPE, $server_info) || empty($server_info[self::SERVER_TYPE])) { - throw new Exception("Missing server info key '" . self::SERVER_TYPE . "'!"); - } - - // Check for server host - if (!array_key_exists(self::SERVER_HOST, $server_info) || empty($server_info[self::SERVER_HOST])) { - throw new Exception("Missing server info key '" . self::SERVER_HOST . "'!"); - } - - // IP address and port check - $this->checkAndSetIpPort($server_info[self::SERVER_HOST]); - - // Check for server id - if (array_key_exists(self::SERVER_ID, $server_info) && !empty($server_info[self::SERVER_ID])) { - // Set the server id - $this->id = $server_info[self::SERVER_ID]; - } else { - // Make an id so each server has an id when returned - $this->id = sprintf('%s:%d', $this->ip, $this->port_client); - } - - // Check and set server options - if (array_key_exists(self::SERVER_OPTIONS, $server_info)) { - // Set the options - $this->options = $server_info[self::SERVER_OPTIONS]; - } - - try { - // Make the protocol class for this type - $class = new \ReflectionClass( - sprintf('GameQ\\Protocols\\%s', ucfirst(strtolower($server_info[self::SERVER_TYPE]))) - ); - - $this->protocol = $class->newInstanceArgs([$this->options]); - } catch (\ReflectionException $e) { - throw new Exception("Unable to locate Protocols class for '{$server_info[self::SERVER_TYPE]}'!"); - } - - // Check and set any server options - $this->checkAndSetServerOptions(); - - unset($server_info, $class); - } - - /** - * Check and set the ip address for this server - * - * @param $ip_address - * - * @throws \GameQ\Exception\Server - */ - protected function checkAndSetIpPort($ip_address) - { - - // Test for IPv6 - if (substr_count($ip_address, ':') > 1) { - // See if we have a port, input should be in the format [::1]:27015 or similar - if (strstr($ip_address, ']:')) { - // Explode to get port - $server_addr = explode(':', $ip_address); - - // Port is the last item in the array, remove it and save - $this->port_client = (int)array_pop($server_addr); - - // The rest is the address, recombine - $this->ip = implode(':', $server_addr); - - unset($server_addr); - } else { - // Just the IPv6 address, no port defined, fail - throw new Exception( - "The host address '{$ip_address}' is missing the port. All " - . "servers must have a port defined!" - ); - } - - // Now let's validate the IPv6 value sent, remove the square brackets ([]) first - if (!filter_var(trim($this->ip, '[]'), FILTER_VALIDATE_IP, ['flags' => FILTER_FLAG_IPV6,])) { - throw new Exception("The IPv6 address '{$this->ip}' is invalid."); - } - } else { - // We have IPv4 with a port defined - if (strstr($ip_address, ':')) { - list($this->ip, $this->port_client) = explode(':', $ip_address); - - // Type case the port - $this->port_client = (int)$this->port_client; - } else { - // No port, fail - throw new Exception( - "The host address '{$ip_address}' is missing the port. All " - . "servers must have a port defined!" - ); - } - - // 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) - ) { - // 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."); - } - } - } - - /** - * Check and set any server specific options - */ - protected function checkAndSetServerOptions() - { - - // Specific query port defined - if (array_key_exists(self::SERVER_OPTIONS_QUERY_PORT, $this->options)) { - $this->port_query = (int)$this->options[self::SERVER_OPTIONS_QUERY_PORT]; - } else { - // Do math based on the protocol class - $this->port_query = $this->protocol->findQueryPort($this->port_client); - } - } - - /** - * Set an option for this server - * - * @param $key - * @param $value - * - * @return $this - */ - public function setOption($key, $value) - { - - $this->options[$key] = $value; - - return $this; // Make chainable - } - - /** - * Return set option value - * - * @param mixed $key - * - * @return mixed - */ - public function getOption($key) - { - - return (array_key_exists($key, $this->options)) ? $this->options[$key] : null; - } - - /** - * Get the ID for this server - * - * @return string - */ - public function id() - { - - return $this->id; - } - - /** - * Get the IP address for this server - * - * @return string - */ - public function ip() - { - - return $this->ip; - } - - /** - * Get the client port for this server - * - * @return int - */ - public function portClient() - { - - return $this->port_client; - } - - /** - * Get the query port for this server - * - * @return int - */ - public function portQuery() - { - - return $this->port_query; - } - - /** - * Return the protocol class for this server - * - * @return \GameQ\Protocol - */ - public function protocol() - { - - return $this->protocol; - } - - /** - * Get the join link for this server - * - * @return string - */ - public function getJoinLink() - { - - return sprintf($this->protocol->joinLink(), $this->ip, $this->portClient()); - } - - /* - * Socket holding - */ - - /** - * Add a socket for this server to be reused - * - * @codeCoverageIgnore - * - * @param \GameQ\Query\Core $socket - */ - public function socketAdd(Query\Core $socket) - { - - $this->sockets[] = $socket; - } - - /** - * Get a socket from the list to reuse, if any are available - * - * @codeCoverageIgnore - * - * @return \GameQ\Query\Core|null - */ - public function socketGet() - { - - $socket = null; - - if (count($this->sockets) > 0) { - $socket = array_pop($this->sockets); - } - - return $socket; - } - - /** - * Clear any sockets still listed and attempt to close them - * - * @codeCoverageIgnore - */ - public function socketCleanse() - { - - // Close all of the sockets available - foreach ($this->sockets as $socket) { - /* @var $socket \GameQ\Query\Core */ - $socket->close(); - } - - // Reset the sockets list - $this->sockets = []; - } -} diff --git a/GameQ/status_expansion.php b/GameQ/status_expansion.php deleted file mode 100644 index dca5ef2..0000000 --- a/GameQ/status_expansion.php +++ /dev/null @@ -1,206 +0,0 @@ -addServer([ - 'type' => 'dayz', - 'host' => '82.64.214.194:3222', - 'options' => [ - 'query_port' => 27022, - ], -]); - - -// 'type' => 'dayz', -// 'host' => '82.64.214.194:2303', -// 'options' => [ -// 'query_port' => 27023, -// ], -//]); - -// Define the servers you wish you query -//$GameQ = new \GameQ\GameQ(); // or //$GameQ = \GameQ\GameQ::factory(); - -$GameQ->setOption('timeout', 3); // 3 seconds -$results = $GameQ->process(); - -//print_r($results); - //echo "

// var dump

"; - //var_dump(json_decode($readjson, true)); -//echo "

// echo

"; -// echo $readjson
"; - //$data1 = json_decode("$readjson", true); -//echo "

//Print data1

" ; - //print_r($data1); -echo "
"; - - -//$data = json_decode($readjson); -$data = json_decode($GameQ); -// class -$name = $data->{'name'}; -$map = $data->{'map'}; -$password = $data->{'password'}; -$game = $data->{'raw'}->{'game'}; -$secure = $data->{'raw'}->{'secure'}; -$numplayers = $data->{'raw'}->{'numplayers'}; -$version = $data->{'raw'}->{'version'}; -$tags = $data->{'raw'}->{'tags'}; - -//$dedicated = $data->{'raw'}->{'rules'}->{'dedicated'}; -//$island = $data->{'raw'}->{'rules'}->{'island'}; - - -$connect = $data->{'connect'}; -$ping = $data->{'ping'}; -$time = "$tags[38]$tags[39]:$tags[41]$tags[42]"; -$battleye = substr($tags,0,8); -$hive = substr($tags,18,8); -$players = $data->{'players'}; - -//if(empty($players)) -// $players = "0"; -//if (empty($players)) { "0"; } -//$playersuser = substr($players,0,8); -//$players = $data->{'array_filter($players)'}; -//$player = $data->{'players'}; - -?> - - - - - Dayz ToX Server: <?php echo"${name}"; ?> - - - - - -

- - - - - - -
-
- - - - - - - - - - - - - - - -
- Server Name IP server Ping Time Player Info Joueurs Version Battleye
-
- -

- - - - - - - - - - - - -
Players Info Debug
Nameprint_r ";print_r($players); - -?> -
- -"; -echo "
Resultat
"; -echo "
Server Name: ${name} \n";echo "
"; -echo "Map: ${map}
"; -echo "Game: ${game}
"; -echo "IP: ${connect}
"; -echo "Secure: ${secure}
"; -echo "Version: ${version}
"; -//echo "Island: ${island}
"; -//echo "dedicated: ${dedicated}
"; -echo "Ping: ${ping}
"; -echo "Time: $time
"; -echo "Nombre Joueurs: ${numplayers}
"; -echo "Players: "; if(count($players) == 1) {echo "il y a des joueurs"; } else {echo "0 player" ;} -echo "
"; -echo "Tags: ($tags)"; //printf("[%0.45s]
",$tags); //print_r($tags); -echo "
hive: ${hive}
"; -echo "Battleye: ${battleye}"; -echo "
"; -?> - - - - - diff --git a/GameQ/status_livonia.php b/GameQ/status_livonia.php deleted file mode 100644 index 825d036..0000000 --- a/GameQ/status_livonia.php +++ /dev/null @@ -1,200 +0,0 @@ -addServer([ - 'type' => 'dayz', - 'host' => '82.64.214.194:3202', - 'options' => [ - 'query_port' => 27022, - ], -]); - - -// Define the servers you wish you query -//$GameQ = new \GameQ\GameQ(); // or //$GameQ = \GameQ\GameQ::factory(); - -$GameQ->setOption('timeout', 3); // 3 seconds -$results = $GameQ->process(); - -//print_r($results); - //echo "

// var dump

"; - //var_dump(json_decode($readjson, true)); -//echo "

// echo

"; -// echo $readjson
"; - //$data1 = json_decode("$readjson", true); -//echo "

//Print data1

" ; - //print_r($data1); -echo "
"; - - -$data = json_decode($readjson); -// class -$name = $data->{'name'}; -$map = $data->{'map'}; -$password = $data->{'password'}; -$game = $data->{'raw'}->{'game'}; -$secure = $data->{'raw'}->{'secure'}; -$numplayers = $data->{'raw'}->{'numplayers'}; -$version = $data->{'raw'}->{'version'}; -$tags = $data->{'raw'}->{'tags'}; - -//$dedicated = $data->{'raw'}->{'rules'}->{'dedicated'}; -//$island = $data->{'raw'}->{'rules'}->{'island'}; - - -$connect = $data->{'connect'}; -$ping = $data->{'ping'}; -$time = "$tags[38]$tags[39]:$tags[41]$tags[42]"; -$battleye = substr($tags,0,8); -$hive = substr($tags,18,8); -$players = $data->{'players'}; - -//if(empty($players)) -// $players = "0"; -//if (empty($players)) { "0"; } -//$playersuser = substr($players,0,8); -//$players = $data->{'array_filter($players)'}; -//$player = $data->{'players'}; -7 -?> - - - - - Dayz ToX Server: <?php echo"${name}"; ?> - - - - - -

- - - - - - -
-
- - - - - - - - - - - - - - - -
- Server Name IP server Ping Time Player Info Joueurs Version Battleye
-
- -

- - - - - - - - - - - - -
Players Info Debug
Nameprint_r ";print_r($players); - -?> -
- -"; -echo "
Resultat
"; -echo "
Server Name: ${name} \n";echo "
"; -echo "Map: ${map}
"; -echo "Game: ${game}
"; -echo "IP: ${connect}
"; -echo "Secure: ${secure}
"; -echo "Version: ${version}
"; -//echo "Island: ${island}
"; -//echo "dedicated: ${dedicated}
"; -echo "Ping: ${ping}
"; -echo "Time: $time
"; -echo "Nombre Joueurs: ${numplayers}
"; -echo "Players: "; if(count($players) == 1) {echo "il y a des joueurs"; } else {echo "0 player" ;} -echo "
"; -echo "Tags: ($tags)"; //printf("[%0.45s]
",$tags); //print_r($tags); -echo "
hive: ${hive}
"; -echo "Battleye: ${battleye}"; -echo "
"; -?> - - - - - diff --git a/README.md b/README.md index d124df6..9110ec8 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,9 @@ Inspired by Omega namager template. > */5 * * * * /usr/local/bin/php -f /your/path/dayz2json_parser_sql.php 2>&1 + Check your time zone here. + https://www.php.net/manual/en/timezones.others.php + ### TODO - make Regex to check time serv (to auto detect it, and it's fucking hard :p) diff --git a/dayz2json_parser_sql.php b/SQL/dayz2json_parser_sql.php similarity index 77% rename from dayz2json_parser_sql.php rename to SQL/dayz2json_parser_sql.php index 0133f7e..66c4447 100644 --- a/dayz2json_parser_sql.php +++ b/SQL/dayz2json_parser_sql.php @@ -5,7 +5,7 @@ include_once('./consql.php'); // Don't touch below (or you know what you do) - $urlserv = $ipserv.":".$portserv ; + $urlserv = $ipserv.":".$servport ; // librarie SQ - info serv game require 'SQ_/bootstrap.php'; @@ -38,9 +38,10 @@ include_once('./consql.php'); $Timer = Number_Format( MicroTime( true ) - $Timer, 4, '.', '' ); - $InfoGT = $Info['GameTags']; - + $InfoGT = $Info['GameTags']; +// DEBUG +/* print_r($Info); echo "

"; @@ -55,9 +56,11 @@ echo "Os: " .$Info['Os'] . "
"; echo "Version: " .$Info['Version'] . "
"; echo "Port: " .$Info['GamePort'] . "
"; echo "GameID: " .$Info['GameID'] . "
"; - echo "
test SQL"; +*/ + +// Variables $HostName = $Info['HostName'] ; $Game = $Info['ModDesc'] ; $Version = $Info['Version'] ; @@ -71,14 +74,18 @@ $GameID = $Info['GameID'] ; // set the default timezone to use. Available since PHP 5.1 -date_default_timezone_set('UTC+1'); +// https://www.php.net/manual/en/timezones.others.php +date_default_timezone_set('Etc/GMT-1'); +//date_default_timezone_set('Europe/Paris'); $date = date('Y-m-d H:i:s'); -$insql = "INSERT INTO $table (date,name,game,map,version,players,maxplayers,ping,timeserver,hive,battleye,connect,secure) VALUES ('$date','$HostName', '$Game', '$Map', '$Version', '$Players', '$MaxPlayers', '0', '2:20', 'hive', 'battleye', '$urlserv', '$Secure')"; +// SQL insert Query. +$insql = "INSERT INTO $table (date,name,players,maxplayers,map,game,version,timeserver,timespeed,timespeedn,battleye,hive,connect,secure,ping) VALUES ('$date','$HostName','$Players','$MaxPlayers','$Map','$Game','$Version','2:20','2','4','battleye','hive','$urlserv','$Secure','666')"; +// Check if errors with SQL query if (mysqli_query($con, $insql)) { - echo "New record created successfully"; + // echo "New record created successfully"; } else { echo "Error: " . $insql . "
" . mysqli_error($con); } diff --git a/regex_statserver_json.php b/SQL/regex_statserver_json.php similarity index 99% rename from regex_statserver_json.php rename to SQL/regex_statserver_json.php index 6ca4720..b63ba18 100644 --- a/regex_statserver_json.php +++ b/SQL/regex_statserver_json.php @@ -14,7 +14,7 @@ include_once('config.php'); //include_once('consql.php'); //var_dump(json_decode($readjson)); - $urlserv = $ipserv.":".$portserv ; + $urlserv = $ipserv.":".$servport ; // librarie SQ - info serv game require 'SQ_/bootstrap.php'; diff --git a/table.sql b/SQL/table.sql similarity index 100% rename from table.sql rename to SQL/table.sql diff --git a/config.php b/config.php index 1d85c47..5cbb508 100644 --- a/config.php +++ b/config.php @@ -5,14 +5,14 @@ // Need to Edit this /* $ipserv = "103.58.149.102" ; // IP server game - $portserv = "2302" ; // Game Server Port + $servport = "2302" ; // Game Server Port $modport = "2312" ; // Mod port omega (+10) $queryport= "27016" ; // Queryport */ $ipserv = "82.64.214.194" ; // IP server game - $portserv = "3201" ; // Game Server Port + $servport = "3201" ; // Game Server Port $modport = "3211" ; // Mod port omega (+10) $queryport= "27001" ; // Queryport @@ -27,7 +27,7 @@ // Don't touch below - $urlserv = $ipserv.":".$portserv ; + $urlserv = $ipserv.":".$servport ; ?> diff --git a/consql.php b/consql.php index 31d7fdf..3f3118e 100644 --- a/consql.php +++ b/consql.php @@ -3,6 +3,7 @@ //# Change with your credential here. // Create Database first ;) + $servdb = "localhost"; $userdb = "user"; $pdb = "pass"; diff --git a/index.php b/index.php index 121d485..6c312aa 100644 --- a/index.php +++ b/index.php @@ -12,7 +12,7 @@ $sec = "300"; // Don't touch below (or you know what you do) - $urlserv = $ipserv.":".$portserv ; + $urlserv = $ipserv.":".$servport ; // need to fix if mod = 0 $json = file_get_contents("http://".$ipserv.":".$modport."/"); $objhigher=json_decode($json); //converts to an object @@ -251,11 +251,11 @@ $sec = "300"; // NEED to find a good regex for this shit! if (count($objlower) == 0){ // if no mod echo $InfoGT[67].$InfoGT[68].$InfoGT[69].$InfoGT[70].$InfoGT[71].$InfoGT[72].$InfoGT[73]; - echo "x". $InfoGT[42]. " - x".$InfoGT[55]." "; } + echo " x ". $InfoGT[42]. " - x ".$InfoGT[55]." "; } if (count($objlower) > 0) { echo $InfoGT[67].$InfoGT[68].$InfoGT[69].$InfoGT[70].$InfoGT[71].$InfoGT[72].$InfoGT[73].$InfoGT[74]; - echo "x". $InfoGT[41].$InfoGT[42].$InfoGT[43]. " - x".$InfoGT[54].$InfoGT[55].$InfoGT[56].""; + echo " x ". $InfoGT[41].$InfoGT[42].$InfoGT[43]. " - x ".$InfoGT[54].$InfoGT[55].$InfoGT[56].""; } /* @@ -451,24 +451,10 @@ $sec = "300";

- +
- -
-
-
- -
-
- (Databse is empty) -
-
-
@@ -483,6 +469,20 @@ $sec = "300";
+
+
+
+ +
+
+ (..) +
+
+
+
@@ -692,9 +692,9 @@ $sec = "300";
-
MAP
+
MAP
- +