Longhouse 2.0.5
11 September 2026. After 2.0.4.
Repins Vaettir to 1.5.1.
Fixed
-
The stowing post could report having nowhere to go while a correctly configured chest stood in range, could send its spirit back and forth without ever delivering, and - once trips started landing again - could duplicate what it moved. Three bugs, each one hidden by the one before it, all older than Valheim 1.0.
The duplication is the reason to update rather than to wait: it needed a trip to actually land, which the second bug made rare, so a post on 1.5.0 could be quietly multiplying a stack larger than ItemsPerTrip with nothing in the log to show for it.
What moved · 1
Vaettir 1.5.0 → 1.5.1
1.5.1
Two long-standing stowing-post bugs, both older than Valheim 1.0, and the reason neither had been found: nothing in the run said a word about either.
Fixed
A chest you had once opened was never used again.
Container.IsInUse()returns the rawm_inUsefield, butContainer.SetInUseonly assigns that field when the caller owns the ZNetView. So on a client that does not own the chest the value is wrong in both directions, and worst of all a chest this client opened and then lost ownership of never receives itsSetInUse(false)- the guard drops it - leaving it "occupied" for the rest of the session.Depositor.Usablerejected it there, before the chest's rule was ever read, and the post reported having nowhere to go while a correctly configured chest stood in range.It is worse than a stale read, because the state seals itself in.
UpdateUseVisualis the only code that ever writesZDOVars.s_inUse, it is reached only fromCheckForChangesthroughLoad(), andLoad()returns false outright whilem_inUseis true. So the flag blocks the one path that would clear it - on the instance and in the world file both - and stops that chest reloading its contents from the ZDO into the bargain.m_inUseis no longer consulted at all. When we do not own the chest,ZDOVars.s_inUseoff the ZDO carries the shared answer, which is what vanilla's ownUpdateUseVisualreads in its non-owner branch. When we do own it, nobody else can have it open - opening transfers ownership, becauseContainer.RPC_RequestOpenends inSetOwner(uid)- so the only honest question is whether we have it open, andInventoryGuianswers that through public API with no private field to go stale.Both halves matter and they cover different people. A player on a shared server hits the non-owner path; a player in singleplayer owns every ZDO and only ever hits the owner one.
discussThe spirit flew back and forth without ever delivering. A trip carried an
ItemDrop.ItemDatareference, andContainerrebuilds its entire inventory from the ZDO on every revision change - which a stow run causes constantly, because each deposit changes a container.Inventory.ContainsItemis reference equality on aList, so the reference was orphaned in flight almost every time.Movetreated that as handled and returned silently, so the spirit landed, moved nothing, and set off again forever.The item is re-found on arrival by shared name, quality, variant and world level - the same fields
Inventory.FindFreeStackItemuses to decide two stacks may merge, so anything matched is something the destination would have stacked with the original anyway.This one was hidden behind the first: with the chest excluded, no trip was ever dispatched.
discussA stow could duplicate what it moved.
Depositor.Deposittook the trip's share out of the source by writingitem.m_stackdirectly, and only calledInventory.RemoveItemonce the stack reached zero. A raw field write is invisible to the inventory:Inventory.Changednever fires, soContainer.OnContainerChangednever runs and the post's ZDO is never saved. The destination's side does save -AddItemcallsChanged- so the post reloaded its old contents from a stale ZDO, the stack came back, and the next trip moved it again. Measured at 21 coal in the post producing 140 in the chest.Only a partial take was affected, which is every trip of a stack larger than
discussItemsPerTrip, and it needs a trip to actually land - so it was invisible for as long as the two bugs above kept trips from landing at all. The removal goes throughInventory.RemoveItem(item, amount)now, and the source is checked for the item before anything is added anywhere, because an add that succeeds beside a removal that fails is the definition of this bug.
Changed
The run explains itself now. A homeless report lists, per item, every usable chest, the rule it carries and whether it wanted the item, refused it, or was full.
discussMove's three silent exits each say which one fired. Previously the log could show "2 usable chest(s)" and then nothing at all, which is the state both bugs above lived in.
Discussion
Nothing said yet.
Sign in or make an account to join in.