1: <?php declare(strict_types=1);
2:
3: /**
4: * Clansuite Server Query
5: *
6: * SPDX-FileCopyrightText: 2003-2025 Jens A. Koch
7: * SPDX-License-Identifier: MIT
8: *
9: * For the full copyright and license information, please view
10: * the LICENSE file that was distributed with this source code.
11: */
12:
13: namespace Clansuite\ServerQuery\ServerProtocols;
14:
15: use function file_get_contents;
16: use function simplexml_load_string;
17: use function stream_context_create;
18: use Clansuite\Capture\Protocol\ProtocolInterface;
19: use Clansuite\Capture\ServerAddress;
20: use Clansuite\Capture\ServerInfo;
21: use Clansuite\ServerQuery\CSQuery;
22: use Override;
23:
24: /**
25: * Farming Simulator server protocol implementation.
26: *
27: * Farming Simulator uses HTTP API with XML response.
28: * Requires a token from the server settings page.
29: *
30: * @see https://github.com/ich777/farming-simulator-dedicated-server
31: */
32: class FarmingSimulator extends CSQuery implements ProtocolInterface
33: {
34: /**
35: * Protocol name.
36: */
37: public string $name = 'FarmingSimulator';
38:
39: /**
40: * Protocol identifier.
41: */
42: public string $protocol = 'farmingsimulator';
43:
44: /**
45: * Constructor.
46: */
47: public function __construct(mixed $address = null, mixed $queryport = null)
48: {
49: parent::__construct();
50: $this->address = $address !== null ? (string) $address : null;
51: $this->queryport = $queryport !== null ? (int) $queryport : null;
52: }
53:
54: /**
55: * query method.
56: */
57: #[Override]
58: public function query(ServerAddress $addr): ServerInfo
59: {
60: $info = new ServerInfo;
61: $info->online = false;
62:
63: if ($this->queryHTTP($addr, $info)) {
64: $info->online = true;
65: }
66:
67: return $info;
68: }
69:
70: /**
71: * getProtocolName method.
72: */
73: #[Override]
74: public function getProtocolName(): string
75: {
76: return $this->protocol;
77: }
78:
79: /**
80: * getVersion method.
81: */
82: #[Override]
83: public function getVersion(ServerInfo $info): string
84: {
85: return $info->gameversion ?? 'unknown';
86: }
87:
88: /**
89: * query_server method.
90: */
91: #[Override]
92: public function query_server(bool $getPlayers = true, bool $getRules = true): bool
93: {
94: // Use HTTP query
95: $addr = new ServerAddress($this->address ?? '', $this->queryport ?? 0);
96: $info = $this->query($addr);
97:
98: $this->online = $info->online;
99: $this->servertitle = $info->servertitle ?? '';
100: $this->mapname = $info->mapname ?? '';
101: $this->numplayers = $info->numplayers;
102: $this->maxplayers = $info->maxplayers;
103: $this->gamename = $info->gamename ?? '';
104: $this->gameversion = $info->gameversion ?? '';
105:
106: if ($getPlayers && $info->players !== []) {
107: $this->players = $info->players;
108: }
109:
110: if ($getRules && $info->rules !== []) {
111: $this->rules = $info->rules;
112: }
113:
114: return $this->online;
115: }
116:
117: private function queryHTTP(ServerAddress $addr, ServerInfo $info): bool
118: {
119: $host = $addr->ip;
120: $port = $addr->port;
121: // Note: token is required, but for example, we assume it's provided or use default
122: $token = 'example_token'; // In real use, get from server settings
123: $url = "http://{$host}:{$port}/feed/dedicated-server-stats.xml?code={$token}";
124:
125: $context = stream_context_create([
126: 'http' => [
127: 'timeout' => 5,
128: ],
129: ]);
130:
131: $response = @file_get_contents($url, false, $context);
132:
133: if ($response === false) {
134: return false;
135: }
136:
137: $xml = simplexml_load_string($response);
138:
139: if ($xml === false) {
140: return false;
141: }
142:
143: // Parse the XML data
144: $info->address = $addr->ip . ':' . $addr->port;
145: $info->queryport = $addr->port;
146: $info->gamename = 'Farming Simulator';
147: $info->servertitle = (string) $xml->Server['name'];
148: $info->mapname = (string) $xml->Server['mapName'];
149: $info->numplayers = (int) $xml->Server->Slots['numUsed'];
150: $info->maxplayers = (int) $xml->Server->Slots['capacity'];
151:
152: // Players
153: $players = [];
154:
155: foreach ($xml->Server->Slots->Player as $player) {
156: if ((string) $player['isUsed'] === 'true') {
157: $players[] = ['name' => (string) $player, 'score' => 0, 'time' => (int) $player['uptime']];
158: }
159: }
160: $info->players = $players;
161:
162: // Rules (server variables)
163: $rules = [];
164:
165: foreach ($xml->Server->attributes() as $key => $value) {
166: $rules[$key] = (string) $value;
167: }
168: $info->rules = $rules;
169:
170: return true;
171: }
172: }
173: