Real Inventory, Nested Backpacks, and Vanilla Trading
A genuine IsoPlayer already owns a real inventory. The hard part was moving exact items safely through nested containers and vanilla trade without inventing an NPC connection.
Inventory was already part of the body
Inventory wasn't something I had to fake for True MP NPC. Because the NPC is a genuine Project Zomboid IsoPlayer, it already owns the game's real ItemContainer.
Eating and drinking were some of the first useful proofs of that. The NPC wasn't changing a custom “food counter” somewhere in my code. It was consuming real InventoryItem objects owned by the server-side character.
From there I built a proper Inventory Authority around the existing PZ inventory instead of letting every new feature manipulate items however it wanted.
That layer now handles exact item ownership, transfers, consumption, primary and secondary hand state, worn items, carrying weight, capacity and persistence. The Brain never gets direct access to mutable PZ item objects. It now receives bounded food and drink reserve facts for survival choices, but not an unrestricted full-detail inventory model.
Backpacks made ownership more interesting
Backpacks aren't a separate inventory system in PZ. They're items that contain another ItemContainer, so ownership becomes a tree.
Survivor
└── Root Inventory
├── Baseball Bat
├── Old Bag
└── Hiking Bag [WORN: BACK]
├── Water
├── Bandage
└── Food
An item inside the Hiking Bag still belongs to the survivor, but its immediate container is the bag rather than the root inventory.
True MP NPC now understands and persists that relationship.
The NPC can own multiple bags, wear one, remove it and keep the contents through a restart. It can also compare a newly acquired backpack with the one it's already using.
For now that comparison is intentionally simple: usable capacity, weight reduction and condition. I don't think the project needs an advanced backpack-packing AI before the NPC can even scavenge properly.
The more important part is making an upgrade safely.
When the NPC decides to change bags, the old bag, new bag and contents are reserved. The new bag is equipped, the contents are migrated and ownership is verified afterwards. If everything won't fit, the NPC keeps using the old bag instead of throwing items away just to finish the operation.
No disappearing items and no duplicated items.
Vanilla Trade exposed a different problem
For a while, choosing Trade on an NPC simply resulted in the NPC refusing.
The inventory wasn't the problem.
Project Zomboid's normal multiplayer Trade flow assumes that both participants are ordinary network players. Eventually the vanilla path expects both sides to have a UdpConnection and reaches normal player-persistence logic.
True MP NPC deliberately has neither.
IsoPlayer yes
OnlineID yes
inventory yes
UdpConnection no
Steam session no
fake client no
Creating a fake connection just to satisfy the Trade system would have defeated one of the main architectural rules of the project.
So instead of pretending the NPC was a connected player, I kept the vanilla Trade experience on the human side and moved ownership of the NPC participant to the server.
vanilla player
↓ vanilla Trade protocol
True NPC TradeSession
├── player offer
├── NPC offer
├── acceptance state
├── item reservations
└── transaction
↓
vanilla-compatible replies
to the real player's connection
The NPC's connection remains null for the entire session.
From the player's point of view it's still the normal interaction: right-click the NPC, choose Trade, add items, see what the NPC offers and accept the exchange.
No True MP NPC client mod is needed for the Trade UI.
Moving an item is easy. Moving it safely isn't.
One thing Trade forced me to take seriously was transaction safety.
I didn't want the implementation to become:
remove item
add item somewhere else
hope nothing fails
Before a Trade commits, the server checks that the exact items are still there, still belong to the expected participant and haven't been moved or consumed by another activity.
The offered items are reserved while the session is active.
Then the exchange commits and the resulting ownership is verified. Cancelling or disconnecting releases the reservations without completing the transfer.
That has now been tested with player-to-NPC transfers, NPC-to-player transfers, two-way trades, multiple NPCs, backpacks and restart persistence.
The useful part is that none of this is really specific to a Trade window anymore.
The same ownership and transfer foundation can be reused for:
world container → NPC backpack
NPC backpack → Home storage
NPC → NPC
weapon → hand
food → consumption
clothing → worn slot
So Trade ended up being much more important than simply getting another vanilla UI to work.
Trading forced the inventory system to prove that real items could safely move between a connected human player and a connectionless server-owned survivor without inventing a fake client.