Outward
Install with App

Details

Latest version
0.2.0
Last Updated
First Uploaded
Downloads
205
Likes
0
Size
295KB
Dependants

Categories

Cloudward changelog

0.2.0 — 2026-08-28

  • You can now see the launch sync working. When the boot pull takes more than a moment (a first sync, or a big share over a slow connection), a small progress bar and status line appear at the bottom of the main menu — "checking share…", "syncing saves… 12/44", then a brief "sync complete — pulled 40" — and disappear on their own. A fast sync shows nothing; there is no setting. Previously a multi-minute first sync was indistinguishable from a hang without reading the log.

  • Boot sync can no longer fail in total silence (V-SILENTBOOT, found live on a device that never pulled the share's characters). The boot pass now logs a synchronous boot reconcile queued: line before any mount I/O, a boot reconcile done: pulled=… pushed=… summary on completion (including the previously-silent save-in-progress skip), and a patch ledger: applied=2/2 line proving the Harmony hooks bound. A stall watchdog warns once when a background sync op runs past 60 seconds — the signature of a hung network mount, which blocks forever without throwing and used to silently starve every heartbeat for the rest of the session.

  • A misconfigured share that resolves to a local folder now names itself (V-SHADOWSHARE). A one-shot boot probe reads the game process's own mount table and warns if [Sync] MountPath resolves to a local filesystem instead of a real network share, instead of silently syncing against an empty private replica forever.

  • The save-set pin no longer engages at every main menu (V-MENUPIN). It was reading a local-player UI slot count that is true from the moment the main menu itself is shown, not from an actual character being loaded — so the boot pull deferred on every single launch, on every device, since the pin shipped. Removed in favour of the three real signals (save in progress, a load sequence running, any character actually in use), which already cover the wedge this pin exists to prevent.

  • The Thunderstore package now actually ships the preloader patcher. Cloudward.Preload has to live in BepInEx/patchers/: it is what applies an adopted payload, and it can only run before the plugins load. It was never included in the Thunderstore package at all, so for anyone who installed Cloudward that way the payload tier could sync but never apply. Manual installs and the hand-off bundle already shipped it.

  • Fixed: the overlays/ folder was about to be flattened by r2modman, which would have left the config tier with no overlays to read. Same packaging cause as the Beastwhispering fix; 0.1.1 predates the folder, so no released version was affected.

  • Also since 0.1.1: the kit versioning contract (KitContract handshake, COMPAT_SINCE, [BepInDependency] version floors), a wave of payload-integrity and reliability fixes (locked+gated boot repair, quit-time publish budget, stale-receipt generation checks, share-tree crash windows, late-mount recovery, join-race protection), clearer failure logging throughout (say when a decision was downgraded; several silent failures made loud), a single share-temp-name/path-denormaliser instead of three separate ones, and the Forge shell / dev-tooling work this mod's live-testing leaned on all session.

Payload sync (mod folders + mod config)

  • New [Payload] tier: sync your mod folders and mod configuration across devices, alongside saves. Off by default ([Payload] Enable = false) — it rewrites BepInEx/plugins, so it has to be a decision rather than a side effect of turning save sync on.
  • Change detection is free in the steady state. A directory walk produces a size+mtime signature; if it is unchanged, the tier's content fingerprint is reused and zero bytes are hashed. On a miss, only the files whose stats moved are re-hashed. mtime is a cache key only — content SHA256 is always the authority, because cp -a, rsync -a and installers all preserve or reset mtimes in ways that lie.
  • Adopting a payload never touches the running session. BepInEx loads plugin assemblies at process start and reads each plugin's .cfg in its constructor, so an incoming payload is fetched into BepInEx/cloudward-staged/ and applied by a new preloader patcher (BepInEx/patchers/Cloudward.Preload.dll) at the next launch, before the chainloader runs. The patcher verifies every staged file's SHA256 before touching anything: a truncated network fetch discards the staging tree and leaves the install untouched, rather than producing a half-updated plugins folder that loads no mods at all.
  • The config tier moves values, not files, and only the keys named in plugins/Cloudward/overlays/*.cfg.overlay — the same allowlist scripts/sync-config.py uses. Everything else in your .cfg files is host-local and its bytes are never rewritten, so MountPath, DeviceName, keybinds, resolution and joystick GUIDs cannot travel. A no-op merge is byte-identical, enforced in code.
  • The first boot against a new share reports what it would do and changes nothing.
  • Configs, saves, logs, pet files, registries and dev command channels can never ride the plugins tier — that exclusion is compiled in, not a config setting, and ExtraExcludes can only add to it.
  • Divergence (both sides changed) pauses by default rather than guessing: unlike a save fork there is no newest-wins heuristic worth automating when a wrong pick installs the wrong code.
  • Backups before every replace, on the share and locally; payloadrollback restores.
  • Kill switch that works without launching the game: create .cloudward-disable in the game root.
  • Refuses to run on an IL2CPP install, and refuses to adopt a payload from a device whose BepInEx loader differs from this one's.
  • New verbs: payloadstatus, payloadscan, payloadpush, payloadstage, payloadresolve, payloadrollback, payloadapply.
  • Save-tier fixes carried along: the device-local state file is now written temp-then-swap (a second background worker now exists in the process), and a share set up payload-first is recognised as real data by the mount-marker recovery check.

0.1.0 — initial release

  • Cross-device save sync via a mounted/shared directory: always-local writes, boot-time reconcile (pull), play/quit push, offline-first.
  • Fork detection via a share-side generation ledger; a genuine divergence pauses instead of auto-merging or auto-discarding (syncresolve local|share|both).
  • Marker-file mount guard (an unmounted mountpoint looks like an empty directory otherwise).
  • Crash-safe heartbeat session lock — a stale lock is reclaimable by any device, and a device's own crashed lock reclaims instantly on relaunch.
  • Verbs: syncstatus, syncnow, syncresolve, synclock, syncmarker, selftest.
  • Alpha — design complete, compute layer unit-tested (tests/Cloudward.Tests), not yet live-verified on a real multi-device session. See the README's known-limitations note.
Thunderstore development is made possible with ads. Please consider making an exception to your adblock.