1399 lines
40 KiB
Markdown
1399 lines
40 KiB
Markdown
# GSP Steam Workshop and Server Content Design
|
|
|
|
Workspace reference: [`GSP-WORKSPACE.md`](../../../GSP-WORKSPACE.md)
|
|
|
|
## Scope
|
|
|
|
This document is an investigation and design report only. It does not implement code.
|
|
|
|
The goal is a professional Steam Workshop and general server content system for GSP that works across:
|
|
|
|
- `Agent-Windows`
|
|
- `Agent_Linux` (the Linux agent directory currently uses an underscore in this repository)
|
|
- `Panel`
|
|
- `Website`
|
|
|
|
The system should support games that use Steam Workshop directly, games that require server-side mod installation, and games that use non-Workshop add-ons or content packs.
|
|
|
|
Target games include DayZ, Arma / Arma 2 / Arma 3, Rust, Garry's Mod, CS / Source games where applicable, and future games with installable server content.
|
|
|
|
## Current Code Findings
|
|
|
|
### Add-ons manager state
|
|
|
|
The old add-ons manager has already been partially converted into a broader Server Content Manager.
|
|
|
|
Relevant files:
|
|
|
|
- `Panel/modules/addonsmanager/addons_manager.php`
|
|
- `Panel/modules/addonsmanager/addons_installer.php`
|
|
- `Panel/modules/addonsmanager/server_content_helpers.php`
|
|
- `Panel/modules/addonsmanager/server_content_actions.php`
|
|
- `Panel/modules/addonsmanager/workshop_content.php`
|
|
- `Panel/modules/addonsmanager/workshop_action.php`
|
|
- `Panel/modules/addonsmanager/server_content_categories.php`
|
|
- `Panel/modules/addonsmanager/scripts/workshop/generic_steam_workshop_linux.sh`
|
|
- `Panel/modules/addonsmanager/scripts/workshop/generic_steam_workshop_windows_cygwin.sh`
|
|
- `Panel/modules/addonsmanager/SERVER_CONTENT_ROADMAP.md`
|
|
- `Panel/modules/addonsmanager/SERVER_CONTENT_WORKSHOP_PHASE1.md`
|
|
|
|
What exists:
|
|
|
|
- Server Content language and categories have started replacing legacy "add-ons" language.
|
|
- Install methods include `download_zip`, `steam_workshop`, `config_edit`, and `post_script`.
|
|
- Workshop content has a user-facing page where customers can enter Workshop item IDs.
|
|
- Workshop IDs are validated as numeric strings.
|
|
- A `server_content_workshop` table is created/migrated by helper code.
|
|
- A remote manifest is written under the game server home.
|
|
- Panel-owned Linux and Cygwin/Windows templates are used to generate per-job scripts under the server home.
|
|
- The generated job script creates a temporary SteamCMD runscript and calls SteamCMD with `+runscript`.
|
|
- Basic install, update, update selected, update all, and remove selected actions exist.
|
|
- Actions are logged through the panel logger and the script writes a text log under `gsp_server_content`.
|
|
|
|
What is incomplete:
|
|
|
|
- No search or metadata lookup workflow exists in the UI.
|
|
- Titles are stored but not reliably resolved.
|
|
- There is no load order management.
|
|
- There is no enabled/disabled state separate from installed/removed state.
|
|
- There is no per-game install strategy model.
|
|
- There is no first-class DayZ/Arma `-mod=` generation.
|
|
- There is no robust copy-key behavior for DayZ `.bikey` files.
|
|
- There is no clone/copy mod list workflow.
|
|
- There is no asynchronous job/progress system for long Workshop installs.
|
|
- Current generic scripts are synchronous from the Panel request.
|
|
- Current scripts assume anonymous SteamCMD login.
|
|
- Current scripts only constrain writes under the server home, so they do not support a true agent global cache outside the game directory.
|
|
- Current scripts run optional `post_install_script` using `bash -lc`, which should remain admin-only and should not be customer-provided.
|
|
- The XML schema does not yet define the Workshop support tags that the helper code expects.
|
|
|
|
### Current Workshop Phase 1 flow
|
|
|
|
The current user flow is:
|
|
|
|
1. User opens the Workshop Mods page for a server.
|
|
2. User enters numeric Workshop item IDs.
|
|
3. Panel inserts or updates rows in `server_content_workshop`.
|
|
4. Panel writes a manifest to:
|
|
- `{GAME_HOME}/gsp_server_content/workshop_manifest.json`
|
|
5. Panel writes a generated job script to:
|
|
- `{GAME_HOME}/gsp_server_content/jobs/workshop/workshop_job_<timestamp>_<random>.sh`
|
|
6. Panel executes:
|
|
- `bash <script_path> <manifest_path>`
|
|
7. The script writes a temporary SteamCMD runscript:
|
|
- `@ShutdownOnFailedCommand 0`
|
|
- `@NoPromptForPassword 1`
|
|
- `force_install_dir <server_root>`
|
|
- `login anonymous`
|
|
- `workshop_download_item <workshop_app_id> <workshop_id> validate`
|
|
8. The script runs SteamCMD with `+runscript <scriptfile>`.
|
|
9. The script copies downloaded files to a target folder, defaulting to:
|
|
- `{SERVER_ROOT}/@{WORKSHOP_ID}`
|
|
10. Panel updates DB row state to `installed`, `failed`, or `removed`.
|
|
|
|
This is useful as a proof of concept, but it is not yet a commercial Workshop/mod system.
|
|
|
|
### Current DB/storage state
|
|
|
|
The current helper creates:
|
|
|
|
`server_content_workshop`
|
|
|
|
Known columns:
|
|
|
|
- `id`
|
|
- `content_id`
|
|
- `home_id`
|
|
- `home_cfg_id`
|
|
- `remote_server_id`
|
|
- `workshop_app_id`
|
|
- `workshop_item_id`
|
|
- `title`
|
|
- `install_state`
|
|
- `last_installed_at`
|
|
- `last_updated_at`
|
|
- `last_error`
|
|
- `created_by`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
The current helper also writes agent-side files under the server home:
|
|
|
|
- `gsp_server_content/workshop_manifest.json`
|
|
- `gsp_server_content/manifests/*.json`
|
|
- `gsp_server_content/installed_content.json`
|
|
- `gsp_server_content/workshop_install.log`
|
|
- `gsp_server_content/workshop_install_windows.log`
|
|
- `gsp_server_content/workshop/removed/*`
|
|
- `gsp_server_content/jobs/workshop/workshop_job_*.sh`
|
|
|
|
Current DB weaknesses:
|
|
|
|
- No load order column.
|
|
- No enabled column.
|
|
- No install path column per row.
|
|
- No install folder/name column per row.
|
|
- No installed Workshop timestamp/version/hash metadata from Steam.
|
|
- No job table for long-running installs.
|
|
- No normalized global Workshop item metadata table.
|
|
- No clean split between desired state, installed state, and job state.
|
|
|
|
### Current Panel-Agent communication
|
|
|
|
Panel communicates with agents through XML-RPC using `Panel/includes/lib_remote.php`.
|
|
|
|
Relevant methods:
|
|
|
|
- `steam_cmd(...)`
|
|
- `steam_workshop(...)`
|
|
- `get_workshop_mods_info(...)`
|
|
- `start_file_download(...)`
|
|
- `remote_writefile(...)`
|
|
- `remote_readfile(...)`
|
|
- `exec(...)`
|
|
|
|
There are two Workshop paths:
|
|
|
|
1. Legacy agent RPC:
|
|
- Panel method: `OGPRemoteLibrary::steam_workshop(...)`
|
|
- Agent subroutine: `steam_workshop_without_decrypt(...)`
|
|
- Runs SteamCMD in a screen update session.
|
|
- Generates post-install shell snippets that edit a config file.
|
|
|
|
2. Current Server Content manifest path:
|
|
- Panel writes a JSON manifest using `remote_writefile`.
|
|
- Panel copies an approved script to the agent using `remote_writefile`.
|
|
- Panel runs the script through `exec`.
|
|
- This path does not use the old `steam_workshop` RPC.
|
|
|
|
The second path is cleaner for future Server Content work because it is manifest-driven, but it should be moved away from direct synchronous `exec` into a first-class agent job/action.
|
|
|
|
### Current agent SteamCMD behavior
|
|
|
|
Linux agent:
|
|
|
|
- File: `Agent_Linux/ogp_agent.pl`
|
|
- SteamCMD path constants:
|
|
- `AGENT_RUN_DIR/steamcmd`
|
|
- `steamcmd.sh`
|
|
- `check_steam_cmd_client` downloads and installs SteamCMD if missing.
|
|
- `steam_cmd_without_decrypt` creates a SteamCMD runscript and runs it in a screen update session.
|
|
- `steam_workshop_without_decrypt` creates a SteamCMD runscript containing `workshop_download_item` lines and runs it in a screen update session.
|
|
- `get_workshop_mods_info` reads `.ogpmod` files from `AGENT_RUN_DIR/WorkshopModsInfo`.
|
|
|
|
Windows/Cygwin agent:
|
|
|
|
- File: `Agent-Windows/ogp_agent.pl`
|
|
- SteamCMD path constants:
|
|
- `/OGP/steamcmd`
|
|
- `steamcmd.exe`
|
|
- `steam_cmd_without_decrypt` uses Cygwin path conversion for `force_install_dir`.
|
|
- `steam_workshop_without_decrypt` uses Cygwin path conversion for the mods path and the SteamCMD runscript.
|
|
- `get_workshop_mods_info` mirrors the Linux behavior.
|
|
|
|
Agent limitations:
|
|
|
|
- The legacy `steam_workshop` RPC is not tied to the newer `server_content_workshop` DB table.
|
|
- It edits config files through generated shell script content instead of structured startup parameter state.
|
|
- It does not understand enabled/disabled state or load order.
|
|
- It does not expose a durable install job ID with pollable progress.
|
|
- It does not track per-server install manifests as the source of truth.
|
|
- It does not provide a DayZ-specific strategy.
|
|
|
|
### Current game XML and startup parameter behavior
|
|
|
|
Relevant files:
|
|
|
|
- `Panel/modules/config_games/schema_server_config.xml`
|
|
- `Panel/modules/config_games/config_servers.php`
|
|
- `Panel/modules/config_games/cli-params.php`
|
|
- `Panel/modules/gamemanager/mini_start.php`
|
|
- `Panel/modules/gamemanager/cfg_text_replace.php`
|
|
- `Panel/modules/gamemanager/update_actions.php`
|
|
|
|
The XML schema currently supports:
|
|
|
|
- `cli_template`
|
|
- `cli_params`
|
|
- `replace_texts`
|
|
- `custom_fields`
|
|
- `pre_install`
|
|
- `post_install`
|
|
- `pre_start`
|
|
- `post_start`
|
|
- `environment_variables`
|
|
- `lock_files`
|
|
- `configuration_files`
|
|
|
|
The XML schema does not currently support a first-class `workshop_support` block. Helper code already checks ad hoc fields such as:
|
|
|
|
- `workshop_app_id`
|
|
- `workshop_appid`
|
|
- `steam_workshop_app_id`
|
|
- `steam_workshop_appid`
|
|
- `workshop_script_linux`
|
|
- `workshop_script_windows`
|
|
|
|
Because `read_server_config()` validates XML against `schema_server_config.xml`, these ad hoc fields are not safe to use in game XML until the schema is extended.
|
|
|
|
Startup parameters are currently generated in `mini_start.php` from `cli_template` and `cli_params`, with stored server values/custom fields layered in. This should be the integration point for generated mod parameters, but the mod list must be structured data, not raw customer command text.
|
|
|
|
### Current config/custom field behavior
|
|
|
|
`cfg_text_replace.php` reads custom fields from the database and applies configured replacements to files through `remote_readfile` and `remote_writefile`.
|
|
|
|
This is useful for game config editing, but it should not be used as the primary Workshop/mod list system because:
|
|
|
|
- It is text replacement based.
|
|
- It does not model enabled/disabled mods.
|
|
- It does not model load order.
|
|
- It does not model install state.
|
|
- It can be fragile for repeated add/remove/reorder operations.
|
|
|
|
### Existing Workshop support in game configs
|
|
|
|
Some Source/Garry's Mod configs expose Workshop-related startup params directly:
|
|
|
|
- `+host_workshop_collection`
|
|
- `+host_workshop_map`
|
|
- `+workshop_start_map`
|
|
|
|
This is game-managed Workshop support. GSP should preserve that behavior and not force all games through server-side file copying.
|
|
|
|
## Current Add-ons/Content Module State
|
|
|
|
The current module is best described as "Server Content Phase 1."
|
|
|
|
Partially working pieces:
|
|
|
|
- Admins can define content records in the `addons` table.
|
|
- Users can view server content from the add-ons manager.
|
|
- `steam_workshop` is recognized as an install method.
|
|
- Workshop IDs can be entered manually.
|
|
- A manifest-driven script runner exists.
|
|
- Basic install/update/remove states exist.
|
|
|
|
Broken or incomplete pieces for commercial use:
|
|
|
|
- No schema-level game capability declaration.
|
|
- No game-specific install strategy selection.
|
|
- No load order UI.
|
|
- No enable/disable UI.
|
|
- No safe startup parameter generation for mod lists.
|
|
- No DayZ/Arma key copy strategy.
|
|
- No metadata discovery or title resolution.
|
|
- No async job/progress model.
|
|
- No central cache design.
|
|
- No cache cleanup policy.
|
|
- No rollback/repair strategy.
|
|
- No robust uninstall ownership model for copied keys/files.
|
|
- No support for private Workshop items requiring login beyond older SteamCMD update settings.
|
|
|
|
## Recommended Architecture
|
|
|
|
### Main design rule
|
|
|
|
The Panel database should be the source of truth for desired server content state.
|
|
|
|
The agent should be the source of truth for execution state and filesystem results.
|
|
|
|
Agent files should be treated as runtime manifests, logs, caches, and recovery aids, not as the only source of truth.
|
|
|
|
### Core model
|
|
|
|
Create a first-class Server Content / Workshop system with:
|
|
|
|
- XML-declared game capabilities.
|
|
- Database-stored per-server content state.
|
|
- Agent-executed install/update/uninstall jobs.
|
|
- Structured startup parameter generation.
|
|
- Game-specific install strategies.
|
|
- Safe, pollable job logs.
|
|
- Optional global cache.
|
|
- Cross-platform behavior for Linux and Cygwin/Windows agents.
|
|
|
|
### Required states
|
|
|
|
For a server Workshop item:
|
|
|
|
- `selected`: saved but not installed.
|
|
- `queued`: job has been queued.
|
|
- `installing`: agent is installing it.
|
|
- `installed`: installed and available.
|
|
- `disabled`: installed but excluded from generated startup parameters.
|
|
- `updating`: update job is running.
|
|
- `failed`: last install/update failed.
|
|
- `removing`: uninstall job is running.
|
|
- `removed`: removed from desired state.
|
|
|
|
For an install job:
|
|
|
|
- `queued`
|
|
- `running`
|
|
- `succeeded`
|
|
- `failed`
|
|
- `cancelled`
|
|
|
|
### Recommended component responsibilities
|
|
|
|
Panel:
|
|
|
|
- Reads game XML capability definitions.
|
|
- Shows Workshop/Mods/Server Content UI only when supported.
|
|
- Stores desired content state.
|
|
- Queues install/update/remove/reorder actions.
|
|
- Generates desired startup mod list from DB state.
|
|
- Sends structured manifests/jobs to the agent.
|
|
- Polls agent for progress/logs.
|
|
- Shows clear error messages and restart-required prompts.
|
|
|
|
Agent:
|
|
|
|
- Runs SteamCMD.
|
|
- Stages downloads.
|
|
- Copies/installs files using approved strategies.
|
|
- Copies DayZ/Arma keys when configured.
|
|
- Writes progress logs.
|
|
- Writes per-job result JSON.
|
|
- Tracks installed file manifests where useful.
|
|
- Does not trust customer-supplied shell commands.
|
|
- Does not decide desired load order.
|
|
|
|
Game XML:
|
|
|
|
- Declares whether Workshop/content support exists.
|
|
- Declares the provider, Steam app IDs, install strategy, path templates, startup parameter format, key copy behavior, cache policy, and authentication needs.
|
|
- Provides admin-defined strategy data, not customer-editable commands.
|
|
|
|
## XML Capability Proposal
|
|
|
|
Add a first-class optional block to `schema_server_config.xml`.
|
|
|
|
Example:
|
|
|
|
```xml
|
|
<workshop_support>
|
|
<enabled>1</enabled>
|
|
<provider>steam</provider>
|
|
<steam_app_id>221100</steam_app_id>
|
|
<workshop_app_id>221100</workshop_app_id>
|
|
<download_method>steamcmd</download_method>
|
|
<install_strategy>dayz_mod_folder</install_strategy>
|
|
<install_path>{GAME_PATH}</install_path>
|
|
<mod_folder_format>@{SAFE_TITLE}</mod_folder_format>
|
|
<startup_param_format>-mod={MOD_LIST}</startup_param_format>
|
|
<mod_separator>;</mod_separator>
|
|
<mod_prefix>@</mod_prefix>
|
|
<requires_restart>1</requires_restart>
|
|
<supports_load_order>1</supports_load_order>
|
|
<supports_disable>1</supports_disable>
|
|
<allow_cache>1</allow_cache>
|
|
<requires_steam_login>0</requires_steam_login>
|
|
<copy_keys enabled="1">
|
|
<source_pattern>{MOD_PATH}/keys/*.bikey</source_pattern>
|
|
<target_path>{GAME_PATH}/keys</target_path>
|
|
</copy_keys>
|
|
</workshop_support>
|
|
```
|
|
|
|
### Required XML fields
|
|
|
|
- `enabled`
|
|
- `provider`
|
|
- `download_method`
|
|
- `install_strategy`
|
|
|
|
For Steam Workshop:
|
|
|
|
- `steam_app_id`
|
|
- `workshop_app_id`
|
|
|
|
For strategies that install files:
|
|
|
|
- `install_path`
|
|
|
|
For strategies that update startup parameters:
|
|
|
|
- `startup_param_format`
|
|
- `mod_separator`
|
|
|
|
### Optional XML fields
|
|
|
|
- `mod_prefix`
|
|
- `mod_folder_format`
|
|
- `server_mod_param_format`
|
|
- `client_mod_param_format`
|
|
- `copy_keys`
|
|
- `requires_restart`
|
|
- `supports_load_order`
|
|
- `supports_disable`
|
|
- `allow_cache`
|
|
- `cache_scope`
|
|
- `requires_steam_login`
|
|
- `steam_login_profile`
|
|
- `max_items`
|
|
- `allowed_item_types`
|
|
- `install_script_key`
|
|
- `post_install_strategy`
|
|
- `validate_files`
|
|
- `backup_before_update`
|
|
- `preserve_previous_version`
|
|
|
|
### Supported install strategies
|
|
|
|
- `game_managed_workshop`
|
|
- `steamcmd_download_only`
|
|
- `copy_to_game_root`
|
|
- `copy_to_mod_folder`
|
|
- `dayz_mod_folder`
|
|
- `arma_mod_folder`
|
|
- `config_only`
|
|
- `custom_scripted_install`
|
|
|
|
### Strategy meanings
|
|
|
|
`game_managed_workshop`
|
|
|
|
- The game downloads/uses Workshop content internally.
|
|
- GSP should generate game-supported startup params such as Workshop collection IDs.
|
|
- No server-side file copy is required.
|
|
- Example: Garry's Mod or Source games using `+host_workshop_collection`.
|
|
|
|
`steamcmd_download_only`
|
|
|
|
- Agent downloads Workshop item to a known cache/staging path.
|
|
- No direct install into game root.
|
|
- Useful for games/tools that consume downloaded content separately.
|
|
|
|
`copy_to_game_root`
|
|
|
|
- Agent downloads then copies files directly under `{GAME_PATH}` or a safe subpath.
|
|
|
|
`copy_to_mod_folder`
|
|
|
|
- Agent downloads then copies content to a generated mod folder.
|
|
|
|
`dayz_mod_folder`
|
|
|
|
- Agent downloads content.
|
|
- Agent installs under `{GAME_PATH}/@ModName`.
|
|
- Agent copies `.bikey` files to `{GAME_PATH}/keys`.
|
|
- Panel generates `-mod=@Mod1;@Mod2` from enabled ordered items.
|
|
|
|
`arma_mod_folder`
|
|
|
|
- Similar to DayZ, but should support Arma-specific client/server mod parameter variants as needed.
|
|
|
|
`config_only`
|
|
|
|
- The content changes structured config values only.
|
|
- No Workshop download.
|
|
|
|
`custom_scripted_install`
|
|
|
|
- Admin-defined trusted script/action.
|
|
- Should be used sparingly.
|
|
- Customer must never provide arbitrary script text.
|
|
|
|
### XML validation rules
|
|
|
|
- `enabled` must be `0` or `1`.
|
|
- App IDs and Workshop IDs must be numeric.
|
|
- Strategy must be one of the allowed strategy names.
|
|
- Path templates must only use approved variables.
|
|
- Path templates must resolve under allowed roots.
|
|
- Startup param format must only contain approved placeholders.
|
|
- `copy_keys` target path must resolve under the game home unless explicitly allowed by admin policy.
|
|
- `custom_scripted_install` must reference an approved script key/path, not inline customer text.
|
|
|
|
### Backward compatibility
|
|
|
|
Older XML files should continue to work with no Workshop support.
|
|
|
|
If `workshop_support` is absent:
|
|
|
|
- Existing startup parameters such as `+host_workshop_collection` continue to work.
|
|
- Existing add-ons manager content can still be shown if admin-created content records exist.
|
|
- No Workshop Mods page should be shown unless enabled by admin record or capability detection.
|
|
|
|
Existing ad hoc fields such as `workshop_app_id` should either be migrated into `workshop_support` or tolerated by a compatibility parser after the schema is explicitly updated.
|
|
|
|
## DB Table Proposal
|
|
|
|
### `gsp_workshop_items`
|
|
|
|
Global metadata cache for Workshop items.
|
|
|
|
Suggested columns:
|
|
|
|
- `id`
|
|
- `provider`
|
|
- `app_id`
|
|
- `workshop_id`
|
|
- `title`
|
|
- `description_short`
|
|
- `preview_url`
|
|
- `author_name`
|
|
- `visibility`
|
|
- `file_size`
|
|
- `time_created`
|
|
- `time_updated`
|
|
- `metadata_json`
|
|
- `last_metadata_fetch_at`
|
|
- `last_metadata_error`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
Unique key:
|
|
|
|
- `(provider, app_id, workshop_id)`
|
|
|
|
### `gsp_server_workshop_items`
|
|
|
|
Desired per-server Workshop state.
|
|
|
|
Suggested columns:
|
|
|
|
- `id`
|
|
- `home_id`
|
|
- `home_cfg_id`
|
|
- `remote_server_id`
|
|
- `content_id`
|
|
- `provider`
|
|
- `app_id`
|
|
- `workshop_app_id`
|
|
- `workshop_id`
|
|
- `item_title`
|
|
- `install_name`
|
|
- `safe_folder_name`
|
|
- `install_path`
|
|
- `enabled`
|
|
- `load_order`
|
|
- `install_strategy`
|
|
- `install_state`
|
|
- `installed_version`
|
|
- `installed_timestamp`
|
|
- `last_update_check`
|
|
- `last_installed_at`
|
|
- `last_updated_at`
|
|
- `last_error`
|
|
- `restart_required`
|
|
- `installed_by`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
Recommended unique key:
|
|
|
|
- `(home_id, provider, workshop_id)`
|
|
|
|
### `gsp_workshop_install_jobs`
|
|
|
|
Pollable install/update/remove jobs.
|
|
|
|
Suggested columns:
|
|
|
|
- `id`
|
|
- `job_uuid`
|
|
- `home_id`
|
|
- `remote_server_id`
|
|
- `action`
|
|
- `status`
|
|
- `requested_by`
|
|
- `started_at`
|
|
- `finished_at`
|
|
- `agent_job_id`
|
|
- `manifest_path`
|
|
- `log_path`
|
|
- `result_path`
|
|
- `progress_percent`
|
|
- `last_message`
|
|
- `last_error`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
### `gsp_workshop_install_job_items`
|
|
|
|
Per-item job details.
|
|
|
|
Suggested columns:
|
|
|
|
- `id`
|
|
- `job_id`
|
|
- `server_workshop_item_id`
|
|
- `workshop_id`
|
|
- `action`
|
|
- `status`
|
|
- `install_path`
|
|
- `message`
|
|
- `error`
|
|
- `started_at`
|
|
- `finished_at`
|
|
|
|
### `gsp_server_content_profiles`
|
|
|
|
Optional admin-defined reusable profiles per game/config.
|
|
|
|
Suggested columns:
|
|
|
|
- `id`
|
|
- `home_cfg_id`
|
|
- `profile_key`
|
|
- `display_name`
|
|
- `provider`
|
|
- `steam_app_id`
|
|
- `workshop_app_id`
|
|
- `install_strategy`
|
|
- `install_path_template`
|
|
- `startup_param_format`
|
|
- `copy_keys_json`
|
|
- `cache_policy`
|
|
- `created_at`
|
|
- `updated_at`
|
|
|
|
### Source of truth
|
|
|
|
The Panel DB should be the source of truth for:
|
|
|
|
- Which mods are desired.
|
|
- Which mods are enabled.
|
|
- Load order.
|
|
- Generated startup params.
|
|
- Last known install state.
|
|
|
|
The agent should write runtime state for:
|
|
|
|
- Active job progress.
|
|
- Install logs.
|
|
- Download/cache manifests.
|
|
- Files installed during a job.
|
|
- Last job result.
|
|
|
|
## Agent Execution Proposal
|
|
|
|
### Preferred direction
|
|
|
|
Add a dedicated agent action for server content jobs instead of running generic `exec` synchronously from a web request.
|
|
|
|
Potential XML-RPC methods:
|
|
|
|
- `server_content_start_job(home_id, manifest_json)`
|
|
- `server_content_job_status(home_id, job_id)`
|
|
- `server_content_job_log(home_id, job_id, offset)`
|
|
- `server_content_cancel_job(home_id, job_id)`
|
|
|
|
The agent should return quickly with a job ID. The Panel polls status and logs.
|
|
|
|
### Manifest shape
|
|
|
|
Example:
|
|
|
|
```json
|
|
{
|
|
"manifest_version": 2,
|
|
"job_uuid": "uuid",
|
|
"home_id": 123,
|
|
"home_path": "/home/ogp_agent/OGP_User_Files/123",
|
|
"provider": "steam",
|
|
"action": "install_update",
|
|
"strategy": "dayz_mod_folder",
|
|
"steam_app_id": "221100",
|
|
"workshop_app_id": "221100",
|
|
"startup": {
|
|
"param_format": "-mod={MOD_LIST}",
|
|
"separator": ";",
|
|
"mod_prefix": "@"
|
|
},
|
|
"copy_keys": {
|
|
"enabled": true,
|
|
"source_pattern": "{MOD_PATH}/keys/*.bikey",
|
|
"target_path": "{GAME_PATH}/keys"
|
|
},
|
|
"items": [
|
|
{
|
|
"workshop_id": "1559212036",
|
|
"title": "CF",
|
|
"safe_folder_name": "@CF",
|
|
"enabled": true,
|
|
"load_order": 10,
|
|
"install_path": "{GAME_PATH}/@CF"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Agent job execution
|
|
|
|
For each job:
|
|
|
|
1. Validate manifest fields.
|
|
2. Resolve paths from approved templates only.
|
|
3. Create job directory under agent control.
|
|
4. Start a background worker, preferably screen-backed for consistency with existing agent behavior.
|
|
5. Write progress logs.
|
|
6. Run SteamCMD download.
|
|
7. Verify expected download path exists.
|
|
8. Stage content.
|
|
9. Install/copy/sync to final path.
|
|
10. Copy keys if strategy requires it.
|
|
11. Write installed file manifest.
|
|
12. Write job result JSON.
|
|
13. Return status to Panel polling.
|
|
|
|
### SteamCMD command
|
|
|
|
Baseline command:
|
|
|
|
```bash
|
|
steamcmd +login anonymous +workshop_download_item <workshop_app_id> <workshop_id> validate +quit
|
|
```
|
|
|
|
Authenticated variant:
|
|
|
|
```bash
|
|
steamcmd +login <configured_user> <configured_password> +workshop_download_item <workshop_app_id> <workshop_id> validate +quit
|
|
```
|
|
|
|
The agent must redact credentials from logs.
|
|
|
|
### Agent paths
|
|
|
|
Recommended paths:
|
|
|
|
- Job root:
|
|
- `{CONTROL_PATH}/server_content/jobs/{job_uuid}`
|
|
- Job manifest:
|
|
- `{CONTROL_PATH}/server_content/jobs/{job_uuid}/manifest.json`
|
|
- Job log:
|
|
- `{CONTROL_PATH}/server_content/jobs/{job_uuid}/job.log`
|
|
- Job result:
|
|
- `{CONTROL_PATH}/server_content/jobs/{job_uuid}/result.json`
|
|
- Per-server content manifest:
|
|
- `{CONTROL_PATH}/server_content/installed_manifest.json`
|
|
- Per-server staging:
|
|
- `{CONTROL_PATH}/server_content/staging/{job_uuid}`
|
|
- Per-server Workshop staging:
|
|
- `{CONTROL_PATH}/server_content/workshop/staging/{workshop_id}`
|
|
|
|
`CONTROL_PATH` should be agent-managed and should not be customer-editable through FTP/file manager.
|
|
|
|
### Cache paths
|
|
|
|
Optional global cache:
|
|
|
|
- `{AGENT_CACHE}/steam_workshop/{workshop_app_id}/{workshop_id}`
|
|
|
|
Optional per-server cache:
|
|
|
|
- `{CONTROL_PATH}/server_content/cache/steam_workshop/{workshop_app_id}/{workshop_id}`
|
|
|
|
The first version can use per-server staging only. Global cache can be added once ownership, quota, cleanup, and sharing rules are defined.
|
|
|
|
## User Workflow
|
|
|
|
Customer workflow:
|
|
|
|
1. Open a game server.
|
|
2. Click `Workshop`, `Mods`, or `Server Content`.
|
|
3. Paste a Workshop URL or numeric Workshop ID.
|
|
4. Panel extracts and validates the numeric ID.
|
|
5. Panel optionally fetches title/metadata.
|
|
6. User adds the item to the install queue.
|
|
7. User chooses enabled or disabled.
|
|
8. User adjusts load order where the game supports it.
|
|
9. User clicks `Install / Update`.
|
|
10. Panel shows live progress and logs.
|
|
11. When complete, Panel marks restart required if the game is running.
|
|
12. User restarts server.
|
|
13. Startup params are generated from the enabled ordered mod list.
|
|
|
|
Installed mod list should show:
|
|
|
|
- Enabled checkbox/toggle.
|
|
- Load order controls.
|
|
- Workshop ID.
|
|
- Title.
|
|
- Folder/install name.
|
|
- Installed status.
|
|
- Last updated.
|
|
- Last error.
|
|
- Actions: update, repair, disable, uninstall.
|
|
|
|
## Admin Workflow
|
|
|
|
Admin workflow:
|
|
|
|
1. Edit game XML or admin content profile.
|
|
2. Enable Workshop support.
|
|
3. Set provider and Steam app/workshop IDs.
|
|
4. Select install strategy.
|
|
5. Define install path template.
|
|
6. Define startup parameter format.
|
|
7. Define key copy behavior.
|
|
8. Choose cache policy.
|
|
9. Choose whether Steam login is required.
|
|
10. Save and validate schema.
|
|
11. Test install/update/uninstall on Linux and Cygwin/Windows agents.
|
|
|
|
Admins should not need to write shell scripts for common games like DayZ, Arma, Rust, Garry's Mod, or Source games.
|
|
|
|
## Workshop Item Discovery
|
|
|
|
### First version
|
|
|
|
Support:
|
|
|
|
- Numeric Workshop ID entry.
|
|
- Steam Workshop URL paste.
|
|
- Extraction of the `id=` query parameter.
|
|
- Basic local validation.
|
|
- Optional metadata fetch when a Steam Web API key is configured.
|
|
|
|
Accepted examples:
|
|
|
|
- `1559212036`
|
|
- `https://steamcommunity.com/sharedfiles/filedetails/?id=1559212036`
|
|
- Multiple IDs separated by newline or comma.
|
|
|
|
Validation:
|
|
|
|
- Extract only numeric IDs.
|
|
- Reject non-numeric values.
|
|
- Deduplicate IDs.
|
|
- Enforce optional max item count per game/server.
|
|
|
|
### Professional version
|
|
|
|
Support:
|
|
|
|
- Steam Web API metadata fetch.
|
|
- Cached metadata table.
|
|
- Search by title when API key is configured.
|
|
- Preview image/title/author display.
|
|
- Visibility and removed/private item warnings.
|
|
- Update timestamp checks.
|
|
|
|
Limitations:
|
|
|
|
- Some Workshop content requires authenticated Steam credentials.
|
|
- Some items are private, age-gated, removed, or region-restricted.
|
|
- Search can be rate-limited.
|
|
- SteamCMD may download content even when metadata fetch fails, or vice versa.
|
|
|
|
Recommendation:
|
|
|
|
- Build the first version around URL/ID entry.
|
|
- Add metadata enrichment as a progressive enhancement.
|
|
- Do not block install solely because metadata is unavailable.
|
|
|
|
## Download and Install Strategy
|
|
|
|
### SteamCMD execution
|
|
|
|
SteamCMD should run on the agent host because the agent has filesystem access to the game server install.
|
|
|
|
Linux:
|
|
|
|
- Use `steamcmd.sh`.
|
|
- Existing agent already knows `AGENT_RUN_DIR/steamcmd/steamcmd.sh`.
|
|
|
|
Cygwin/Windows:
|
|
|
|
- Use `steamcmd.exe`.
|
|
- Convert Cygwin paths to Windows paths when passing paths to SteamCMD.
|
|
- Keep scripts and screen usage as similar to Linux as possible.
|
|
|
|
### Download flow
|
|
|
|
Recommended flow:
|
|
|
|
1. Resolve SteamCMD path.
|
|
2. Resolve download/cache path.
|
|
3. Run `workshop_download_item`.
|
|
4. Capture stdout/stderr to job log.
|
|
5. Verify expected content folder exists.
|
|
6. Stage content.
|
|
7. Install via strategy.
|
|
8. Record installed file manifest.
|
|
|
|
### DayZ install flow
|
|
|
|
For each enabled mod:
|
|
|
|
1. Download Workshop item with app ID `221100`.
|
|
2. Resolve safe display title if available.
|
|
3. Generate safe folder name:
|
|
- Prefer `@Title` normalized for filesystem and startup use.
|
|
- Fall back to `@<workshop_id>`.
|
|
4. Copy content to:
|
|
- `{GAME_PATH}/@ModName`
|
|
5. Copy `.bikey` files from common locations:
|
|
- `{MOD_PATH}/keys/*.bikey`
|
|
- `{MOD_PATH}/Keys/*.bikey`
|
|
- optionally recursive search if configured.
|
|
6. Copy keys to:
|
|
- `{GAME_PATH}/keys`
|
|
7. Track copied keys in an installed file manifest.
|
|
8. Generate `-mod=@Mod1;@Mod2` from enabled ordered items.
|
|
9. Mark restart required if server is running.
|
|
|
|
### Generic game support
|
|
|
|
Game-managed Workshop games:
|
|
|
|
- Store Workshop collection/map IDs.
|
|
- Generate the game's native Workshop startup params.
|
|
- Do not copy files unless configured.
|
|
|
|
Copy-to-folder games:
|
|
|
|
- Download Workshop item.
|
|
- Copy folder contents to a configured target path.
|
|
- Optionally add startup parameters.
|
|
|
|
Config-only content:
|
|
|
|
- Apply structured config changes from approved templates.
|
|
|
|
Custom scripted install:
|
|
|
|
- Admin-defined trusted scripts only.
|
|
- Scripts should receive a manifest path.
|
|
- Scripts should write structured result JSON.
|
|
|
|
## Startup Parameter Integration
|
|
|
|
Startup parameter generation must be structured and repeatable.
|
|
|
|
For DayZ/Arma style mods:
|
|
|
|
1. Load enabled Workshop items for the server ordered by `load_order`.
|
|
2. Build `MOD_LIST` using the XML `mod_separator`.
|
|
3. Render `startup_param_format`.
|
|
4. Inject the rendered mod parameter into startup generation.
|
|
5. Avoid duplicate `-mod=` entries.
|
|
6. Preserve unrelated startup parameters.
|
|
7. Remove generated mod params when all mods are disabled/uninstalled.
|
|
|
|
Example:
|
|
|
|
```text
|
|
-mod=@CF;@Dabs Framework;@VPPAdminTools
|
|
```
|
|
|
|
Rules:
|
|
|
|
- Customers should not edit the raw generated `-mod=` string.
|
|
- Customers may reorder/enable/disable structured mod rows.
|
|
- Generated startup fragments should be labeled internally as GSP-managed.
|
|
- Existing custom startup params should remain separate where possible.
|
|
|
|
Recommended implementation:
|
|
|
|
- Add a startup fragment resolver before `mini_start.php` finalizes `$start_cmd`.
|
|
- The resolver reads the server content DB state and XML `workshop_support`.
|
|
- It returns a generated fragment such as `-mod=...`.
|
|
- The fragment is inserted through a reserved placeholder or appended according to XML rules.
|
|
|
|
Possible XML placeholder:
|
|
|
|
```xml
|
|
<cli_template>%GAME_TYPE% -config=serverDZ.cfg {GSP_WORKSHOP_PARAMS}</cli_template>
|
|
```
|
|
|
|
If no placeholder exists, XML can specify:
|
|
|
|
```xml
|
|
<startup_injection mode="append" />
|
|
```
|
|
|
|
## Uninstall, Disable, Update, Repair
|
|
|
|
### Disable
|
|
|
|
Disable should:
|
|
|
|
- Set `enabled=0`.
|
|
- Keep installed files.
|
|
- Remove the item from generated startup parameters.
|
|
- Mark restart required if server is running.
|
|
|
|
### Uninstall
|
|
|
|
Uninstall should:
|
|
|
|
- Set job status to `removing`.
|
|
- Remove item from startup mod list.
|
|
- Stop using the mod immediately after next restart.
|
|
- Optionally delete installed files.
|
|
- Optionally leave global cache intact.
|
|
- Remove copied keys only if safe.
|
|
- Update DB row status.
|
|
|
|
Key cleanup rule:
|
|
|
|
- Only remove keys that GSP knows it copied and that are not still required by another installed mod.
|
|
- If ownership is unclear, leave the key and warn the user/admin.
|
|
|
|
### Update
|
|
|
|
Update should:
|
|
|
|
- Download new Workshop content.
|
|
- Stage it separately.
|
|
- Preserve old installed folder until staging succeeds.
|
|
- Swap/copy into place only after successful download.
|
|
- Roll back if install fails where feasible.
|
|
- Mark restart required if server is running.
|
|
|
|
### Repair/reinstall
|
|
|
|
Repair should:
|
|
|
|
- Re-run download with `validate`.
|
|
- Re-copy content.
|
|
- Re-copy keys.
|
|
- Rebuild startup parameters.
|
|
|
|
### Clone mod set
|
|
|
|
Clone should:
|
|
|
|
- Copy desired mod list, enabled state, and load order to another compatible server.
|
|
- Validate same game/config capability.
|
|
- Queue install/update job for the target server.
|
|
- Reuse cache when safe and available.
|
|
|
|
## Caching and Cleanup Plan
|
|
|
|
### Cache options
|
|
|
|
No cache:
|
|
|
|
- Lowest complexity.
|
|
- Highest repeated bandwidth usage.
|
|
|
|
Per-server cache:
|
|
|
|
- Safer ownership model.
|
|
- Easier cleanup.
|
|
- Less sharing benefit.
|
|
|
|
Agent global cache:
|
|
|
|
- Best reuse across servers.
|
|
- Saves bandwidth and time.
|
|
- Requires quota, permissions, locking, and cleanup.
|
|
|
|
### Recommended phases
|
|
|
|
First implementation:
|
|
|
|
- Use per-server staging/cache under agent control.
|
|
- Do not expose cache through customer file manager.
|
|
|
|
Later:
|
|
|
|
- Add optional global cache by app ID and Workshop ID.
|
|
- Track size and last-used timestamp.
|
|
- Admin-configurable max cache size.
|
|
- Cleanup least recently used items.
|
|
- Support hardlink/symlink/junction only after cross-platform testing.
|
|
|
|
### Cache metadata
|
|
|
|
Cache manifest should track:
|
|
|
|
- Provider.
|
|
- App ID.
|
|
- Workshop ID.
|
|
- Download timestamp.
|
|
- Steam update timestamp if known.
|
|
- Size.
|
|
- Source path.
|
|
- Last used by home ID.
|
|
- Last validation result.
|
|
|
|
## Security Considerations
|
|
|
|
### Customer input
|
|
|
|
Customers may provide:
|
|
|
|
- Workshop URLs.
|
|
- Workshop IDs.
|
|
- Enable/disable choices.
|
|
- Load order.
|
|
|
|
Customers must not provide:
|
|
|
|
- Shell commands.
|
|
- SteamCMD command fragments.
|
|
- Arbitrary install paths.
|
|
- Arbitrary startup command fragments.
|
|
- Arbitrary copy patterns.
|
|
|
|
### Command safety
|
|
|
|
- Commands should be generated from trusted XML/admin config and validated DB state.
|
|
- Workshop IDs must be numeric.
|
|
- URL parsing must only extract numeric `id` values.
|
|
- Path templates must resolve under allowed roots.
|
|
- No path traversal.
|
|
- No null bytes or control characters.
|
|
- Logs must redact Steam credentials.
|
|
- Admin scripts must be explicitly marked trusted.
|
|
|
|
### File location safety
|
|
|
|
Managed manifests, job files, logs, and scripts should live outside customer-editable roots where possible.
|
|
|
|
If current deployment requires storing under game home temporarily:
|
|
|
|
- Use a `gsp_server_content` directory.
|
|
- Prevent customer file manager/FTP access to that control directory if possible.
|
|
- Validate that all write targets stay under approved paths.
|
|
|
|
### Credentials
|
|
|
|
- Steam credentials should remain in admin settings or a dedicated secure credential profile.
|
|
- Do not expose credentials in manifests shown to customers.
|
|
- Do not write raw passwords to logs.
|
|
- Prefer passing credentials through agent-managed secure files or redacted runscript generation.
|
|
|
|
### Avoid arbitrary process/file damage
|
|
|
|
- Install/uninstall should act only on paths from the per-item manifest.
|
|
- Remove only files/folders GSP installed or explicitly owns.
|
|
- Do not recursively delete broad paths such as `{GAME_PATH}`.
|
|
- Do not remove shared keys unless manifest ownership is clear.
|
|
|
|
## Cross-platform Considerations
|
|
|
|
### Linux
|
|
|
|
- Use `steamcmd.sh`.
|
|
- Use POSIX path handling.
|
|
- Use screen-backed jobs for consistency with existing agent update behavior.
|
|
- Use `rsync` if available, otherwise safe recursive copy.
|
|
- Preserve file ownership for the game server user.
|
|
|
|
### Cygwin/Windows
|
|
|
|
- Use `steamcmd.exe`.
|
|
- Convert paths with `cygpath -wa` when passing to SteamCMD.
|
|
- Be careful with spaces and backslashes.
|
|
- Use Cygwin shell for shared scripts where practical.
|
|
- Avoid Linux-only tools unless bundled or checked.
|
|
- Use safe copy behavior that works under Cygwin.
|
|
|
|
### Common risks
|
|
|
|
- Quoting differences.
|
|
- Case-insensitive paths on Windows.
|
|
- Long paths.
|
|
- File locks while server is running.
|
|
- Different SteamCMD output.
|
|
- Different permission/ownership behavior.
|
|
- Symlink/junction behavior is not portable enough for first version.
|
|
|
|
## DayZ-Specific Plan
|
|
|
|
DayZ should be the first full strategy because it exercises the hard cases.
|
|
|
|
XML:
|
|
|
|
```xml
|
|
<workshop_support>
|
|
<enabled>1</enabled>
|
|
<provider>steam</provider>
|
|
<steam_app_id>221100</steam_app_id>
|
|
<workshop_app_id>221100</workshop_app_id>
|
|
<download_method>steamcmd</download_method>
|
|
<install_strategy>dayz_mod_folder</install_strategy>
|
|
<install_path>{GAME_PATH}</install_path>
|
|
<mod_folder_format>@{SAFE_TITLE}</mod_folder_format>
|
|
<startup_param_format>-mod={MOD_LIST}</startup_param_format>
|
|
<mod_separator>;</mod_separator>
|
|
<copy_keys enabled="1">
|
|
<source_pattern>{MOD_PATH}/keys/*.bikey</source_pattern>
|
|
<target_path>{GAME_PATH}/keys</target_path>
|
|
</copy_keys>
|
|
</workshop_support>
|
|
```
|
|
|
|
Panel behavior:
|
|
|
|
- Accept Workshop URL/ID.
|
|
- Resolve title when possible.
|
|
- Store desired item row.
|
|
- Allow reorder.
|
|
- Allow enabled/disabled.
|
|
- Generate `-mod=` from enabled ordered mods.
|
|
- Prompt restart after changes.
|
|
|
|
Agent behavior:
|
|
|
|
- Download item.
|
|
- Install to `@ModName`.
|
|
- Copy keys.
|
|
- Write install manifest.
|
|
- Report clear failures:
|
|
- SteamCMD missing.
|
|
- Steam login required.
|
|
- Workshop item not found.
|
|
- Download path missing.
|
|
- Disk full.
|
|
- Key copy failed.
|
|
|
|
## Generic Game Support Plan
|
|
|
|
Each game should choose a strategy:
|
|
|
|
- Source/Garry's Mod: `game_managed_workshop`
|
|
- Rust: likely server-managed or game-specific strategy depending on current Rust mod ecosystem support.
|
|
- DayZ: `dayz_mod_folder`
|
|
- Arma 2/3: `arma_mod_folder`
|
|
- Generic file content: `copy_to_mod_folder` or `copy_to_game_root`
|
|
- Config packs: `config_only`
|
|
|
|
The UI can stay mostly the same while XML changes behavior behind the scenes.
|
|
|
|
## Commercial-Quality Expected Result
|
|
|
|
Customer experience:
|
|
|
|
- Paste Workshop URL or ID.
|
|
- See item title if available.
|
|
- Install one or many mods.
|
|
- See progress and logs.
|
|
- Enable/disable mods without deleting them.
|
|
- Reorder mods.
|
|
- Update selected or update all.
|
|
- Uninstall cleanly.
|
|
- See restart-required prompts.
|
|
- See clear errors that explain what failed.
|
|
|
|
Admin experience:
|
|
|
|
- Game XML declares support.
|
|
- Install strategy is selected by game.
|
|
- Steam app IDs are configured centrally.
|
|
- Startup parameter format is configured centrally.
|
|
- Key copy behavior is configured centrally.
|
|
- Cache policy is configured centrally.
|
|
- No customer-editable helper batch files are needed.
|
|
|
|
## Recommended Implementation Phases
|
|
|
|
### Phase 1: Inventory/report only
|
|
|
|
- Complete this report.
|
|
- Do not modify code.
|
|
|
|
### Phase 2: XML schema design
|
|
|
|
- Add `workshop_support` schema.
|
|
- Add parser helpers.
|
|
- Add validation warnings in config editor.
|
|
- Preserve old XML behavior.
|
|
|
|
### Phase 3: DB schema
|
|
|
|
- Add normalized Workshop metadata table.
|
|
- Add per-server Workshop item table.
|
|
- Add install job and job item tables.
|
|
- Migrate existing `server_content_workshop` rows.
|
|
|
|
### Phase 4: Panel UI
|
|
|
|
- Replace Phase 1 Workshop page with:
|
|
- URL/ID entry.
|
|
- Installed list.
|
|
- Enable/disable.
|
|
- Load order.
|
|
- Update/uninstall/repair.
|
|
- Live job log.
|
|
|
|
### Phase 5: Agent job runner
|
|
|
|
- Add first-class agent job actions.
|
|
- Return job ID immediately.
|
|
- Poll status/logs.
|
|
- Keep screen as shared backend.
|
|
|
|
### Phase 6: SteamCMD download job
|
|
|
|
- Implement cross-platform SteamCMD runner.
|
|
- Support anonymous and configured login.
|
|
- Redact credentials.
|
|
- Write progress/result files.
|
|
|
|
### Phase 7: DayZ strategy
|
|
|
|
- Download Workshop items.
|
|
- Install `@ModName` folders.
|
|
- Copy `.bikey` files.
|
|
- Generate `-mod=` startup fragment.
|
|
- Test install/update/disable/uninstall.
|
|
|
|
### Phase 8: Startup parameter integration
|
|
|
|
- Add structured generated startup fragments.
|
|
- Avoid duplicate raw params.
|
|
- Preserve existing game startup behavior.
|
|
|
|
### Phase 9: Update/uninstall/reorder
|
|
|
|
- Add update all/selected.
|
|
- Add repair.
|
|
- Add safe uninstall.
|
|
- Add load order persistence.
|
|
|
|
### Phase 10: Cache/clone support
|
|
|
|
- Add optional global cache.
|
|
- Add cleanup policy.
|
|
- Add clone mod list workflow.
|
|
|
|
### Phase 11: Additional game strategies
|
|
|
|
- Add Arma strategy.
|
|
- Add game-managed Workshop strategy for Garry's Mod/Source where appropriate.
|
|
- Add generic copy/config strategies.
|
|
|
|
## Open Questions
|
|
|
|
- Should the agent expose a new XML-RPC job API, or should the Panel continue to use `exec` for Phase 2?
|
|
- What should the canonical agent control path be outside customer-editable files?
|
|
- Can the current file manager/FTP layer hide `gsp_server_content` reliably if control files remain under game home?
|
|
- Which DB migration system should own the new tables?
|
|
- How should existing `server_content_workshop` rows be migrated to the proposed normalized tables?
|
|
- Where should Steam credentials be stored for Workshop items requiring login?
|
|
- Should per-server Steam credentials ever be supported, or admin-only credential profiles?
|
|
- Which games require authenticated Workshop downloads?
|
|
- How should Workshop metadata be fetched without a Steam Web API key?
|
|
- Should title resolution be required before install, or should `@<workshop_id>` always be allowed?
|
|
- How should conflicts be handled when two Workshop items normalize to the same folder name?
|
|
- Should DayZ keys be copied recursively by default or only from configured paths?
|
|
- How should key ownership be tracked for safe uninstall?
|
|
- Should updating mods while a server is running be blocked, staged, or allowed with restart required?
|
|
- Should global cache be enabled in commercial deployments by default?
|
|
- How should disk quota account for downloaded cache and installed copies?
|
|
- Should symlinks/junctions ever be used to avoid duplicate copies?
|
|
- How should Windows long paths be handled?
|
|
- Should Workshop install logs be exposed through the existing log viewer or a dedicated Server Content job log page?
|
|
|
|
## Summary Recommendation
|
|
|
|
Use the current Phase 1 Server Content work as a starting point, but do not keep extending it as a synchronous script runner.
|
|
|
|
The professional path is:
|
|
|
|
- Add XML-declared Workshop/content capabilities.
|
|
- Store desired Workshop state in the Panel database.
|
|
- Add pollable agent jobs for install/update/remove.
|
|
- Use SteamCMD on the agent.
|
|
- Implement game-specific strategies, starting with DayZ.
|
|
- Generate startup parameters from structured enabled/load-ordered rows.
|
|
- Treat LGSL/GameQ and game query systems as unrelated to content installation.
|
|
- Keep customers away from raw commands, helper scripts, and managed control files.
|