maks2204-BestAutoSort icon

BestAutoSort

Standalone storage mod: shared chests, quick-stack, restock, rules, crafting from chests, autofeed, upgrades, sort.

CHANGELOG

Changelog

0.6.28 (hash anchor on every save)

  • A postfix on vanilla Container.Save re-anchors the session content hash after every save, covering host-side vanilla drags, in-chest moves, loans and sorts that persist outside any Tx commit (proven by decompilation: inventory.m_onChanged auto-saves for the owner).

0.6.27 (save-anchored session hash)

  • Every direct container save re-anchors the session content hash, so host-side crafting loans, sorts, trash and restocks no longer trip FOREIGN-WRITE quarantine on the next remote op.

0.6.26 (live-commit hash re-anchor)

  • Host live commits re-anchor the session content hash after saving, so the next remote job no longer reads our own save as a foreign write (fixes FOREIGN-WRITE quarantine bricking host-mode chests).

0.6.25 (host viewer refresh)

  • Hosts holding a managed chest open now poll-refresh like remote viewers (the manager skip assumed RAM==truth, false when remotes commit via session/ZDO). Dedicated/single-player unaffected.

0.6.24 (delta pricing + pocket refund)

  • Upgrades charge target-minus-current per resource (no double-paying overlap); unreadable current recipe degrades to full price, never free.
  • Previous-tier-unique mats (e.g. iron for reinforced-to-blackmetal) are refunded to the upgrader's pockets in the upgrade response (refund-once guarded, ground fallback when full).

0.6.23 (server dims follow chest tier)

  • Server chest sessions grow their working inventory from the tier prefab when a tier marker is present — moves/adds into upgrade-added slots are accepted instead of rejected.

0.6.22 (keep native colliders on tier-matching chests)

  • Prefab/tier-matching chests no longer get a visual overlay (native look, dims and colliders are already correct) — fixes upgraded chests becoming unopenable (no hover prompt).

0.6.21 (upgrade look for non-wood chests)

  • In-place upgraded non-wood chests take the target-tier look via the legacy-visual path (prefab/marker mismatch branch); prefab-matching chests keep the compact path byte-identical.

0.6.20 (natural chest tiers)

  • Tier resolution: explicit marker always wins; unmarked chests resolve by prefab (natural reinforced/blackmetal/grausten are tiers 1/2/3) — upgrade buttons and server validation work for them.
  • ApplyState skips unmarked chests (vanilla look/dims preserved); tier template dims/name applied on upgrade (never shrinks).
  • Tier-table unit tests pinned in the harness.

0.6.19 (upgrade diagnostics)

  • Upgrade visual pipeline fully instrumented (all silent failure exits + install scale sanity); submit logs prefab/marker/dims/tier/costs for old-chest upgrade diagnosis.

0.6.18 (upgrade staging keep)

  • Mediated upgrade gather registers staged mats (NoteUpgradeStaged) so the ahead-stage ledger holds them for the second press instead of returning them immediately (fetch-return loop fixed).

0.6.17 (server marker upgrade + split costs)

  • Server executes UpgradeRequest in place: pure tier-path check, costs verified + deducted from chest, marker key set, receipt=self. No structural replace on dedicated; ghost path kept for host/legacy.
  • Split costs: player covers shortfalls via claimed snapshots (shared Add-claim dedup, removed only on terminal Accept); server deducts the remainder strictly. Full chests upgrade without deposit space.
  • UpgradeRequest carries player-cost items (tolerant trailing wire field); host deposits first, then ghost as before.
  • Client applies marker + resize + effects on self-receipt.

0.6.16 (feed flight visuals)

  • Autofeed renders local flight visuals (chest to animal mouth) on successful feed; watchers already covered by server broadcast.

0.6.15 (upgrade-missing diagnostics)

  • Upgrade missing-resources check logs need/have/invStacks per requirement (diagnoses stale-viewer vs genuinely-short materials).

0.6.14 (feeder-anchored range)

  • Range enforced against the server-resolved actor position (+15m lag slack); client-stamped position drives visuals only (fixes autofeed pos-mismatch storm while moving).
  • Feeder Takes carry the hungry animal ZDO (FeederId, tolerant trailing wire field); range anchors at the server-verified animal (Tameable prefab + AutoFeedRange), player position irrelevant for AfK farms. Identity/privacy/wards unchanged.

0.6.13 (server-mediated chest destroy)

  • Hammer-remove of managed chests goes through the server: spill from server truth (Take-shaped bodies, zero new codec), ZDO delete, session drop, txId-keyed tombstone replays, idempotent gone-handling.
  • Guards: eligibility, decode, m_canBeRemoved, privacy+nonempty, full access (range+slack/wards/creator), sender binding + compat, claim- verified delete. Deny/timeout keep the chest with a message.
  • No-dupe discipline: stale-txId drop, refund-once set, session reset on UID/world change, fault directions fail-closed.
  • Residuals: damage-destroy path, no-build/station gates, cross-client in-flight races (Indeterminate), restart-wiped tombs.

0.6.12 (review-loop hardening: gate order, auth, fault directions)

  • OnRequest gate order mirrors production (binding, replay, transient, ring-corrupt, unsupported, access, virgin, owner, revalidation, quarantine, flagged, floor, fence). AnswerQuery consults the transient set; undecodable requests answer UnknownTx.
  • Response sender authenticated (server peer only); range checked against server-resolved position with 8m slack; guard/ward faults fail closed; prune throttled (10s); foreign-write refusals go through the durable quarantine matrix.

0.6.11 (virgin clear-to-0, content-hash revalidation)

  • Virgin birth converges ownership to 0 (verified by read-back): new chests servable immediately, broadcast open-routing intact, no reassignment. Ownership guards allow uid==0 everywhere (relinquish is never a takeover).
  • Content-hash (FNV-1a-64) revalidation replaces revision compare: benign bumps (lid toggles) pass, real s_items divergence quarantines. Baselines stamped on every server save + at session creation.
  • Removed: virgin-born pin/bypass fields, ServerZdoSet choke, VirginRev.

0.6.10 (virgin-born owner bypass + continuous revalidation)

  • Virgin attempt runs before the owner gate (superseded in 0.6.11 by clear-to-0: bypass fields removed).
  • Bounded trust via content hash (supersedes the revision-stamp scheme: ServerZdoSet/VirginRev removed in 0.6.11).

0.6.9 (virgin veto refinement)

  • Virgin veto refined: only committed ring entries (Accepted/Partial/ Duplicate via TxRing.IsCommittedStatus) block; Rejected-only rings and floor keys no longer self-poison virgin chests. Corrupt rings still veto.

0.6.8 (virgin init, submit truth, honest Take diagnostics)

  • Virgin-chest initialization: ownerless s_items-null with no ring/floor history materializes a vanilla-empty blob and serves (new chests usable); any history/live owner keeps the quarantine.
  • SEND line carries items=/expected= submit truth (open AddBatch arity case).
  • Answer() logs takes= blob count for Take ops instead of a fake int sum.

0.6.7 (remote flow visuals, guard no-op quiet, arity diagnostics)

  • Server broadcasts TxFlights after Add/AddBatch/TakeBatch commits: watchers see other players' quick-stack icons (same packet, ZDO-sourced).
  • Ownership guards pass through no-op changes (owner==requested) silently; real changes still blocked + counted.
  • Arity diagnostics: client logs expected/bodyLen/bodyFirst on add-body mismatch; server logs op/acceptedTotal per response (open AddBatch case).

0.6.6 (Move/Sort served, settle removed)

  • Server manager serves Move/Sort (pure-inventory shared Execute paths).
  • Settle-HOLD fully removed: requests execute immediately (strict parity with the production Takeover path; the live-owner gate already excludes concurrent writers before execution). Zero open-delay by construction.
  • Single-writer owner gate (code shipped in 0.6.3, documented here): serve only owner==0/self/dead-peer, else ephemeral Rejected; ownership never mutated.

0.6.5 (ZDO-level ward evaluation)

  • Server access gate evaluates wards from ZDO data (sector scan, s_enabled, prefab m_radius, s_creator + pu_id list); no covering ward allows exactly like vanilla. Ward-opted fail-closed removed.

0.6.4 (server transport framing fix)

  • KindTx byte on server request/response outer frames (was misparsed as kind, all tx traffic silently dropped; ping/pong unaffected).

0.6.3 (unreleased: option-B server manager, slices 1-3)

  • Slice 1 (transport): instance-independent global RPCs BestAutoSort_TxServerRequest/Response (ZDOID.None dispatch, Hello precedent); client ping every 60s, first pong logged unconditionally. Zero GameObjects needed.
  • Slice 2 (sessions + codec): ZDO-keyed ServerChestSession (dims from prefab Container, quarantine-first); decode/encode via vanilla Inventory.Load/Save (byte-identical by construction); zdo.Set auto-bumps revision; restart recovery via durable ring/floor reseed.
  • Slice 3 (manager): ZDO-only Take/Add(+Batch) through the SHARED ExecuteCall (rule/reserve ZDO overloads, ExecZdo context); shared idempotency (Processed/ProcOrder/Floor), durable ring/floor, quarantine matrix, spoof/binding gates mirrored; access mirrors ChestAuthority.CanUse (ZDO/prefab sources); new sessions HOLD 8s (rev-re-armed) with deferred answers; unsupported ops -> persisted Rejected; legacy chests never answered (silent drop).
  • Residuals: Move/Sort/Upgrade/SetRule on dedicated stay Rejected; ward-opted chests fail closed; slice-4 freshness barrier pending (settle narrows, does not close, the proven ClaimOwnership race); m_privacy read from prefab.

0.6.2 (unreleased: Awake-independent authority discovery sweep)

  • Server-only discovery sweep every 15s (PumpAuthoritySweep): live managed chests missing from States (Awake edge never fired — late zone activation on dedicated servers) get the exact Awake registration (RPCs + state + EnsureOnAwake adoption). Adoption stays metadata-only + quarantine-first; the sweep path skips the verified-init materialization (fromSweep, timer paths NEVER materialize holds literally); unconditional log on change + 5-min heartbeat (discovery sweep found=/managed=/registered=).
  • Known residual (proven by decompilation, fix deferred): ClaimOwnership is a local flag flip with no flush handshake — the server is not guaranteed the ex-owner's latest state at adoption. Mitigations active: quarantine on null/invalid, owner-gated writes, SetOwnerInternal guard; freshness handshake (ForceSendZDO + DataRevision compare) is the planned second stage.

0.6.2-DIAG (temporary dedicated-server silence diagnostics, revert after diagnosis)

  • Temporary verbose probes only, no behavior change: [ChestTX] config: startup dump (TxVerbose/mode/effective), authority awake probe at EnsureOnAwake entry, container awake: <name> at OnContainerAwake entry. Purpose: prove whether Container.Awake/adoption runs at all on the dedicated server (live symptom: client SENDs, zero server ChestTX lines, every op Indeterminate). Revert before any release.

0.6.1 (experimental: full review-loop fixes on 0.6.x)

  • Review-loop hardening: dead authority seams wired into production (remote-mutation ban, stale-route drop, structural single rule); quarantine gates on craft consume/loan and SortLocal paths (incl. priority loan); manifest 0.6.x packaging consistent; README experimental banner + wire/ops table; threat model stated; verification table narrowed to seam-confirmed with wiring-assumed + transient C15 row.
  • Residuals unchanged from 0.6.0 (live multi-peer traces outstanding).

0.6.0 (experimental: server-authoritative chests, invariant NOT claimed pending live multi-peer verification)

  • Server-authority migration (waves 1-3): canonical eligible-chest policy, authority UID, ServerAuthority (default) + LegacyDistributed modes with Hello/mode compat; source guards (open/stack/take-all without SetOwner, ReleaseNearbyZDOS exclusion, RPC_ZDOData boundary, ClaimOwnership block); server-only metadata adoption with quarantine-first; IsAuthorityManager routing for every mutation path with stale-route drop; host queue-serialized; remote Upgrade fail-closed; timer null-heals disabled in authority mode; ForceSendZDO documented as viewer-propagation hint.
  • Server-mediated remote chest upgrade (TxOp.UpgradeRequest, honest-weak): ghost protocol (spawn -> sync reverse-link -> copy -> Ready -> one-way pointer switch -> receipt -> idempotent retire); op-keyed entitlements; legacy direct-upgrade frames refused. Residuals in docs/remote-upgrade-mediated.md.
  • Residuals: live multi-peer traces outstanding; client-crash/ACK/eviction/post-write/SetRule/Upgrade-structural/response-trust gaps unchanged from v0.5.x; vanilla clients unsupported for managed chests.

0.6.x-Dedicated-Test remote upgrade (experimental slice, honest-weak)

  • Server-mediated remote chest upgrade (TxOp.UpgradeRequest): client sends a REQUEST (source ZDOID + authenticated sender + durable client nonce = fencing txId counter half + tier); the server executes the ghost protocol in its per-chest manager queue (pure core TxUpgradeManager/TxUpgradeGate in BestAutoSort.TxCore/TxUpgradeOp.cs, production host in src/Tx/TxRemoteUpgrade.cs). Spawn -> synchronous reverse-link write -> non-destructive copy -> validate Ready -> one-way pointer switch -> receipt -> idempotent retire; same op never spawns twice (record gate + reverse-link adoption); different ops queue behind the prepared head.
  • Ingredients pre-deposited in the source chest via normal ChestTX Takes; the op never charges the client inventory; spend recorded at-most-once, refunds only as an op-keyed entitlement via the idempotent ClaimRefund step. Old TxOp.Upgrade frames refused for managed chests in authority mode; host-local upgrades route through the same queue. UI closes the old view, shows locked-pending, and opens the new view only on a validated receipt; timeouts re-query the same op.
  • Residuals (documented in docs/remote-upgrade-mediated.md): hard-kill mint-link micro-window => unlinked ghost kept standing + quarantine + manual reconcile; copy-window duplication safe-direction; totals-only ring replay loses the receipt (manual check, never auto-open).

0.6.x-Dedicated-Test wave 1 (experimental slice, invariant NOT claimed)

  • Server-authority migration, vertical slice: canonical eligible-chest policy (stationary storage in, player/tomb/wagon/ship/moving/unknown out), authority UID (server GetUID / client server-peer uid, unknown fail closed), ServerAuthority (default) + LegacyDistributed modes with Hello/mode compat negotiation (mismatched peers rejected; vanilla clients unsupported for managed chests).
  • Source guards for eligible chests only: access-checked open grant without SetOwner (lease still denies); request-stack/take-all denied regardless of IsShared; TakeAllResponse claim suppressed; ZDO.SetOwner/SetOwnerInternal ownership backstop (toward-authority only); mod/client ClaimOwnership blocked with diagnosis; ReleaseNearbyZDOS redistribution exclusion via verified transpiler (2/2 sites, fail-closed SetOwner backstop on IL change); GUI/TakeAll/StackAll view-only for non-owners outside the shared path.
  • Server-only EnsureServerOwnership (awake/discovery/tx-request hooks, metadata-only, pre-mutation s_items + ring/floor read, quarantine on untrusted, verified-init empty-blob materialize only, ZDOID/old/new/reason logs + repair counters). AutoFeed untouched (animal-owner scheduling, no creature ownership change). Takeover/LastOwner/TxNullEscape retained.

0.5.15

  • s_items load-gate hardening: null is never empty, blobs validated before Load with RAM-snapshot restore, defensive byte clones, vanilla handoff order.

0.5.14

  • Transient send-path one-way invariant: no unflagged fallback after transient state; flagged Query-or-Wait with Pending/claims retained.

0.5.13

  • Authoritative transient-retry flag: flagged requests never execute as fresh, even on a clean new manager; clean-handoff proof.

0.5.12

  • Transient same-tx retry (non-terminal) with bounded backoff; crash-resistant counter blocked marker.

0.5.11

  • Quarantine durable-terminal matrix; persistent counter block surviving restart; replay op-mismatch guard.

0.5.10

  • Quarantine fence-first, counter fail-closed, replay op guard, fence propagation requests.

0.5.9

  • Wave-1 isolation + v3 hardening: ephemeral spoof, quarantine fencing, drain/claims lifecycle, drag gate, atomic counter.

0.5.8

  • Authoritative inventory reload + quarantine for post-fence failures.

0.5.7

  • Durable pre-execution floor fence before every fresh mutation; crash-safe tx ordering.

0.5.6

  • Canonical peer identity (negative UID support), durable floor, corrupt-ring degraded recovery.

0.5.5

  • Persistent ring v2 with stable terminal outcomes across handoff; UnknownTx is Indeterminate.

0.5.4

  • Ring includes the committed tx before handoff; UnknownTx no longer treated as committed.

0.5.3

  • Eggs quick-stackable behind TreatEggsAsAutoStack (default on); quickstack empty-diagnosis logging; issue #10 listen-server actor-first authority fix.
  • Quick-stack duplication race fix (also on branch): ExecuteAdd credits clamped to the live source stack.

0.4.0

  • Legacy chests no longer shrink a larger runtime inventory applied by other mods (final = max(current, template), issue #8).
  • Eating food from a shared chest as non-owner no longer pulls the whole stack into inventory (take 1 unit, issue #6).

0.3.2

  • Staged-stock return no longer breaks crafting (craft stages untracked) and no longer loops on upgrades (recent-upgrade keep window).

0.3.1

  • Deferred building pipelines the next set (no more multi-click starvation); unused staged stock returns to chests on selection change, hammer put-away, or late landing.

0.3.0

  • Absolute tx idempotency (no re-apply after handoff), retry-or-loud client, no-void compensation.
  • Owned-chest persistence everywhere (restock, loans, quick-stack into open, trash, sort, replacement).
  • Deferred builds and upgrades consume chest stock; quest items never leak via TakeAll/drop/right-click.
  • Shared-mode deny for direct TakeAll RPC; lease-safe chest open; drag-take lands in the drop cell.

0.2.0

  • Feeder flights target the animal, not the player.
  • Upgrade button stages chest stock and consumes owned-chest resources; replacement chest contents persisted (no more ghost items).
  • Chest buttons narrowed to Trash/Stack width; Sort Chest renamed to Sort.

0.1.10

  • BepInExPack 5.4.2350, simultaneous-access highlight, protocol docs.

0.1.9

  • Simultaneous chest access highlight, protocol docs with diagrams, packaging fixes.

0.1.8

  • Transport-safe batching, feeder on transactions, deferred placement, conservation gates.

0.1.7

  • Pull-on-press crafting (no browse-time floods), chest-inclusive craft/build display, DoCrafting conservation gate.
  • In-flight Add deduplication, drag/grid-inventory fixes, monotonic viewer, GearSlots tag handling.
  • Verified against Valheim 1.0.12.

0.1.6

  • Wire protocol v2 (client-stamped actor position), build commit hash baked into the DLL.

0.1.5

  • Quick-stack outcome visibility and skip diagnostics, build tag in startup log.

0.1.4

  • Owner quick-stack through the tx queue (broadcasts for all), quick-stack entry logging.

0.1.3

  • Flight visuals broadcast (TxFlights) + manager-side play for remote batches.

0.1.2

  • Fix response body framing (nested package was read flat: Adds silently applied 0, Takes crashed) and short presence/query bodies (heartbeats died, lid flapped).

0.1.1

  • Wire protocol fix (ProtoVersion header) + version gate: mixed 0.1.0/0.1.1 peers are rejected loudly instead of silent garbage.

0.1.0

  • Rebrand to BestAutoSort (dev.maks2204.bestautosort): new GUID, name, version, own plugin folder.
  • Fresh config dev.maks2204.bestautosort.cfg, no legacy imports.
  • Console command renamed to bestautosort.
  • Full storage feature set (quick-stack, restock, rules, crafting/fuel from chests, autofeed, shared chests, upgrades, sort, trash), no ModCore dependency.
  • Own save-data keys, no compatibility with other storage mods by design.