# SymlinkModels Replace unwanted Sven Co-op player models with a neutral placeholder by symlinking them to `helmet.mdl`. This keeps your client from rendering anime, NSFW, or other models you don't want to see, while still letting you connect to any server that uses them. ## How it works For each model ID, the scripts create a relative symlink: ``` svencoop_addon/models/player//.mdl -> ../../../../svencoop/models/player/helmet/helmet.mdl ``` Every suppressed model renders as the default helmet instead. ## Prerequisites - Sven Co-op installed (scripts must run from the game's root folder, alongside `tags.json`) - Python 3.8+ **or** PowerShell 5.1+ - **Windows only:** Developer Mode enabled *(Settings → For developers)* **or** run as Administrator — both Windows symlink scripts check for this and warn if neither condition is met ## Files | File | Description | |---|---| | `tags.json` | Model ID lists grouped by category (`anime`, `nsfw`, `vehicle`) | | `symlink_models.py` | Python — symlink models from `tags.json`, a server path, or a text file | | `symlink_models.ps1` | PowerShell equivalent of `symlink_models.py` | | `symlink_downloads.py` | Python — symlink downloaded models that match `tags.json`, then optionally clean up `svencoop_downloads` | | `symlink_downloads.ps1` | PowerShell equivalent of `symlink_downloads.py` | | `server_models.txt` | Example model ID dump from a server, usable with `--from-file` | ## Usage Place the scripts and `tags.json` in your **Sven Co-op root folder** (the directory that contains `svencoop/` and `svencoop_addon/`). ### symlink_models — bulk symlink by source Symlinks every model ID from the selected source. **Python:** ```bash # Default: all IDs in tags.json python symlink_models.py # Scan a server's player/ directory python symlink_models.py --server /path/to/svencoop_addon/models/player # Read IDs from a text file (one ID per line) python symlink_models.py --from-file server_models.txt # Preview changes without writing anything python symlink_models.py --dry-run ``` **PowerShell:** ```powershell # Default: all IDs in tags.json .\symlink_models.ps1 # Scan a server's player/ directory .\symlink_models.ps1 -Server "C:\path\to\svencoop_addon\models\player" # Read IDs from a text file .\symlink_models.ps1 -FromFile server_models.txt # Preview changes without writing anything .\symlink_models.ps1 -DryRun ``` ### symlink_downloads — process already-downloaded models Scans `svencoop_downloads/models/player/` for `.mdl` files whose names match IDs in `tags.json`. For each match it creates the symlink in `svencoop_addon`, then lists the source folders and prompts whether to delete them. **Python:** ```bash python symlink_downloads.py # Preview without writing or deleting python symlink_downloads.py --dry-run ``` **PowerShell:** ```powershell .\symlink_downloads.py # Preview without writing or deleting .\symlink_downloads.ps1 -DryRun ``` The `svencoop_downloads/models/player/` root itself is never deleted — only matched sub-folders. ### Dumping model IDs from a server If you have access to a server's files (directly or via a network mount), you can dump its player model IDs to a text file and feed it to `symlink_models`: **Linux/macOS:** ```bash find /path/to/svencoop_addon/models/player \ -mindepth 2 -maxdepth 2 -name "*.mdl" -printf "%f\n" \ | sed 's/\.mdl$//' > server_models.txt ``` **PowerShell:** ```powershell Get-ChildItem -Path "C:\path\to\svencoop_addon\models\player" -Recurse -Filter "*.mdl" | Where-Object { $_.DirectoryName -ne "...\player" } | ForEach-Object { $_.BaseName } | Sort-Object -Unique | Set-Content server_models.txt ``` ## tags.json The tag file is a flat JSON object with three category arrays: ```json { "anime": ["2d_ab_kanna_coco", "sagas_trunks_ssj", ...], "nsfw": [...], "vehicle": [...] } ``` - **anime** (~2,129 entries) — anime character models - **nsfw** (~579 entries) — adult content models - **vehicle** (~73 entries) — vehicle models Model IDs are lowercase with underscores or hyphens. Version suffixes like `_v2` and `_hd` are treated as separate entries. To add or remove a model, edit the relevant array directly. Existing entries are not fully sorted, but try to insert near alphabetical neighbours. ## Output Each script prints one line per model processed and a summary on exit: ``` [anime] — 2129 models create : 2d_ab_kanna_coco skipped : 2d_ab_kratos replace : sagas_trunks_ssj 147 symlinks written (147 new, 0 replaced), 1982 already correct ``` Exit codes are 0 on success, non-zero on a fatal error (missing `helmet.mdl`, bad path, etc.).