Skip to content

Commit 66d5565

Browse files
author
Thành Nhân
committed
...
1 parent 84d58ff commit 66d5565

7 files changed

Lines changed: 1045 additions & 0 deletions

File tree

‎LICENSE‎

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

‎README.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<h1>QueryServer<img src="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/NhanAZ/QueryServer/blob/master/icon.png" height="64" width="64" align="left"></img></h1><br/>
2+
3+
This is a plugin written in PHP programming language and running on the PocketMine platform that works stably on the API 4.0.0 platform. It allows you to query some other server information
4+
5+
<div align="center"> <b>Queryable information</b> </div>
6+
7+
<img src="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/NhanAZ/Images/blob/master/query_nethergames.png" />
8+
9+
# Contacts
10+
If you encounter an error or would like to contribute to my plugin, contact me via the platforms below:
11+
12+
- Zalo: @thanhnhanaz
13+
- Gmail: nhanaz@pm.me
14+
- Discord: NhanAZ#9115
15+
- FaceBook: fb.com/thanhnhanaz
16+
17+
# License
18+
[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html)

‎icon.png‎

5.64 KB
Loading

‎plugin.yml‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
name: QueryServer
3+
version: 0.0.1
4+
api: 4.0.0
5+
main: NhanAZ\QueryServer\Main
6+
website: https://github.com/NhanAZ
7+
description: Allow querying some other servers information
8+
commands:
9+
query:
10+
aliases: [qr]
11+
permission: query.cmd
12+
description: Querying some other server's information
13+
usage: /query <domain/ip:port> to query certain server information
14+
permission-message: §e>§c You do not have permission to use this command!
15+
querys:
16+
aliases: [qrs]
17+
permission: querys.cmd
18+
description: Querying some other server's information (Backup method)
19+
usage: "/querys <domain/ip : port> to query certain server information"
20+
permission-message: §e>§c You do not have permission to use this command!
21+
permissions:
22+
query.cmd:
23+
default: op
24+
description: Allow querying some other servers information
25+
querys.cmd:
26+
default: op
27+
description: Allow querying some other servers information (Backup method)
28+
...

‎src/Main.php‎

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NhanAZ\QueryServer;
6+
7+
use pocketmine\event\Listener;
8+
use pocketmine\plugin\PluginBase;
9+
10+
use pocketmine\command\Command;
11+
use pocketmine\command\CommandSender;
12+
13+
use NhanAZ\QueryServer\libs\libpmquery\PMQuery;
14+
use NhanAZ\QueryServer\libs\libpmquery\PmQueryException;
15+
16+
class Main extends PluginBase implements Listener
17+
{
18+
19+
public function onCommand(CommandSender $sender, Command $cmd, string $label, array $args) : bool
20+
{
21+
if ($cmd->getName() == "query") {
22+
if (!isset($args[0])) {
23+
$sender->sendMessage("§e>§c Usage: /query §b<domain/ip:port>§c to query certain server information");
24+
$sender->sendMessage("§e>§c Example: /query §b0.0.0.0:19132 §cor §b/query goole.com:19132");
25+
return true;
26+
}
27+
if (!$sender instanceof Player) {
28+
try {
29+
$status = json_decode(file_get_contents("https://api.mcsrvstat.us/2/" . $args[0]));
30+
} catch (\Exception $e) {
31+
$sender->sendMessage("§e>§f Error:§c Your IP does not open the port or the device does not match!");
32+
$sender->sendMessage("§e>§c Try another query method using §b/querys");
33+
return true;
34+
}
35+
if ($status->online == true) {
36+
$sender->sendMessage("§e>§f Domain:§a " . str_replace(":", "§f:§a",$args[0]));
37+
try {
38+
$sender->sendMessage("§e>§f IP/Port:§a " . $status->ip . "§f:§a" . $status->port);
39+
} catch (\Exception $e) {
40+
$sender->sendMessage("§e>§f IP/Port:§c Error or has blocked queries!");
41+
}
42+
try {
43+
$sender->sendMessage("§e>§f Ping:§a " . ($status->debug->ping ? "true" : "§cfalse"));
44+
} catch (\Exception $e) {
45+
$sender->sendMessage("§e>§f Ping:§c Error or has blocked queries!");
46+
}
47+
try {
48+
$sender->sendMessage("§e>§f Query:§a " . ($status->debug->query ? "true" : "§cfalse"));
49+
} catch (\Exception $e) {
50+
$sender->sendMessage("§e>§f Query:§c Error or has blocked queries!");
51+
}
52+
try {
53+
$sender->sendMessage("§e>§f SRV:§a " . ($status->debug->srv ? "true" : "§cfalse"));
54+
} catch (\Exception $e) {
55+
$sender->sendMessage("§e>§f SRV:§c Error or has blocked queries!");
56+
}
57+
try {
58+
$sender->sendMessage("§e>§f QueryMisMatch:§a " . ($status->debug->querymismatch ? "true" : "§cfalse"));
59+
} catch (\Exception $e) {
60+
$sender->sendMessage("§e>§f QueryMisMatch:§c Error or has blocked queries!");
61+
}
62+
try {
63+
$sender->sendMessage("§e>§f IPInSRV:§a " . ($status->debug->ipinsrv ? "true" : "§cfalse"));
64+
} catch (\Exception $e) {
65+
$sender->sendMessage("§e>§f IPInSRV:§c Error or has blocked queries!");
66+
}
67+
try {
68+
$sender->sendMessage("§e>§f CNameInSRV:§a " . ($status->debug->cnameinsrv ? "true" : "§cfalse"));
69+
} catch (\Exception $e) {
70+
$sender->sendMessage("§e>§f CNameInSRV:§c Error or has blocked queries!");
71+
}
72+
try {
73+
$sender->sendMessage("§e>§f AnimatedMotd:§a " . ($status->debug->animatedmotd ? "true" : "§cfalse"));
74+
} catch (\Exception $e) {
75+
$sender->sendMessage("§e>§f AnimatedMotd:§c Error or has blocked queries!");
76+
}
77+
try {
78+
$sender->sendMessage("§e>§f CacheTime:§a " . $status->debug->cachetime);
79+
} catch (\Exception $e) {
80+
$sender->sendMessage("§e>§f CacheTime:§c Error or has blocked queries!");
81+
}
82+
try {
83+
foreach ($status->motd->clean as $clean) {
84+
$sender->sendMessage("§e>§f Motd:§r ". $clean);
85+
}
86+
} catch (\Exception $e) {
87+
$sender->sendMessage("§e>§f Motd:§c Error or has blocked queries!");
88+
}
89+
try {
90+
$sender->sendMessage("§e>§f Online/Max:§a " . $status->players->online . "§f/§a" . $status->players->max);
91+
} catch (\Exception $e) {
92+
$sender->sendMessage("§e>§f Online/Max:§c Error or has blocked queries!");
93+
}
94+
try {
95+
$list = "§e>§f Players (".count($players->list)."): §a";
96+
foreach ($players->list as $lists) {
97+
$list .= $lists . "§f,§a ";
98+
}
99+
$sender->sendMessage($list);
100+
} catch (\Exception $e) {
101+
$sender->sendMessage("§e>§f Players:§c Error or has blocked queries!");
102+
}
103+
try {
104+
$uuid = "§e>§f UUIDS (".count($players->uuid)."): §a";
105+
foreach ($players->uuid as $uuids) {
106+
$uuid .= $uuids . "§f,§a ";
107+
}
108+
$sender->sendMessage($uuid);
109+
} catch (\Exception $e) {
110+
$sender->sendMessage("§e>§f UUIDS:§c Error or has blocked queries!");
111+
}
112+
try {
113+
$sender->sendMessage("§e>§f Version:§a " . (($status->version == null) ? "§cNull!" : $status->version));
114+
} catch (\Exception $e) {
115+
$sender->sendMessage("§e>§f Version:§c Error or has blocked queries!");
116+
}
117+
try {
118+
$sender->sendMessage("§e>§f protocol:§a " . $status->protocol);
119+
} catch (\Exception $e) {
120+
$sender->sendMessage("§e>§f Protocol:§c Error or has blocked queries!");
121+
}
122+
try {
123+
$sender->sendMessage("§e>§f HostName:§a " . $status->hostname);
124+
} catch (\Exception $e) {
125+
$sender->sendMessage("§e>§f HostName:§c Error or has blocked queries!");
126+
}
127+
try {
128+
$sender->sendMessage("§e>§f Icon:§a " . $status->icon);
129+
} catch (\Exception $e) {
130+
$sender->sendMessage("§e>§f Icon:§c Error or has blocked queries!");
131+
}
132+
try {
133+
$sender->sendMessage("§e>§f SoftWare:§a " . $status->software);
134+
} catch (\Exception $e) {
135+
$sender->sendMessage("§e>§f SoftWare:§c Error or has blocked queries!");
136+
}
137+
try {
138+
$sender->sendMessage("§e>§f Map:§a " . $status->map);
139+
} catch (\Exception $e) {
140+
$sender->sendMessage("§e>§f Map:§c Error or has blocked queries!");
141+
}
142+
try {
143+
$plugin = "§e>§f Plugins (".count($status->plugins->raw)."): §a";
144+
foreach ($status->plugins->raw as $raw) {
145+
$plugin .= str_replace(" ", " v", $raw) . "§f,§a ";
146+
}
147+
$sender->sendMessage($plugin);
148+
} catch (\Exception $e) {
149+
$sender->sendMessage("§e>§f Plugins:§c Error or has blocked queries!");
150+
}
151+
try {
152+
$mod = "§e>§f Mods (".count($status->mods->raw)."): §a";
153+
foreach ($status->mods->raw as $raw) {
154+
$mod .= $raw . "§f,§a ";
155+
}
156+
$sender->sendMessage($mod);
157+
} catch (\Exception $e) {
158+
$sender->sendMessage("§e>§f Mods:§c Error or has blocked queries!");
159+
}
160+
try {
161+
$info = "§e>§f Info (".count($status->info->clean)."): §a";
162+
foreach ($status->info->clean as $clean) {
163+
$info .= $clean . "§f,§a ";
164+
}
165+
$sender->sendMessage($info);
166+
} catch (\Exception $e) {
167+
$sender->sendMessage("§e>§f Info:§c Error or has blocked queries!");
168+
}
169+
if(strrchr($args[0], ":") == true) {
170+
$sender->sendMessage("§e>§f Below is the fallback query method:");
171+
try {
172+
$IP_Or_Domain_And_Port = explode(":", $args[0]);
173+
$IP_Or_Domain = $IP_Or_Domain_And_Port[0];
174+
$Port = $IP_Or_Domain_And_Port[1];
175+
$query = PMQuery::query($IP_Or_Domain, (int)$Port);
176+
$sender->sendMessage("§e>§f GameName:§a " . (($query["GameName"] == null) ? "§cNull!" : $query["GameName"]));
177+
$sender->sendMessage("§e>§f HostName:§r " . (($query["HostName"] == null) ? "§cNull!" : $query["HostName"]));
178+
$sender->sendMessage("§e>§f Protocol:§a " . (($query["Protocol"] == null) ? "§cNull!" : $query["Protocol"]));
179+
$sender->sendMessage("§e>§f Version:§a " . (($query["Version"] == null) ? "§cNull!" : $query["Version"]));
180+
$sender->sendMessage("§e>§f Players:§a " .(($query["Players"] == null) ? "§cNull!" : $query["Players"]));
181+
$sender->sendMessage("§e>§f MaxPlayers:§a " . (($query["MaxPlayers"] == null) ? "§cNull!" : $query["MaxPlayers"]));
182+
$sender->sendMessage("§e>§f ServerId:§a " . (($query["ServerId"] == null) ? "§cNull!" : $query["ServerId"]));
183+
$sender->sendMessage("§e>§f Map:§a " . (($query["Map"] == null) ? "§cNull!" : $query["Map"]));
184+
$sender->sendMessage("§e>§f GameMode:§a " . (($query["GameMode"] == null) ? "§cNull!" : $query["GameMode"]));
185+
$sender->sendMessage("§e>§f NintendoLimited:§a " . (($query["NintendoLimited"] == null) ? "§cNull!" : $query["NintendoLimited"]));
186+
$sender->sendMessage("§e>§f IPv4Port:§a " . (($query["IPv4Port"] == null) ? "§cNull!" : $query["IPv4Port"]));
187+
$sender->sendMessage("§e>§f IPv6Port:§a " . (($query["IPv6Port"] == null) ? "§cNull!" : $query["IPv6Port"]));
188+
$sender->sendMessage("§e>§f Extra:§a " . (($query["Extra"] == null) ? "§cNull!" : $query["Extra"]));
189+
} catch(PmQueryException $e) {
190+
$sender->sendMessage("§e>§c The server is offline or has blocked queries!");
191+
$sender->sendMessage("§e>§f Possible error:§c Your IP does not open the port or the device does not match!");
192+
}
193+
}
194+
} else {
195+
$sender->sendMessage("§e>§c The server is offline or has blocked queries!");
196+
$sender->sendMessage("§e>§c Try another query method using §b/querys");
197+
}
198+
} else {
199+
$sender->sendMessage("§e>§c Please use the command on the console!");
200+
}
201+
return true;
202+
}
203+
if ($cmd->getName() == "querys") {
204+
if ($sender instanceof Player) {
205+
$sender->sendMessage("§e>§c Please use the command on the console!");
206+
return true;
207+
}
208+
if (!isset($args[0])) {
209+
$sender->sendMessage("§e>§f Error:§c You have not entered the IP/Domain of the server you want to query!");
210+
$sender->sendMessage("§e>§c Usage: /query §b<domain/ip> <port>§c to query certain server information");
211+
$sender->sendMessage("§e>§c Example: /query §b0.0.0.0 19132 §cor §b/query goole.com 19132");
212+
return true;
213+
}
214+
if (!isset($args[1])) {
215+
$sender->sendMessage("§e>§f Error:§c You have not entered the Port of the server you want to query!");
216+
$sender->sendMessage("§e>§c Usage: /query §b<domain/ip> <port>§c to query certain server information");
217+
$sender->sendMessage("§e>§c Example: /query §b0.0.0.0 19132 §cor §b/query goole.com 19132");
218+
return true;
219+
}
220+
try {
221+
$query = PMQuery::query($args[0], (int)$args[1]);
222+
$sender->sendMessage("§e>§f GameName:§a " . (($query["GameName"] == null) ? "§cNull!" : $query["GameName"]));
223+
$sender->sendMessage("§e>§f HostName:§r " . (($query["HostName"] == null) ? "§cNull!" : $query["HostName"]));
224+
$sender->sendMessage("§e>§f Protocol:§a " . (($query["Protocol"] == null) ? "§cNull!" : $query["Protocol"]));
225+
$sender->sendMessage("§e>§f Version:§a " . (($query["Version"] == null) ? "§cNull!" : $query["Version"]));
226+
$sender->sendMessage("§e>§f Players:§a " .(($query["Players"] == null) ? "§cNull!" : $query["Players"]));
227+
$sender->sendMessage("§e>§f MaxPlayers:§a " . (($query["MaxPlayers"] == null) ? "§cNull!" : $query["MaxPlayers"]));
228+
$sender->sendMessage("§e>§f ServerId:§a " . (($query["ServerId"] == null) ? "§cNull!" : $query["ServerId"]));
229+
$sender->sendMessage("§e>§f Map:§a " . (($query["Map"] == null) ? "§cNull!" : $query["Map"]));
230+
$sender->sendMessage("§e>§f GameMode:§a " . (($query["GameMode"] == null) ? "§cNull!" : $query["GameMode"]));
231+
$sender->sendMessage("§e>§f NintendoLimited:§a " . (($query["NintendoLimited"] == null) ? "§cNull!" : $query["NintendoLimited"]));
232+
$sender->sendMessage("§e>§f IPv4Port:§a " . (($query["IPv4Port"] == null) ? "§cNull!" : $query["IPv4Port"]));
233+
$sender->sendMessage("§e>§f IPv6Port:§a " . (($query["IPv6Port"] == null) ? "§cNull!" : $query["IPv6Port"]));
234+
$sender->sendMessage("§e>§f Extra:§a " . (($query["Extra"] == null) ? "§cNull!" : $query["Extra"]));
235+
} catch(PmQueryException $e) {
236+
$sender->sendMessage("§e>§c The server is offline or has blocked queries!");
237+
$sender->sendMessage("§e>§f Possible error:§c Your IP does not open the port or the device does not match!");
238+
}
239+
return true;
240+
}
241+
}
242+
}

‎src/libs/libpmquery/PMQuery.php‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace NhanAZ\QueryServer\libs\libpmquery;
4+
5+
use NhanAZ\QueryServer\libs\libpmquery\PmQueryException;
6+
7+
8+
class PMQuery {
9+
/**
10+
* @param string $host Ip/dns address being queried
11+
* @param int $port Port on the ip being queried
12+
* @param int $timeout Seconds before socket times out
13+
*
14+
* @return string[]|int[]
15+
* @throws PmQueryException
16+
*/
17+
public static function query(string $host, int $port, int $timeout = 4) {
18+
$socket = @fsockopen('udp://'.$host, $port, $errno, $errstr, $timeout);
19+
20+
if($errno and $socket !== false) {
21+
fclose($socket);
22+
throw new PmQueryException($errstr, $errno);
23+
}elseif($socket === false) {
24+
throw new PmQueryException($errstr, $errno);
25+
}
26+
27+
stream_Set_Timeout($socket, $timeout);
28+
stream_Set_Blocking($socket, true);
29+
30+
// hardcoded magic https://github.com/facebookarchive/RakNet/blob/1a169895a900c9fc4841c556e16514182b75faf8/Source/RakPeer.cpp#L135
31+
$OFFLINE_MESSAGE_DATA_ID = \pack('c*', 0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78);
32+
$command = \pack('cQ', 0x01, time()); // DefaultMessageIDTypes::ID_UNCONNECTED_PING + 64bit current time
33+
$command .= $OFFLINE_MESSAGE_DATA_ID;
34+
$command .= \pack('Q', 2); // 64bit guid
35+
$length = \strlen($command);
36+
37+
if($length !== fwrite($socket, $command, $length)) {
38+
throw new PmQueryException("Failed to write on socket.", E_WARNING);
39+
}
40+
41+
$data = fread($socket, 4096);
42+
43+
fclose($socket);
44+
45+
if(empty($data) or $data === false) {
46+
throw new PmQueryException("Server failed to respond", E_WARNING);
47+
}
48+
if(substr($data, 0, 1) !== "\x1C") {
49+
throw new PmQueryException("First byte is not ID_UNCONNECTED_PONG.", E_WARNING);
50+
}
51+
if(substr($data, 17, 16) !== $OFFLINE_MESSAGE_DATA_ID) {
52+
throw new PmQueryException("Magic bytes do not match.");
53+
}
54+
55+
// TODO: What are the 2 bytes after the magic?
56+
$data = \substr($data, 35);
57+
58+
// TODO: If server-name contains a ';' it is not escaped, and will break this parsing
59+
$data = \explode(';', $data);
60+
61+
return [
62+
'GameName' => $data[0] ?? null,
63+
'HostName' => $data[1] ?? null,
64+
'Protocol' => $data[2] ?? null,
65+
'Version' => $data[3] ?? null,
66+
'Players' => $data[4] ?? null,
67+
'MaxPlayers' => $data[5] ?? null,
68+
'ServerId' => $data[6] ?? null,
69+
'Map' => $data[7] ?? null,
70+
'GameMode' => $data[8] ?? null,
71+
'NintendoLimited' => $data[9] ?? null,
72+
'IPv4Port' => $data[10] ?? null,
73+
'IPv6Port' => $data[11] ?? null,
74+
'Extra' => $data[12] ?? null, // TODO: What's in this?
75+
];
76+
}
77+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
namespace NhanAZ\QueryServer\libs\libpmquery;
4+
5+
class PmQueryException extends \Exception{
6+
}

0 commit comments

Comments
 (0)