Panel/docs/features/WORKSHOP_SYSTEM.md
2026-06-09 06:13:44 -05:00

281 lines
11 KiB
Markdown

# Workshop System
Workspace reference: [`GSP-WORKSPACE.md`](../../../GSP-WORKSPACE.md)
## Current State
The current Workshop/content work is split across two module lines:
- `Panel/modules/steam_workshop` - deprecated compatibility layer
- `Panel/modules/addonsmanager` - the active Server Content Manager path
Important files:
- `Panel/modules/addonsmanager/module.php`
- `Panel/modules/addonsmanager/user_addons.php`
- `Panel/modules/addonsmanager/addons_manager.php`
- `Panel/modules/addonsmanager/workshop_content.php`
- `Panel/modules/addonsmanager/workshop_action.php`
- `Panel/modules/addonsmanager/scripts/workshop/generic_steam_workshop_linux.sh`
- `Panel/modules/addonsmanager/scripts/workshop/generic_steam_workshop_windows_cygwin.sh`
- `Panel/modules/steam_workshop/module.php`
- `Panel/modules/steam_workshop/agent_update_workshop.php`
## Current Implemented Behavior
Workshop is Panel-side orchestration. The active workflow lives in Server Content Manager and uses existing agent primitives only:
- Panel writes manifests with validated numeric Workshop IDs.
- Panel generates a per-job shell script under the server home.
- The generated job script writes a temporary SteamCMD runscript and runs `steamcmd +runscript <scriptfile>`.
- Panel invokes the job script through the existing authenticated agent `exec` RPC.
- Agents do not need new Workshop-specific business logic.
- Legacy agent RPCs from the old `steam_workshop` module remain compatibility-only and are not the primary path.
The active user workflow is now `addonsmanager` -> `workshop_content`.
Users can enter either:
- a numeric Workshop item ID
- a full Steam Workshop URL containing `id=<number>`
The Panel extracts and stores only numeric Workshop IDs. Invalid text is rejected before any manifest or shell command is built.
The Panel writes a manifest under the server home:
- `{SERVER_HOME}/gsp_server_content/workshop_manifest.json`
The Panel writes a generated per-job script to:
- `{SERVER_HOME}/gsp_server_content/jobs/workshop/workshop_job_<timestamp>_<random>.sh`
The agent executes the generated script with the manifest path by using the existing generic command execution path. Customers do not need to place scripts manually on the agent.
Script/job rules:
1. Server Content Manager always generates the primary Workshop job script per action.
2. Game XML does not define static agent script paths.
3. The default script filename must never be treated as a pre-existing agent path.
4. The agent does not require `generic_steam_workshop_linux.sh` or `generic_steam_workshop_windows_cygwin.sh` to exist on disk.
The generated job script uses this SteamCMD runscript pattern:
```text
@ShutdownOnFailedCommand 0
@NoPromptForPassword 1
force_install_dir <server_root>
login anonymous
workshop_download_item <workshop_app_id> <workshop_id> validate
quit
```
The manifest includes:
- `home_id`
- server/game path
- `workshop_app_id`
- Workshop item IDs
- per-item target paths
- install strategy
- key-copy settings
- content template metadata
Default install paths:
- Generic Workshop installs default to `{SERVER_ROOT}/workshop/{MOD_FOLDER}`.
- DayZ/Arma-style installs default to `dayz_mod_folder` or `arma_mod_folder` based on the game key/name/config file. Those strategies install to `{SERVER_ROOT}/{MOD_FOLDER}` so `@<workshop_id>` folders remain compatible with existing `-mod=` workflows.
- DayZ/Arma key-copy behavior copies `.bikey` files into the server `keys` folder when found. Missing key files are logged but do not fail the install.
App ID rules:
- `workshop_app_id` must come from the selected game's canonical `workshop_support` XML block.
- Server Content admin forms must not ask for Workshop app IDs, target paths, launch params, or Workshop script paths.
- Do not silently use the dedicated server Steam app ID as the Workshop app ID.
- Arma 3 XML declares Workshop app ID `107410`; its dedicated server Steam app ID remains `233780`.
Canonical XML:
```xml
<workshop_support>
<enabled>1</enabled>
<provider>steam</provider>
<steam_app_id>107410</steam_app_id>
<workshop_app_id>107410</workshop_app_id>
<download_method>steamcmd</download_method>
<install_strategy>arma_mod_folder</install_strategy>
<install_path>{SERVER_ROOT}/{MOD_FOLDER}</install_path>
<startup_param_format>-mod={MOD_LIST}</startup_param_format>
<mod_separator>;</mod_separator>
<mod_prefix>@</mod_prefix>
<copy_keys enabled="1">
<source_pattern>{MOD_PATH}/keys/*.bikey</source_pattern>
<target_path>{SERVER_ROOT}/keys</target_path>
</copy_keys>
<post_install_action></post_install_action>
</workshop_support>
```
The Panel helper parser reads `workshop_support` as the source of truth. New game XML must not use loose top-level Workshop tags, and the schema no longer accepts per-game static agent script tags such as `script_linux` or `script_windows`.
## Database State
`server_content_workshop` tracks:
- `content_id`
- `home_id`
- `workshop_app_id`
- `workshop_item_id`
- `title`
- `install_path`
- `install_strategy`
- `enabled`
- `load_order`
- `update_policy`
- `pending_action`
- `install_state`
- `last_installed_at`
- `last_updated_at`
- `last_error`
Current install states used by Phase 1:
- `queued`
- `installing`
- `installed`
- `downloaded`
- `failed`
- `removed`
`server_content_workshop_catalog` tracks known/common Workshop items seen through Server Content Manager:
- `workshop_id`
- `app_id`
- `title`
- `author`
- `thumbnail_url`
- `install_count`
- `first_seen`
- `last_installed`
- `last_updated`
- `published_date`
- `tags`
- `game_key`
- `local_cache_path`
The catalog is Panel-side and does not require Steam Web API metadata. It grows from real installs and can be searched by Workshop ID, Steam URL, keyword/title, author, tag, or game key. Metadata can be enriched later through Steam Web API or SteamCMD output parsing.
## What Exists Today
The current direction already supports:
- content records in the Panel database
- Workshop item IDs
- installation metadata
- install history tables
- XML-owned game compatibility fields
- XML-owned launch parameter format
- XML-owned post-install action placeholder
## Main Limitations
- Workshop metadata is still incomplete.
- Load order is tracked but not yet a full drag-and-drop or startup-param UX concept.
- Enable/disable is exposed and stored but does not yet regenerate startup parameters.
- update/remove are synchronous and should become background jobs.
- caching and cleanup policy need product-level design, not just ad hoc scripts.
- `-mod=` / `-serverMod=` generation still needs a safe structured implementation.
- Steam keyword/tag search currently searches the local Panel catalog and links to Steam's app-scoped Workshop search; direct Steam Web API search is Phase 2.
## Scheduler Integration
Workshop updates use the existing `cron` / Scheduler system. No second Workshop scheduler should be created.
Supported scheduler action keys:
- `workshop_update`
- `workshop_update_and_restart`
- `workshop_download_only`
- `workshop_install_pending_on_restart`
Compatibility Server Content keys remain available:
- `server_content_check_workshop_updates`
- `server_content_update_workshop`
- `server_content_install_updates_next_restart`
- `server_content_install_updates_and_restart`
Per-item update policy values stored on `server_content_workshop.update_policy`:
- `manual`
- `scheduled`
- `update_now`
- `update_and_restart`
- `download_only`
- `install_on_restart`
## Troubleshooting
| Symptom | Meaning | Fix |
|---|---|---|
| `Configured workshop script not found on agent host: generic_steam_workshop_windows_cygwin.sh` | Old Panel logic treated the default script filename as an agent path. | Update the Panel. Current logic generates a per-job script under `gsp_server_content/jobs/workshop/`. |
| `SteamCMD is missing on the agent host.` | The generated job could not find SteamCMD at `STEAMCMD_PATH` or common locations. | Install SteamCMD on the agent or set `STEAMCMD_PATH` for the agent environment. |
| `Workshop App ID is missing` | The selected game XML does not provide `workshop_support/workshop_app_id`. | Add a canonical `workshop_support` block to the game XML and validate it. |
| `This game XML does not enable Steam Workshop support` | The user opened Workshop for a game whose XML lacks enabled Workshop capability. | Add `workshop_support` with `enabled` and `workshop_app_id`, or do not expose Workshop for that game. |
| Download succeeds but mod does not load | Startup parameters are not yet regenerated from installed Workshop rows. | Manually add the installed `@...` folders to the game startup params until Phase 2 startup integration is complete. |
## Recommended Mental Model
Use `addonsmanager` as the main future home for:
- mods
- add-ons
- Workshop items
- scripts
- config packs
- server content manifests
- install history
Treat `steam_workshop` as a legacy bridge for migration only.
## References Reviewed
- `reference/Module-Steam_Workshop` is the local legacy OGP module. It confirms that the Panel historically owned Workshop state/configuration and used the agent for execution.
- The uploaded `steam-workshop-downloader` reference was not present in this workspace, but its reviewed behavior is reflected in the active design: generate a SteamCMD runscript, call `workshop_download_item <appid> <workshop_id> validate`, copy or link the downloaded `steamapps/workshop/content/<appid>/<workshop_id>` folder into the server's mod location, optionally lowercase files for Linux, copy Arma/DayZ keys, and generate future `-mod=` data from installed items.
## Panel-Agent Contract
Phase 1 does not use the legacy `steam_workshop` XML-RPC method for the primary user workflow. Instead:
1. Panel parses customer input into numeric Workshop IDs.
2. Panel writes `{SERVER_HOME}/gsp_server_content/workshop_manifest.json`.
3. Panel writes a generated per-job script under `{SERVER_HOME}/gsp_server_content/jobs/workshop/`.
4. The job script writes a temporary SteamCMD runscript.
5. Panel invokes the job script through the existing authenticated agent `exec` RPC.
6. The job writes `workshop_install.log` or `workshop_install_windows.log` under `gsp_server_content`.
7. Panel updates `server_content_workshop.install_state` from queued/installing to installed/failed/removed.
Important manifest fields:
- `home_id`
- `home_cfg_id`
- `game_path`
- `server_path`
- `workshop_app_id`
- `steam_app_id`
- `items`
- `item_details`
- `install_strategy`
- `target_path`
- `extra.copy_keys`
- `extra.keys_target_path`
Generated Workshop jobs validate numeric item IDs, keep writes under the server home, use SteamCMD through a temporary runscript, copy files into the resolved target path, and copy `.bikey` files for DayZ/Arma strategies when enabled.
Bundled handler actions:
- `install` - download with SteamCMD, copy/install into target path.
- `update` - validate/download with SteamCMD, copy/install into target path.
- `check_updates` - validate/download only; does not alter live mod folders.
- `download_only` - download/cache only and leave install pending.
- `validate_files` - SteamCMD validate/download only.
- `remove` - move the installed target folder into `gsp_server_content/workshop/removed/`; this does not require SteamCMD.