Skip to content

Commit 7eab204

Browse files
committed
feat: move game-specific fields from servers table to game settings tables
Move admin_password, verify_signatures, allowed_file_patching, battle_eye, persistent, von_enabled, and additional_server_options off the shared Server model into their respective game settings tables (arma3_settings, reforger_settings, project_zomboid_settings). Introduce HasQueryPort marker interface (implemented by Arma3, Reforger, PZ, Factorio) so query_port stays on Server but is nullable for games that don't use it. Add auto_restart validation in form requests conditioned on DetectsServerState. The frontend is entirely schema-driven via the source property, so no frontend changes are needed.
1 parent 580a372 commit 7eab204

22 files changed

Lines changed: 241 additions & 93 deletions

app/Contracts/HasQueryPort.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace App\Contracts;
4+
5+
/**
6+
* Marker interface for game handlers that use a configurable Steam query port.
7+
*
8+
* Handlers implementing this will have `query_port` validated and persisted
9+
* on the Server model. Non-implementing handlers will have a null query_port.
10+
*/
11+
interface HasQueryPort {}

app/GameHandlers/Arma3Handler.php

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Contracts\DetectsServerState;
66
use App\Contracts\GameHandler;
7+
use App\Contracts\HasQueryPort;
78
use App\Contracts\ManagesModAssets;
89
use App\Contracts\SteamGameHandler;
910
use App\Contracts\SupportsBackups;
@@ -16,7 +17,7 @@
1617
use Illuminate\Support\Facades\Log;
1718
use Illuminate\Validation\Rule;
1819

19-
final class Arma3Handler implements DetectsServerState, GameHandler, ManagesModAssets, SteamGameHandler, SupportsBackups, SupportsHeadlessClients, SupportsMissions
20+
final class Arma3Handler implements DetectsServerState, GameHandler, HasQueryPort, ManagesModAssets, SteamGameHandler, SupportsBackups, SupportsHeadlessClients, SupportsMissions
2021
{
2122
public function __construct(
2223
protected TwigConfigRenderer $configRenderer,
@@ -310,18 +311,17 @@ public function settingsSchema(): array
310311
'title' => 'Server Rules',
311312
'showOnCreate' => true,
312313
'createLabel' => 'Arma 3 Options',
313-
'source' => 'server',
314+
'source' => 'arma3_settings',
314315
'fields' => [
315-
['key' => 'query_port', 'label' => 'Steam Query Port', 'type' => 'number', 'default' => $this->defaultQueryPort(), 'min' => 1, 'max' => 65535, 'description' => 'Steam server browser query port. Typically game port + 1.'],
316-
['key' => 'password', 'label' => 'Server Password', 'type' => 'text', 'default' => '', 'placeholder' => 'Leave empty for no password'],
316+
['key' => 'query_port', 'label' => 'Steam Query Port', 'type' => 'number', 'default' => $this->defaultQueryPort(), 'min' => 1, 'max' => 65535, 'description' => 'Steam server browser query port. Typically game port + 1.', 'source' => 'server'],
317+
['key' => 'password', 'label' => 'Server Password', 'type' => 'text', 'default' => '', 'placeholder' => 'Leave empty for no password', 'source' => 'server'],
317318
['key' => 'admin_password', 'label' => 'Admin Password', 'type' => 'text', 'default' => '', 'placeholder' => 'In-game admin password'],
318319
['type' => 'separator'],
319320
['key' => 'verify_signatures', 'label' => 'Verify Signatures', 'type' => 'toggle', 'default' => true],
320321
['key' => 'allowed_file_patching', 'label' => 'Allow File Patching', 'type' => 'toggle', 'default' => false],
321322
['key' => 'battle_eye', 'label' => 'BattlEye Anti-Cheat', 'type' => 'toggle', 'default' => true],
322323
['key' => 'von_enabled', 'label' => 'Voice Over Network', 'type' => 'toggle', 'default' => true],
323324
['key' => 'persistent', 'label' => 'Persistent Server', 'type' => 'toggle', 'default' => false],
324-
['key' => 'auto_restart', 'label' => 'Auto-Restart on Crash', 'type' => 'toggle', 'default' => false],
325325
],
326326
],
327327

@@ -478,7 +478,7 @@ public function settingsSchema(): array
478478
'advanced' => true,
479479
'fields' => [
480480
['key' => 'additional_params', 'label' => 'Additional Launch Parameters', 'type' => 'textarea', 'default' => '', 'rows' => 2, 'placeholder' => '-loadMissionToMemory -enableHT', 'source' => 'server'],
481-
['key' => 'additional_server_options', 'label' => 'Additional server.cfg Options', 'type' => 'textarea', 'default' => '', 'rows' => 3, 'placeholder' => 'Raw config directives appended to server.cfg'],
481+
['key' => 'additional_server_options', 'label' => 'Additional server.cfg Options', 'type' => 'textarea', 'default' => '', 'rows' => 3, 'placeholder' => 'Raw config directives appended to server.cfg', 'source' => 'arma3_settings'],
482482
],
483483
],
484484
];
@@ -502,21 +502,22 @@ public function serverValidationRules(?Server $server = null): array
502502
Rule::unique('servers', 'port')->when($server, fn ($rule) => $rule->ignore($server->id)),
503503
],
504504
'password' => ['nullable', 'string', 'max:255'],
505+
'additional_params' => ['nullable', 'string', 'max:1000'],
506+
];
507+
}
508+
509+
public function settingsValidationRules(): array
510+
{
511+
return [
512+
// Server options (on arma3_settings)
505513
'admin_password' => ['nullable', 'string', 'max:255'],
506-
'auto_restart' => ['boolean'],
507514
'verify_signatures' => ['boolean'],
508515
'allowed_file_patching' => ['boolean'],
509516
'battle_eye' => ['boolean'],
510517
'persistent' => ['boolean'],
511518
'von_enabled' => ['boolean'],
512-
'additional_params' => ['nullable', 'string', 'max:1000'],
513519
'additional_server_options' => ['nullable', 'string'],
514-
];
515-
}
516520

517-
public function settingsValidationRules(): array
518-
{
519-
return [
520521
// Difficulty settings
521522
'reduced_damage' => ['boolean'],
522523
'group_indicators' => ['integer', 'between:0,2'],
@@ -636,21 +637,22 @@ protected function getModNames(Server $server): array
636637
protected function generateServerConfig(Server $server): void
637638
{
638639
$renderer = $this->configRenderer;
640+
$settings = $server->arma3Settings ?? $this->getDefaultSettings();
639641

640642
$content = $renderer->render('arma3/server.cfg.twig', [
641643
'hostname' => addslashes($server->name),
642644
'password' => addslashes((string) $server->password),
643-
'admin_password' => addslashes((string) $server->admin_password),
645+
'admin_password' => addslashes((string) $settings->admin_password),
644646
'max_players' => (int) $server->max_players,
645-
'verify_signatures' => $server->verify_signatures ? 2 : 0,
646-
'allowed_file_patching' => $server->allowed_file_patching ? 2 : 0,
647-
'disable_von' => $server->von_enabled ? 0 : 1,
648-
'persistent' => $server->persistent ? 1 : 0,
649-
'battle_eye' => $server->battle_eye ? 1 : 0,
647+
'verify_signatures' => $settings->verify_signatures ? 2 : 0,
648+
'allowed_file_patching' => $settings->allowed_file_patching ? 2 : 0,
649+
'disable_von' => $settings->von_enabled ? 0 : 1,
650+
'persistent' => $settings->persistent ? 1 : 0,
651+
'battle_eye' => $settings->battle_eye ? 1 : 0,
650652
'motd_lines' => $server->description
651653
? array_map(fn (string $line) => addslashes(trim($line)), explode("\n", $server->description))
652654
: null,
653-
'additional_server_options' => $server->additional_server_options ?: null,
655+
'additional_server_options' => $settings->additional_server_options ?: null,
654656
]);
655657

656658
file_put_contents(
@@ -739,6 +741,14 @@ protected function generateProfileConfig(Server $server): void
739741
protected function getDefaultSettings(): Arma3Settings
740742
{
741743
$settings = new Arma3Settings;
744+
// Server option defaults
745+
$settings->admin_password = null;
746+
$settings->verify_signatures = true;
747+
$settings->allowed_file_patching = false;
748+
$settings->battle_eye = true;
749+
$settings->persistent = false;
750+
$settings->von_enabled = true;
751+
$settings->additional_server_options = null;
742752
// Difficulty defaults
743753
$settings->reduced_damage = false;
744754
$settings->group_indicators = 2;

app/GameHandlers/FactorioHandler.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
use App\Contracts\DetectsServerState;
66
use App\Contracts\DownloadsDirectly;
77
use App\Contracts\GameHandler;
8+
use App\Contracts\HasQueryPort;
89
use App\Models\FactorioSettings;
910
use App\Models\ModPreset;
1011
use App\Models\Server;
1112
use App\Services\Renderer\JsonConfigRenderer;
1213
use Illuminate\Support\Facades\Log;
1314
use Illuminate\Support\Facades\Process;
1415

15-
final class FactorioHandler implements DetectsServerState, DownloadsDirectly, GameHandler
16+
final class FactorioHandler implements DetectsServerState, DownloadsDirectly, GameHandler, HasQueryPort
1617
{
1718
public function __construct(
1819
protected JsonConfigRenderer $configRenderer,

app/GameHandlers/ProjectZomboidHandler.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44

55
use App\Contracts\DetectsServerState;
66
use App\Contracts\GameHandler;
7+
use App\Contracts\HasQueryPort;
78
use App\Contracts\SteamGameHandler;
89
use App\Models\ModPreset;
910
use App\Models\ProjectZomboidSettings;
1011
use App\Models\Server;
1112
use App\Services\Renderer\TwigConfigRenderer;
1213

13-
final class ProjectZomboidHandler implements DetectsServerState, GameHandler, SteamGameHandler
14+
final class ProjectZomboidHandler implements DetectsServerState, GameHandler, HasQueryPort, SteamGameHandler
1415
{
1516
public function __construct(
1617
protected TwigConfigRenderer $configRenderer,
@@ -78,11 +79,13 @@ public function buildLaunchCommand(Server $server): array
7879
$profileName = $this->getProfileName($server);
7980
$cachedir = $server->getProfilesPath();
8081

82+
$settings = $server->projectzomboidSettings;
83+
8184
$params = [
8285
$binary,
8386
'-servername', $profileName,
8487
'-cachedir='.$cachedir,
85-
'-adminpassword', $server->admin_password,
88+
'-adminpassword', $settings?->admin_password ?? '',
8689
];
8790

8891
if ($server->additional_params) {
@@ -152,7 +155,7 @@ public function settingsSchema(): array
152155
'createLabel' => 'Project Zomboid Options',
153156
'fields' => [
154157
['key' => 'password', 'label' => 'Server Password', 'type' => 'text', 'default' => '', 'placeholder' => 'Leave empty for no password', 'source' => 'server'],
155-
['key' => 'admin_password', 'label' => 'Admin Password', 'type' => 'text', 'default' => '', 'placeholder' => 'Required for server startup', 'required' => true, 'source' => 'server'],
158+
['key' => 'admin_password', 'label' => 'Admin Password', 'type' => 'text', 'default' => '', 'placeholder' => 'Required for server startup', 'required' => true, 'source' => 'projectzomboid_settings'],
156159
['type' => 'separator'],
157160
['key' => 'open', 'label' => 'Public Server', 'type' => 'toggle', 'default' => true, 'source' => 'projectzomboid_settings', 'description' => 'Show in the public server browser.'],
158161
['key' => 'pvp', 'label' => 'PVP', 'type' => 'toggle', 'default' => true, 'source' => 'projectzomboid_settings'],
@@ -197,14 +200,14 @@ public function serverValidationRules(?Server $server = null): array
197200
{
198201
return [
199202
'password' => ['nullable', 'string', 'max:255'],
200-
'admin_password' => ['required', 'string', 'max:255'],
201203
'additional_params' => ['nullable', 'string', 'max:1000'],
202204
];
203205
}
204206

205207
public function settingsValidationRules(): array
206208
{
207209
return [
210+
'admin_password' => ['required', 'string', 'max:255'],
208211
'pvp' => ['boolean'],
209212
'pause_empty' => ['boolean'],
210213
'global_chat' => ['boolean'],

app/GameHandlers/ReforgerHandler.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Contracts\DetectsServerState;
66
use App\Contracts\GameHandler;
7+
use App\Contracts\HasQueryPort;
78
use App\Contracts\SteamGameHandler;
89
use App\Contracts\SupportsRegisteredMods;
910
use App\Contracts\SupportsScenarios;
@@ -16,7 +17,7 @@
1617
use App\Services\Renderer\JsonConfigRenderer;
1718
use Illuminate\Database\Eloquent\Model;
1819

19-
final class ReforgerHandler implements DetectsServerState, GameHandler, SteamGameHandler, SupportsRegisteredMods, SupportsScenarios, WritesNativeLogs
20+
final class ReforgerHandler implements DetectsServerState, GameHandler, HasQueryPort, SteamGameHandler, SupportsRegisteredMods, SupportsScenarios, WritesNativeLogs
2021
{
2122
public function __construct(
2223
protected JsonConfigRenderer $configRenderer,
@@ -121,7 +122,7 @@ public function generateConfigFiles(Server $server): void
121122
'game' => [
122123
'name' => $server->name,
123124
'password' => (string) $server->password,
124-
'passwordAdmin' => (string) $server->admin_password,
125+
'passwordAdmin' => (string) ($settings?->admin_password ?? ''),
125126
'scenarioId' => $settings?->scenario_id ?? '',
126127
'maxPlayers' => (int) $server->max_players,
127128
'visible' => true,
@@ -132,7 +133,7 @@ public function generateConfigFiles(Server $server): void
132133
'networkViewDistance' => 1000,
133134
'disableThirdPerson' => ! $thirdPersonEnabled,
134135
'fastValidation' => true,
135-
'battlEye' => $server->battle_eye,
136+
'battlEye' => $settings?->battle_eye ?? true,
136137
'VONDisableUI' => true,
137138
'VONDisableDirectSpeechUI' => true,
138139
],
@@ -216,8 +217,9 @@ public function settingsSchema(): array
216217
'source' => 'reforger_settings',
217218
'fields' => [
218219
['key' => 'scenario_id', 'label' => 'Scenario ID', 'type' => 'custom', 'component' => 'scenario-picker', 'default' => ''],
220+
['key' => 'admin_password', 'label' => 'Admin Password', 'type' => 'text', 'default' => '', 'placeholder' => 'In-game admin password'],
219221
['key' => 'third_person_view_enabled', 'label' => 'Third Person View', 'type' => 'toggle', 'default' => true],
220-
['key' => 'battle_eye', 'label' => 'BattlEye Anti-Cheat', 'type' => 'toggle', 'default' => true, 'source' => 'server'],
222+
['key' => 'battle_eye', 'label' => 'BattlEye Anti-Cheat', 'type' => 'toggle', 'default' => true],
221223
['key' => 'cross_platform', 'label' => 'Cross-Platform', 'type' => 'toggle', 'default' => false],
222224
['key' => 'max_fps', 'label' => 'Max FPS', 'type' => 'number', 'default' => 60, 'min' => 10, 'max' => 240, 'description' => 'Recommended: 60-120. Limits server tick rate to prevent excessive CPU usage.'],
223225
],
@@ -229,14 +231,14 @@ public function settingsSchema(): array
229231

230232
public function serverValidationRules(?Server $server = null): array
231233
{
232-
return [
233-
'battle_eye' => ['boolean'],
234-
];
234+
return [];
235235
}
236236

237237
public function settingsValidationRules(): array
238238
{
239239
return [
240+
'admin_password' => ['nullable', 'string', 'max:255'],
241+
'battle_eye' => ['boolean'],
240242
'scenario_id' => ['nullable', 'string', 'regex:/^\{[0-9A-F]{16}\}[a-zA-Z0-9_.\/ -]+$/'],
241243
'third_person_view_enabled' => ['boolean'],
242244
'max_fps' => ['integer', 'min:10', 'max:240'],

app/Http/Controllers/ServerController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public function index(): Response
4848
->orderBy('name')
4949
->get()
5050
->each(function (Server $server): void {
51-
$server->makeVisible(['password', 'admin_password']);
51+
$server->makeVisible(['password']);
5252
$server->setAttribute('supports_backups', $this->gameManager->for($server) instanceof SupportsBackups);
5353
$server->setAttribute('profiles_path', $server->getProfilesPath());
5454
});

app/Http/Requests/Server/StoreServerRequest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Http\Requests\Server;
44

5+
use App\Contracts\DetectsServerState;
56
use App\GameManager;
67
use Illuminate\Contracts\Validation\ValidationRule;
78
use Illuminate\Foundation\Http\FormRequest;
@@ -23,6 +24,7 @@ public function rules(): array
2324
$handlerRules = $handler->serverValidationRules();
2425
$settingsRules = $handler->settingsValidationRules();
2526
} catch (\InvalidArgumentException) {
27+
$handler = null;
2628
$handlerRules = [];
2729
$settingsRules = [];
2830
}
@@ -35,6 +37,7 @@ public function rules(): array
3537
'description' => ['nullable', 'string', 'max:1000'],
3638
'active_preset_id' => ['nullable', 'exists:mod_presets,id'],
3739
'game_install_id' => ['required', 'exists:game_installs,id'],
40+
...($handler instanceof DetectsServerState ? ['auto_restart' => ['boolean']] : []),
3841
...$handlerRules,
3942
...$settingsRules,
4043
];

app/Http/Requests/Server/UpdateServerRequest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Http\Requests\Server;
44

5+
use App\Contracts\DetectsServerState;
56
use App\GameManager;
67
use Illuminate\Contracts\Validation\ValidationRule;
78
use Illuminate\Foundation\Http\FormRequest;
@@ -26,6 +27,7 @@ public function rules(): array
2627
'description' => ['nullable', 'string', 'max:1000'],
2728
'active_preset_id' => ['nullable', 'exists:mod_presets,id'],
2829
'game_install_id' => ['required', 'exists:game_installs,id'],
30+
...($handler instanceof DetectsServerState ? ['auto_restart' => ['boolean']] : []),
2931
...$handler->serverValidationRules($server),
3032
...$handler->settingsValidationRules(),
3133
];

app/Models/Arma3Settings.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ class Arma3Settings extends Model
1515

1616
protected $fillable = [
1717
'server_id',
18+
// Server options (moved from servers table)
19+
'admin_password',
20+
'verify_signatures',
21+
'allowed_file_patching',
22+
'battle_eye',
23+
'persistent',
24+
'von_enabled',
25+
'additional_server_options',
1826
// Difficulty settings
1927
'reduced_damage',
2028
'group_indicators',
@@ -59,6 +67,12 @@ class Arma3Settings extends Model
5967
protected function casts(): array
6068
{
6169
return [
70+
// Server options
71+
'verify_signatures' => 'boolean',
72+
'allowed_file_patching' => 'boolean',
73+
'battle_eye' => 'boolean',
74+
'persistent' => 'boolean',
75+
'von_enabled' => 'boolean',
6276
// Difficulty
6377
'reduced_damage' => 'boolean',
6478
'group_indicators' => 'integer',

app/Models/ProjectZomboidSettings.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class ProjectZomboidSettings extends Model
1818
*/
1919
protected $fillable = [
2020
'server_id',
21+
'admin_password',
2122
'pvp',
2223
'pause_empty',
2324
'global_chat',

0 commit comments

Comments
 (0)