You must have Onward 1.7 installed in the steam/common folder with the mod installed. The mod injector looks for the .dlls in there.
| File | Purpose |
|---|---|
Models.cs |
Data models: RemoteModEntry, LocalModManifest, UpdateResult |
SemVer.cs |
Lightweight Major.Minor.Patch comparison |
ModUpdater.cs |
Core pipeline: fetch → diff → download → extract → callback |
MainThreadDispatcher.cs |
Queues callbacks onto Unity's main thread safely |
ModUpdaterPlugin.cs |
Example BepInEx plugin wiring everything together |
example_mod_manifest.json |
Sample remote JSON to host on GitHub |
-
Host the JSON manifest — push
example_mod_manifest.json(renamed as needed) to a GitHub repo and grab the raw URL. -
Host zip files — each mod is a
.zipwhose contents will be extracted directly intoBepInEx/plugins/<ModName>/. Structure the zip however your mod needs (DLLs, assets, configs, subfolders — all preserved). -
Add to your project — drop the
.csfiles into a BepInEx plugin project. Required references:UnityEngine,BepInEx,System.IO.Compression(ships with .NET Framework 4.6+ / .NET Standard 2.0). -
Update the URL in
ModUpdaterPlugin.csto point at your manifest.
// Create the updater
var updater = new ModUpdater(remoteUrl, Paths.PluginPath, OnComplete);
// Kick off (non-blocking, runs on background thread)
updater.StartUpdate();
// Poll from Update() or a UI coroutine
string status = updater.GetCurrentStatus();
// → "Downloading CoolMod (2/5)…"
// Completion callback (fires on main thread)
void OnComplete(UpdateResult result)
{
// result.Success — true if zero errors
// result.UpdatedCount — how many mods were downloaded
// result.FailedMods — list of mod names that errored
}Versions follow Major.Minor.Patch (e.g. 1.2.3).
A remote mod is downloaded only when its ModNumber is strictly
greater than the locally recorded version for the same UUID.
- Individual zip download/extraction failures are logged via
Debug.LogError, skipped, and the pipeline continues. - After all mods are processed, if any failed, a file
mod_update_errors.txtis written into the plugins folder listing every failed mod name. - The
UpdateResult.Successbool will befalseif any mod failed.
A mod_manifest.json file is maintained in BepInEx/plugins/
tracking every installed mod's UUID and version. This is what
gets compared against the remote list on each run.