1: <?php
2: /**
3: * This file is part of GameQ.
4: *
5: * GameQ is free software; you can redistribute it and/or modify
6: * it under the terms of the GNU Lesser General Public License as published by
7: * the Free Software Foundation; either version 3 of the License, or
8: * (at your option) any later version.
9: *
10: * GameQ is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: * GNU Lesser General Public License for more details.
14: *
15: * You should have received a copy of the GNU Lesser General Public License
16: * along with this program. If not, see <http://www.gnu.org/licenses/>.
17: */
18: namespace GameQ\Protocols;
19:
20: use GameQ\Exception\Protocol as Exception;
21: use GameQ\Result;
22:
23: /**
24: * Tshock Protocol Class
25: *
26: * Result from this call should be a header + JSON response
27: *
28: * References:
29: * - https://tshock.atlassian.net/wiki/display/TSHOCKPLUGINS/REST+API+Endpoints#RESTAPIEndpoints-/status
30: * - http://tshock.co/xf/index.php?threads/rest-tshock-server-status-image.430/
31: *
32: * Special thanks to intradox and Ruok2bu for game & protocol references
33: *
34: * @author Austin Bischoff <austin@codebeard.com>
35: */
36: class Tshock extends Http
37: {
38: /**
39: * Packets to send
40: *
41: * @var array
42: */
43: protected $packets = [
44: self::PACKET_STATUS => "GET /v2/server/status?players=true&rules=true HTTP/1.0\r\nAccept: */*\r\n\r\n",
45: ];
46:
47: /**
48: * The protocol being used
49: *
50: * @var string
51: */
52: protected $protocol = 'tshock';
53:
54: /**
55: * String name of this protocol class
56: *
57: * @var string
58: */
59: protected $name = 'tshock';
60:
61: /**
62: * Longer string name of this protocol class
63: *
64: * @var string
65: */
66: protected $name_long = "Tshock";
67:
68: /**
69: * Normalize some items
70: *
71: * @var array
72: */
73: protected $normalize = [
74: // General
75: 'general' => [
76: // target => source
77: 'dedicated' => 'dedicated',
78: 'hostname' => 'hostname',
79: 'mapname' => 'world',
80: 'maxplayers' => 'maxplayers',
81: 'numplayers' => 'numplayers',
82: 'password' => 'password',
83: ],
84: // Individual
85: 'player' => [
86: 'name' => 'nickname',
87: 'team' => 'team',
88: ],
89: ];
90:
91: /**
92: * Process the response
93: *
94: * @return array
95: * @throws Exception
96: */
97: public function processResponse()
98: {
99: if (empty($this->packets_response)) {
100: return [];
101: }
102:
103: // Implode and rip out the JSON
104: preg_match('/\{(.*)\}/ms', implode('', $this->packets_response), $matches);
105:
106: // Return should be JSON, let's validate
107: if (!isset($matches[0]) || ($json = json_decode($matches[0])) === null) {
108: throw new Exception("JSON response from Tshock protocol is invalid.");
109: }
110:
111: // Check the status response
112: if ($json->status != 200) {
113: throw new Exception("JSON status from Tshock protocol response was '{$json->status}', expected '200'.");
114: }
115:
116: $result = new Result();
117:
118: // Server is always dedicated
119: $result->add('dedicated', 1);
120:
121: // Add server items
122: $result->add('hostname', $json->name);
123: $result->add('game_port', $json->port);
124: $result->add('serverversion', $json->serverversion);
125: $result->add('world', $json->world);
126: $result->add('uptime', $json->uptime);
127: $result->add('password', (int)$json->serverpassword);
128: $result->add('numplayers', $json->playercount);
129: $result->add('maxplayers', $json->maxplayers);
130:
131: // Parse players
132: foreach ($json->players as $player) {
133: $result->addPlayer('nickname', $player->nickname);
134: $result->addPlayer('username', $player->username);
135: $result->addPlayer('group', $player->group);
136: $result->addPlayer('active', (int)$player->active);
137: $result->addPlayer('state', $player->state);
138: $result->addPlayer('team', $player->team);
139: }
140:
141: // Make rules into simple array
142: $rules = [];
143:
144: // Parse rules
145: foreach ($json->rules as $rule => $value) {
146: // Add rule but convert boolean into int (0|1)
147: $rules[$rule] = (is_bool($value)) ? (int)$value : $value;
148: }
149:
150: // Add rules
151: $result->add('rules', $rules);
152:
153: unset($rules, $rule, $player, $value);
154:
155: return $result->fetch();
156: }
157: }
158: