forked from c9jester/q3tool
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathq3tool.php
More file actions
executable file
·206 lines (195 loc) · 5.65 KB
/
Copy pathq3tool.php
File metadata and controls
executable file
·206 lines (195 loc) · 5.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<?php
// Create the class
class q3tool
{
// A couple of local vars to use
private $password;
public $player_data = array();
public $server_data = array();
// Class constructor
public function __construct($server, $port = 27960, $password = "")
{
// Construction ahead.
// Set the password and cache the server info
$this->password = $password;
$this->cache_info($server, $port);
}
// Pulls the data from the server and stores it
// This means fewer actual queries
// This is a good thing.
private function cache_info($server, $port)
{
// Socket to read/write
$socket = fsockopen("udp://$server", $port, $errno, $errstr, 1);
// Send the special message
fwrite($socket, "\xFF\xFF\xFF\xFFgetstatus");
// And retrieve the server's response
$response = fread($socket, 2048);
// Explode the response into an array containing header, server info, players, footer
$sections = explode("\n", $response);
// Remove the header/footer (they're useless)
array_shift($sections);
array_pop($sections);
// Remove the server info from the player list and store it
$server_chunk = array_shift($sections);
// Explode the server info into an array and remove the first (empty) element
$server_bits = explode("\\", $server_chunk);
array_shift($server_bits);
// Every other element is a key or value
// ex. "g_gametype\4\sv_maxclients\40" becomes $server_data["g_gametype"] = 4 & $server_data["sv_maxclients"] = 40
for($i = 0; $i <= count($server_bits) - 1; $i = $i + 2)
{
$key = $server_bits[$i];
$key = str_replace(' ', '', $key);
$value = $server_bits[$i+1];
$value = preg_replace('/\^[0-9]{1}/', '', $value);
$this->server_data[$key] = $value;
}
// Turn the player list string into an array
// ex. [0] ( "name" => "{C9}Jester", "ping" => "50", score => "9001" )
foreach($sections as $raw_player)
{
// Create an array from the player string
// The player string is "<score> <ping> <name>"
// So the array is: [0] = <score>, [1] = <ping>, [2] = <name>
$player = explode(" ", $raw_player);
// Remove any color codes from names
// They just make things hard to read if you leave them in
$name = preg_replace('/\^[0-9]{1}/', '', $player[2]);
// Push the player's info into the $playerdata array
// So each element in $playerdata is an array with the player's name, ping
// So the first element could be something like this:
// $playerdata[0]['name'] = "{C9}Jester", $playerdata[0]['ping'] = 57, $playerdata[0]['score'] = -1
array_push($this->player_data, array("name"=>$name, "ping"=>$player[1], "score"=>$player[0]));
}
}
// Retrives various bits of information about the server (map, hostname, etc)
public function get_info($info)
{
$server_data = &$this->server_data;
$player_data = &$this->player_data;
// Figure out what info we're looking to retrieve, then return it
switch($info)
{
case "players":
// Gives the number of elements in $playerdata (eg. the number of players)
return count($player_data);
break;
case "playerlist":
// Gives the list of players (with each player's name, ping, and score)
return $player_data;
break;
case "map":
return $server_data["mapname"];
break;
case "maxplayers":
return $server_data["sv_maxclients"];
break;
// For convenience, we parse the gametype int into a string
// The g_gametype key can still be used for a raw gametype int
case "gametype":
switch($server_data["g_gametype"])
{
case 0:
$gametype = "Free For All";
break;
case 3:
$gametype = "Team Deathmatch";
break;
case 4:
$gametype = "Team Survivor";
break;
case 5:
$gametype = "Follow The Leader";
break;
case 6:
$gametype = "Capture & Hold";
break;
case 7:
$gametype = "Capture The Flag";
break;
case 8:
$gametype = "Bomb Mode";
break;
default:
$gametype = "Unreconized gametype";
break;
}
return $gametype;
break;
// This is just a shorter gametype string
case "sgametype":
switch($server_data["g_gametype"])
{
case 0:
$gametype = "FFA";
break;
case 3:
$gametype = "TDM";
break;
case 4:
$gametype = "TS";
break;
case 5:
$gametype = "FTL";
break;
case 6:
$gametype = "C&H";
break;
case 7:
$gametype = "CTF";
break;
case 8:
$gametype = "BOMB";
break;
default:
$gametype = "Unrecognized gametype";
break;
}
return $gametype;
break;
case "name":
return $server_data["sv_hostname"];
break;
case "gear":
return $server_data["g_gear"];
break;
case "redname":
return $server_data["g_teamnamered"];
break;
case "bluename":
return $server_data["g_teamnameblue"];
break;
// If none of the above, check to see that the provided key exists
// If it does, return the info, if not, return an error message
default:
if(array_key_exists($info, $server_data))
{
return $server_data[$info];
}
else
{
return "UNRECOGNIZED KEY";
}
break;
}
}
// Check to see if an RCON password was given
// And if it was, send a command to the server
// If not, remind the user
public function send_rcon($command)
{
if(!empty($this->password))
{
$socket = fsockopen("udp://".$this->server, $this->port, $errno, $errstr, 1);
fwrite($socket, "\xFF\xFF\xFF\xFFrcon ".$this->password." $command");
$response = fread($socket, 2048);
return $response;
}
else
{
return "RCON password not supplied";
}
}
}
?>