-
Notifications
You must be signed in to change notification settings - Fork 0
Installer
fuse_installer.py installs mod packages from zip files into the base folder's
Mods directory. It is designed for a bundled FUSE-Installer.exe, so users can
drop zip files beside the executable and run it from the base folder.
The published FUSE-Installer.exe carries the FUSE framework inside it, so it
works two ways:
- Double-click it (no arguments): it installs FUSE. This is the easiest way for a player to get FUSE running.
-
Drag one or more mod
.zipfiles onto it: it installs those mods. A drag-and-drop run installs exactly the mods you dropped and does not touch FUSE.
A no-argument run also installs any loose .zip files sitting beside the exe (in
addition to FUSE), so the "drop several zips in the folder and run once" workflow
still works. Existing mod folders are backed up and updated by default. Pass
--skip-existing to leave them alone, or --no-fuse to process only the loose
zips without installing the bundled FUSE package.
The published FUSE-Installer.exe is distributed via GitHub Releases:
https://github.com/F-U-S-E-E/FuseDevelopmentGroup/releases. The dist/ folder is gitignored,
so building locally produces a private copy at dist\FUSE-Installer.exe.
The installer inspects zip structure and manifest JSON only. It does not import, execute, or depend on any package code.
When FUSE is installed, the installer also creates a data-only UMM entry with
the historical id AssetLoader. This entry contains no DLL and runs no patches;
it exists so older mod manifests that require AssetLoader still pass UMM's
dependency check before their content is loaded through FUSE.
UMM code mods are reflected before their entry method runs. The installer also
checks each installed code DLL (without executing it) for references to the
RailLoader Interchange/Injector or Strange Customs contracts that FUSE replaces.
When found, it adds FUSE to that mod's Requirements and LoadAfter fields so
FUSE's compatibility resolver is active before UMM reflects the DLL. The
original Info.json is copied to a dated
Mods\ModBackups\FUSEInstaller\CompatibilityManifests-* folder first. This is
what allows separately installed UMM packages such as Alina Utilities to start
with the old loader DLLs absent. RailLoader-hosted data/code packages such as
Signals Everywhere follow the separate hosted-package path described below.
- UMM packages with
Info.json. - FUSE data packages with
Info.jsonand FUSE data markers such asFuseDataFiles,FuseAssetPacks, or a FUSE requirement. - RailLoader packages with
Definition.json, including data packages and code-only hosted plugins such as Signals Everywhere. - Multi-package zips laid out as
Mods/PackageA/...andMods/PackageB/....
Each archive is inspected and staged before anything replaces an installed mod.
One bad archive does not stop the remaining archives. The final table lists every
package as INSTALLED, UPDATED, SKIPPED, or FAILED.
Before writing any package, installer 0.8 scans the complete batch and checks:
- unsafe, absolute, parent-traversing, duplicate, or case-colliding ZIP paths;
- ambiguous layouts where one package manifest contains another package;
- duplicate package ids across all selected ZIPs (including
.FUSEaliases); -
Requirements,FuseRequires, and RailLoaderrequires, includingNotBefore/NotAfterversion bounds; - dependencies already installed or supplied later in the same batch; and
- dependency failure propagation, so a package that fails preflight cannot satisfy another package just by being present in the batch.
UMM's versioned string form is understood as well: for example,
GP38SoundMod-4.4.1 means package id GP38SoundMod, minimum version 4.4.1.
It is not treated as one literal package id.
Missing dependency results name the requester, dependency id, version bounds, and corrective action. FUSE satisfies only the legacy contracts it explicitly replaces (for example Alina's Map Mod, Strange Customs, Confusing Supplements, RailLoader Injector/Interchange, and AssetLoader); it does not broadly waive unrelated ZAMU or third-party requirements. Retired legacy version bounds are ignored only for those explicit FUSE replacement contracts. If an installed dependency has no readable version, the installer keeps the package eligible but records that the bound could not be verified.
To install FUSE:
- Install Unity Mod Manager for Railroader.
- Double-click
FUSE-Installer.exe. It searches registered Steam libraries for Railroader; use Browse if you have more than one copy or a non-Steam install. - Leave Install/update the bundled FUSE framework checked.
- Add any mod zips you also want to install, then click Install.
- Read the package-by-package result list before closing the window.
FUSE is written to Mods\FUSE.
To install mods:
- Drag one or more
.zipfiles ontoFUSE-Installer.exe, or open the installer and use Add zips. - Confirm the detected Railroader folder and click Install.
- Each package is written to
Mods\<package id>. Native FUSE, UMM, and hosted RailLoader-format packages can be selected together.
Existing folders are moved to
Mods\ModBackups\FUSEInstaller\<timestamp> before the new copy is installed.
Use --skip-existing only when you intentionally do not want updates.
Every non-dry run writes a machine-readable result under
Mods\FUSEInstaller\Reports so a failed package can be diagnosed without a
screenshot of the installer window. The report's compatibilityActions list
records each AssetLoader backup, alias installation, verification failure, or
blocked migration with its source and destination paths. Each package record
also preserves the dependency ids and version bounds used by preflight.
The same preflight and Tools > Dependency Graph now include locomotives, railcars, and other AssetLoader-style packages. FUSE combines four sources in this order:
- native FUSE fields in
Info.json; - UMM
Requirements/LoadAfterplus RailLoaderDefinition.json; - AssetLoader
Definitions.jsonto identify the package as equipment (asset identifiers are not guessed to be package dependencies); and - Nexus file-version requirements only when the local manifests have no hard requirements.
The installer performs Nexus lookup only when the archive manifest contains an
actual https://www.nexusmods.com/<game>/mods/<id> homepage and a Nexus API key
is supplied. It will not guess a mod page from numbers in an archive filename.
The GUI key field is optional and masked; the key is used only for that run and
is never written to a report or cache. CLI users should prefer the
NEXUS_API_KEY environment variable instead of putting a key in shell history.
Successful provenance and dependency results are written atomically to
Mods\.fuse-metadata\dependencies.json. The in-game graph reads that cache
offline; opening or refreshing a FUSE menu never contacts Nexus. Local explicit
metadata always wins over a cached Nexus edge, and cache records for removed
mod folders are ignored. Nexus dependency definitions containing multiple
alternative mods are reported but are not converted into a false hard
requirement.
Nexus API v3 currently marks the file-version dependency endpoints as experimental. See the official API v3 specification, authentication guidance, and acceptable-use policy.
Before installing, the tool checks the actual game folder, verifies Unity Mod
Manager is present, and looks for known legacy loader files in
Railroader_Data\Managed: Railloader.dll, Railloader.Injector.dll,
Railloader.Interchange.dll, and StrangeCustoms.dll.
If any are found, the installer stops and asks permission to move only those
exact files into a dated backup under
Mods\ModBackups\FUSEInstaller\LegacyLoader-<timestamp>. It does not silently
delete or patch game files. For an unattended repair, pass
--repair-legacy-loader.
Steam's Verify integrity of game files is useful if a game-owned file was modified, but it may leave extra third-party DLLs behind. Verification therefore does not replace the installer's explicit legacy-file check.
FUSE owns all three behaviors exposed by AssetLoader 1.0.1: package-root and
child Catalog.json store discovery, direct mod-folder store paths, and
definitions-only child-folder overrides used by rolling-stock/tender swaps.
During a FUSE install or update, the installer checks Mods for:
- an old
AssetLoaderUMM folder or any immediate mod folder containingAssetLoader.dll; - a loose
Mods\AssetLoader.dll; - a loose
Mods\AssetLoader.zip.
With approval, those exact paths are moved to
Mods\ModBackups\FUSEInstaller\AssetLoader-<timestamp>, then the installer
creates Mods\AssetLoader\Info.json as the data-only dependency alias. It
verifies that no old AssetLoader runtime remains. Use
--repair-asset-loader for an unattended migration. Dragging the old
AssetLoader ZIP onto the FUSE installer does not reinstall its DLL.
Do not simply delete AssetLoader by hand while older packages still declare it
as a UMM requirement. Either use the FUSE installer so the alias is created, or
update those package manifests to require FUSE instead.
Install every zip in the current folder:
.\FUSE-Installer.exeInstall explicit zips:
.\FUSE-Installer.exe .\MyPackage.zip .\OtherPackage.zipForce command-line mode (the published executable opens the graphical installer by default):
.\FUSE-Installer.exe --cli .\MyPackage.zip .\OtherPackage.zip --with-fuseInspect without writing:
.\FUSE-Installer.exe --dry-runInstall from a different location:
.\FUSE-Installer.exe --game-dir "D:\Games\BaseFolder" --inbox "D:\Downloads\Mods"Archive processed zips after successful installs:
.\FUSE-Installer.exe --archive-zipsFill genuine manifest gaps from Nexus for linked packages, without saving the key:
$env:NEXUS_API_KEY = "your personal key"
.\FUSE-Installer.exe --cli .\EquipmentPack.zip
Remove-Item Env:NEXUS_API_KEYFrom the repo root:
powershell -ExecutionPolicy Bypass -File .\tools\build_installer_exe.ps1If PyInstaller is not installed for the active Python environment:
powershell -ExecutionPolicy Bypass -File .\tools\build_installer_exe.ps1 -InstallPyInstallerThe output is dist\FUSE-Installer.exe.
Pass -FusePayload with the core FUSE mod zip (the FUSE-v*.zip produced by the
release build) to bundle FUSE inside the exe. A manual run of that exe then
installs FUSE:
powershell -ExecutionPolicy Bypass -File .\tools\build_installer_exe.ps1 -FusePayload .\FUSE-v1.0.2.zipThe release workflow does this automatically, passing the zip it just built. If
you build without -FusePayload, the exe still installs mods from dragged zips,
but a no-argument run has no FUSE to install and reports that instead. The
bundled-build smoke test verifies FUSE installation and AssetLoader migration
in a throwaway game folder.
Mirrored from docs/FUSE_INSTALLER.md — edit there, not here.