11 KiB
Workshop System
Workspace reference: GSP-WORKSPACE.md
Current State
The current Workshop/content work is split across two module lines:
Panel/modules/steam_workshop- deprecated compatibility layerPanel/modules/addonsmanager- the active Server Content Manager path
Important files:
Panel/modules/addonsmanager/module.phpPanel/modules/addonsmanager/user_addons.phpPanel/modules/addonsmanager/addons_manager.phpPanel/modules/addonsmanager/workshop_content.phpPanel/modules/addonsmanager/workshop_action.phpPanel/modules/addonsmanager/scripts/workshop/generic_steam_workshop_linux.shPanel/modules/addonsmanager/scripts/workshop/generic_steam_workshop_windows_cygwin.shPanel/modules/steam_workshop/module.phpPanel/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
execRPC. - Agents do not need new Workshop-specific business logic.
- Legacy agent RPCs from the old
steam_workshopmodule 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:
- Server Content Manager always generates the primary Workshop job script per action.
- Game XML does not define static agent script paths.
- The default script filename must never be treated as a pre-existing agent path.
- The agent does not require
generic_steam_workshop_linux.shorgeneric_steam_workshop_windows_cygwin.shto exist on disk.
The generated job script uses this SteamCMD runscript pattern:
@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_folderorarma_mod_folderbased 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
.bikeyfiles into the serverkeysfolder when found. Missing key files are logged but do not fail the install.
App ID rules:
workshop_app_idmust come from the selected game's canonicalworkshop_supportXML 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 remains233780.
Canonical 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_idhome_idworkshop_app_idworkshop_item_idtitleinstall_pathinstall_strategyenabledload_orderupdate_policypending_actioninstall_statelast_installed_atlast_updated_atlast_error
Current install states used by Phase 1:
queuedinstallinginstalleddownloadedfailedremoved
server_content_workshop_catalog tracks known/common Workshop items seen through Server Content Manager:
workshop_idapp_idtitleauthorthumbnail_urlinstall_countfirst_seenlast_installedlast_updatedpublished_datetagsgame_keylocal_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_updateworkshop_update_and_restartworkshop_download_onlyworkshop_install_pending_on_restart
Compatibility Server Content keys remain available:
server_content_check_workshop_updatesserver_content_update_workshopserver_content_install_updates_next_restartserver_content_install_updates_and_restart
Per-item update policy values stored on server_content_workshop.update_policy:
manualscheduledupdate_nowupdate_and_restartdownload_onlyinstall_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_Workshopis 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-downloaderreference was not present in this workspace, but its reviewed behavior is reflected in the active design: generate a SteamCMD runscript, callworkshop_download_item <appid> <workshop_id> validate, copy or link the downloadedsteamapps/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:
- Panel parses customer input into numeric Workshop IDs.
- Panel writes
{SERVER_HOME}/gsp_server_content/workshop_manifest.json. - Panel writes a generated per-job script under
{SERVER_HOME}/gsp_server_content/jobs/workshop/. - The job script writes a temporary SteamCMD runscript.
- Panel invokes the job script through the existing authenticated agent
execRPC. - The job writes
workshop_install.logorworkshop_install_windows.logundergsp_server_content. - Panel updates
server_content_workshop.install_statefrom queued/installing to installed/failed/removed.
Important manifest fields:
home_idhome_cfg_idgame_pathserver_pathworkshop_app_idsteam_app_iditemsitem_detailsinstall_strategytarget_pathextra.copy_keysextra.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 intogsp_server_content/workshop/removed/; this does not require SteamCMD.