Feature Container Contents Menu - bh679/dungeon-train-mc GitHub Wiki
Since: v0.74.0 β PR #103 v0.799.0 β PR #1304 β works in the Train Builder, and resolves from the container you are looking at rather than the plot you are standing in. See Β§ Train Builder support.
A billboarded worldspace UI for authoring weighted item pools that roll into chests / barrels / dispensers / hoppers / shulker boxes / any block with a Container BlockEntity. Tap the container-contents hotkey (default C) while looking at a container in any editor plot and a panel anchored against the targeted face appears, listing every authored item with its count and weight. At carriage spawn time, each container's slots roll the pool and produce a deterministic, world-seed-keyed inventory.
Mirrors the architecture of the block-variant menu (Z key) shipped in v0.56.0, with a simpler feature set β no rotation, no lock-IDs, no clipboard copy. The two menus coexist on different keys and store their data in separate sidecar files.
| Goal | Tool |
|---|---|
| Choose which block spawns at this position (chest vs barrel vs stone) | Tap Z β block-variant menu |
| Choose which items spawn inside the container at this position | Tap C β container-contents menu |
| Add the held block as a position variant | Hold Z + right-click |
| Add the held item to the container's loot pool | Tap C β menu β Add |
The two menus operate on the same (plotKey, localPos) namespace but write to separate JSON files β <plotKey>.contents.json for container pools, <id>.variants.json for block variants. Editing one never affects the other.
The C key uses the same tap-to-open pattern as Z. Press + release within ~400ms with no use-interaction during the press β opens the menu against the block under the crosshair. Tap C again (or click X in the toolbar) to close. Held-state is also reported to the server (parallel to the Z key's hold flag) so future "hold C and click" flows have a hook, but no behaviour depends on it yet.
The keymap is rebindable from Esc β Options β Controls β Dungeon Train β Container Contents Menu.
5 cells, fixed left-to-right: Add | min N | max M/27 | Clear | X.
| Cell | Action |
|---|---|
| Add | Capture the player's main-hand item and append it as a pool entry. Count comes from the held stack size; weight defaults to 1. Empty hand β action-bar warning ("Hold an item or use the search screen to add"). |
| min | Click +1, shift-click -1. Sets the minimum number of slots filled at spawn time. Auto-clamped so min β€ max (when max is not "all"). Wraps at the boundaries: click + at the upper bound (= max when set, else 64) β 0; shift-click at 0 β upper bound. Display: bare integer (e.g. 1). |
| max | Click cycles all β 0 β 1 β 2 β β¦ β 64 β all, shift-click reverses. Display: 5/27 or all/27 β the /27 is the targeted block's actual Container.getContainerSize() (chests=27, barrels=27, hoppers=5, dispensers=9, shulkers=27, etc.). When the user lowers the max ceiling below the current min, min is dragged down with it. |
| Clear | Drop the entire pool from the sidecar. Container in the world is untouched (only the spawn-time roll is affected). |
| X | Close the menu. Re-tapping C does the same. |
Each row in the grid lists one pool entry. Right-to-left cell layout: [Γ remove] [w weight] [x count] [item name].
| Cell | Action |
|---|---|
| item name | Display only. Shows the item registry path segment (e.g. diamond_sword from minecraft:diamond_sword). |
| xN (count) | Click +1, shift-click -1. Range [1, 64] with wrap at the boundaries: click + at 64 β 1; shift-click at 1 β 64. Count is a max β at roll time, the actual stack size for this entry is rolled uniformly in [1, count] per slot, with an independent deterministic mixer. So x6 means "up to 6 per slot," not "always 6". |
| wN (weight) | Click +1, shift-click -1. Clamped to β₯1. Sets the proportional weight when rolling which entry fills each slot. |
| Γ (red) | Remove this entry from the pool. |
To get sparse fills, add a minecraft:air entry with a high weight β at roll time, slots that pick the air entry are left empty. Alternatively, lower the max slot cap.
Each row can opt-in to spawn the rolled stack with random damage and/or a random vanilla enchantment. When at least one effect applies to the entry's item, a second sub-strip appears under the entry's main row with up to four extra cells:
[ Dur β ] [ 100% ] [ Ench β ] [ 25% ]
| Cell | Action |
|---|---|
| Dur β / β | Master toggle. When β, eligible damageable items roll a random damage value. |
| NN% (left) | Click +5, shift-click -5. Range [0, 100] with wrap at the boundaries. Probability the durability effect applies on a given spawn. 0% never fires, 100% always fires. |
| Ench β / β | Master toggle. When β, eligible enchantable items roll a vanilla-style random enchantment. |
| NN% (right) | Same controls as the durability chance, but for the enchantment effect. |
Defaults for new entries: Dur β 100%, Ench β 25%.
The sub-strip only appears for items that support at least one of the two effects, and individual pairs only render when the item supports that specific effect:
| Item class | Sub-row shape |
|---|---|
| Neither damageable nor enchantable (cobblestone, bread, oak_log, β¦) | No sub-row. Entry collapses back to a single-strip row. |
| Damageable but not enchantable (flint_and_steel, shears, β¦) | Left two cells only: [Dur β] [NN%]
|
| Enchantable but not damageable (book, enchanted_book base, β¦) | Right two cells only: [Ench β] [NN%]
|
| Both (swords, armor, tools, fishing_rod, β¦) | All four cells |
Click hit-tests honour the same gating β clicking the empty space where a hidden cell would be returns no hit. The raycast walks variable-height rows column-by-column so multi-column layouts handle mixed pools cleanly.
When an entry is picked for a slot, the roller now:
- Materializes the
ItemStack(was: hand-builtItemsNBT). Both the chest path and thedecorated_potpath go through the sharedrollItemStackhelper. - Per-effect chance roll: if
randomDurability && stack.isDamageableItem(), the durability-chance salt mixer rolls a value in[0, 100)β if it falls belowdurabilityChance, the effect applies. -
Damage value: uniform
[0, maxDamage - 1](independent salt) β keeps the item usable, never spawns at "next hit and it breaks". -
Enchantment: vanilla
EnchantmentHelper.enchantItemagainstEnchantmentTags.IN_ENCHANTING_TABLE(the non-treasure set β no Mending / Curses / Frost Walker). Level uniform[1, 30]from a seededRandomSource.
All four new rolls (durability chance, durability value, enchantment chance, enchantment level seed) use distinct salts and feed the same splittable-mix that the K-roll and slot-pick rolls use, so the per-effect outcomes never correlate with the entry-pick or slot-pick rolls. Same world seed + same (carriageIndex, localPos, slot) β identical loot, including the damage value and the rolled enchantments.
Items that fail the runtime gate (!isDamageableItem() or !isEnchantable()) simply skip the effect β the saved flag is harmless on the wrong item, which means future Minecraft versions that make new item classes damageable / enchantable would automatically pick up the flag's intent.
Since: v0.826.0
Potions used to lose their identity in a pool: the entry stored only the item id, so every potion came back as a bare bottle that the roller reinterpreted as "roll me a random effect". Randomisation is now explicit, and an authored potion spawns exactly as placed.
| Entry | Pool |
|---|---|
dungeontrain:random_potion |
Any vanilla potion, 6 escalating tiers of 4β5 effects |
dungeontrain:random_good_potion |
Beneficial only, 4 tiers of 4 (Healing / Night Vision / Water Breathing / Leaping β β¦ β Healing II / Swiftness II / Regeneration II / Strength II) |
dungeontrain:random_bad_potion |
Harmful only, 4 tiers of 3 (Weakness / Slowness / Infested β Poison / Weaving / Oozing β Harming / Slowness II / Wind Charged β Poison II / Harming II / Weaving) |
All three live in the Dungeon Train β Narrative creative tab and are found by typing random in the Add search. At spawn time ContainerContentsRoller.bakeRandomPotion replaces the placeholder with a real drinkable / splash / lingering bottle. Every pick is deterministic per (seed, carriage, pos, slot) and each slot rolls independently, so one row landing several times in a chest usually gives different potions; the tier tables were widened for exactly that.
A placeholder row shows a sub-row with two cells (potions are neither damageable nor enchantable, so the durability / enchantment cells never appear):
- Scale β / β β on (default), the power tier follows carriages travelled (50-carriage bands, same ramp as tipped arrows); off, the effect is drawn uniformly from every tier regardless of distance.
- Form: Any / Potion / Splash / Lingering β click to step. Any (default) re-rolls the bottle per spawn; the other three pin it. The row icon switches to the pinned bottle so the row reads at a glance.
Per-form weighting works as it always did: one row per form, each with its own count and weight (the shipped brewing table is potion Γ4 / splash Γ3 / lingering Γ1 at equal weight).
Adding a potion from your hand now records its vanilla potion on the entry (potionId), and the row label reads e.g. potion (healing) or potion (water). At spawn the stored potion is put back on the stack, so Water, Awkward, Mundane, Thick and every effect potion place exactly. A minecraft:potion added by id alone has no stored potion and spawns vanilla's Uncraftable Potion β no potion entry is ever randomised implicitly any more. Authors of older user-dir prefabs that still list a bare minecraft:potion should re-author them with a random entry.
Optional fields on the entry, omitted when at their default so old sidecars read unchanged: "potion": "minecraft:healing", "scale": false, "form": "splash" (pool sidecar + loot prefab JSON); p / s / f on the variant clipboard; one string, one boolean and one byte per entry on ContainerContentsSyncPacket. Edit ops TOGGLE_SCALE and CYCLE_POTION_FORM on ContainerContentsEditPacket. The shipped potionbarrel, brewing, end, lethershopchest prefabs and the craftshrine2 inline pool were migrated to random_potion with each original row's form pinned.
Three independent deterministic rolls per container, all keyed on (worldSeed, carriageIndex, localPos, β¦):
-
K (slot count) roll.
K = uniform(min, effectiveMax), whereeffectiveMax = (fillMax == FILL_ALL ? containerSize : min(fillMax, containerSize)). Independent salt so K doesn't correlate with the slot-pick or count rolls. -
Slot subset roll. Seeded FisherβYates over
[0, containerSize)produces a deterministic shuffled order; the firstKindices become the filled slots. -
Per-slot entry pick + count roll. For each filled slot, weighted-random pick from the pool's entries (weight-proportional). If the picked entry is
minecraft:air, leave the slot empty. Otherwise, roll the actual stack count uniformly in[1, entry.count](independent salt).
Result: same world seed + same carriage index β identical container contents. Different carriages at the same local pos β different rolls. The same chest layout produces different inventories per playthrough at different seeds.
Any block whose BlockEntity implements net.minecraft.world.Container qualifies. The menu controller probes the targeted block's BlockEntity at toggle time via EntityBlock.newBlockEntity(BlockPos.ZERO, state) and checks instanceof Container β so it works for vanilla Chest, Trapped Chest, Barrel, Hopper, Dispenser, Dropper, Shulker Box, Furnace family, and modded containers.
A non-container target produces an action-bar warning: Block has no inventory β look at a chest, barrel, dispenser, etc.
Like the Z menu, C resolves through BlockVariantPlot.resolveAt(player) so it works in all four editor plot types:
| Plot | Plot key (filename prefix) | Resolver |
|---|---|---|
| Carriage variant | carriage:<id> |
CarriageEditor.plotContaining |
| Carriage contents | contents:<id> |
CarriageContentsEditor.plotContaining |
| Carriage part | part:<kind>:<name> |
CarriagePartEditor.plotContaining |
| Track-side | track:<kind>:<name> |
TrackPlotLocator.locate |
Since v0.799.0 (PR #1304) C also works in a Train Builder world, whose build resolves as a fifth plot:
| Plot | Plot key (filename prefix) | Resolver |
|---|---|---|
| Train Builder build | builder:carriage |
BuilderCarriagePlot.of (world data, not position) |
That key is the same constant in every builder world, which is why the document is not stored in
a file named after it: ContainerContentsStore takes a registered path override pointing at
<world>/dungeontrain/builder/build.contents.json, inside the world save. Before this, every builder
world read and wrote one shared builder_carriage.contents.json in the config dir. An overridden key
also skips the dev-mode source write-through β an unnamed draft has no bundled resource to keep in
lockstep with.
BuilderWorldSetup seeds the document from the template you open, and BuilderSave writes it onto
the template you save as. Links to loot prefabs are carried as links, so a
prefab edit still propagates.
Also since v0.799.0, the menu resolves from the targeted container (resolveAtPos) rather than
the player's position, and once open follows the plot key the server recorded β which is stronger
authorisation than the positional check it replaced. See the
Z menu's note.
Container pools are wired into the carriage placement pipeline at three callsites: CarriageContentsTemplate.applyVariantBlocks, CarriageTemplate.applyVariantBlocks, CarriagePartTemplate.applyVariantBlocksForPlacement. Track and tunnel placements are not yet hooked β chest variants in those plots spawn empty pending a follow-up.
Per-plot JSON sidecar at config/dungeontrain/user/containers/<plotKey>.contents.json (the : in the plot key is replaced with _ for filename safety on Windows). Two-tier load:
-
config/dungeontrain/user/containers/<plotKey>.contents.json(per-install authored) -
/data/dungeontrain/containers/<plotKey>.contents.json(bundled resource β ships authored pools with the mod)
Schema (v3 as of v0.145.0):
{
"schemaVersion": 3,
"pools": {
"1,0,2": {
"fillMin": 1,
"fillMax": 5,
"entries": [
{ "id": "minecraft:diamond_sword", "count": 1, "weight": 4,
"randDur": true, "durChance": 100,
"randEnch": true, "enchChance": 25 },
{ "id": "minecraft:cobblestone", "count": 10, "weight": 1,
"randDur": true, "durChance": 100,
"randEnch": true, "enchChance": 25 }
]
},
"0,1,0": {
"entries": [
{ "id": "minecraft:diamond", "count": 3, "weight": 1,
"randDur": true, "durChance": 100,
"randEnch": true, "enchChance": 25 }
]
}
}
}fillMin defaults to 0, fillMax defaults to -1 (sentinel for "all slots"). Both fields are omitted from disk when at default. A legacy fillCount: N field from an early dev iteration is read back as min == max == N.
The four random-effect fields default to (true, 100, true, 25). v2 files load with those defaults β no destructive migration. Per-cobblestone entries carry the flags too, but the runtime gate (isDamageableItem() / isEnchantable()) skips them at roll time so the data is harmless on items that don't apply.
When DevMode is enabled, saving the parent template (/dt save <id> for contents, parts) also writes the per-plot containers/<plotKey>.contents.json sidecar to src/main/resources/data/dungeontrain/containers/ β same write-through pattern as the block-variant sidecars. Empty stores are skipped so a save with no authored pools or links does not produce a sidecar file.
The promote path (/dt save default <id>) symmetrically copies the config-dir sidecar to source so existing config-only authoring can be shipped without re-saving. Sidecar promotion is best-effort: if the parent .nbt promote succeeds but the sidecar fails (missing, source tree unwritable), the parent promote is not rolled back β a warning is logged.
This means authored pools and links blocks committed to the repo ship with the next build's bundled resources and become every fresh install's default. The links block is the one most likely to silently disappear from the bundled tier if the sidecar is missing β chests authored with a link to a loot prefab appear correctly at runtime in the dev session but spawn empty (or with stale fallback data) for end users until the sidecar is shipped.
The barrel contents (the first authored pool, shipped in v0.74.0) was committed via this path. Container-link promotion across all contents/part plots was wired in PR #181 β prior to it, only barrel was correctly shipped because every other plot's sidecar was silently absent from the bundled tier.
Protocol bumped 6 β 9 in v0.74.0 β four new packets added in PR #103.
| Packet | Direction | Payload |
|---|---|---|
ContainerHotkeyPacket |
C2S | held boolean |
ContainerContentsMenuTogglePacket |
C2S | open boolean |
ContainerContentsSyncPacket |
S2C | plotKey, localPos (or null = close), entries [itemId, count, weight, randDur, durChance, randEnch, enchChance], fillMin, fillMax, containerSize, anchor pos / right / up |
ContainerContentsEditPacket |
C2S | op (ADD / REMOVE / CLEAR / BUMP_WEIGHT / BUMP_COUNT / BUMP_FILL_MIN / BUMP_FILL_MAX / TOGGLE_RAND_DUR / TOGGLE_RAND_ENCH / BUMP_DUR_CHANCE / BUMP_ENCH_CHANCE / UNLINK), plotKey, localPos, entryIndex, itemId, delta |
In v0.145.0 the sync packet's Entry record was extended with the four new fields and the edit packet's Op enum grew four new values (TOGGLE_RAND_DUR, TOGGLE_RAND_ENCH, BUMP_DUR_CHANCE, BUMP_ENCH_CHANCE). The packet TYPE id is unchanged β the layout grew, so old clients talking to a new server (or vice versa) would mis-decode. The editor is OP-only single-player by design.
The ADD op with empty itemId signals "use main-hand item" (server-side capture); a non-empty itemId is the explicit-id path used by the (currently unreachable) search screen.
/dt editor contents enter barrel # enter a contents plot
[walk to a chest in the plot]
C (tap) # menu opens against the chest face
[hold a diamond sword in main hand]
Click "Add" # row added: diamond_sword | x1 | w1
Click on count cell # β x2
Shift-click count # β x1
Click "min" twice # β 1, β 2 (slots will fill 2..max)
Click "max" # all β 0
Click "max" 5 more times # β 5/27 (max 5 of the 27 slots)
[Spawn carriage in real run] # the chest rolls 2..5 slots,
# each with a weighted-random
# entry, count 1..N per slot
Containers in editor plots can be linked to a loot prefab. A linked container doesn't store its own pool data β it reads through to the prefab on every menu open, every spawn-time roll. Edits made via any linked container's menu propagate to every other linked container instantly.
| Trigger | Result |
|---|---|
Click Save in the C-menu on an unlinked container, name it foo
|
Container is now linked to foo. Action-bar: Saved loot 'foo' (linked). |
Right-click a foo loot-prefab item from the creative tab inside an editor plot
|
The placed container is linked to foo. Action-bar gains the (linked) suffix. |
| Right-click the same prefab item outside an editor plot | No link β gameplay placement is unchanged. The chest still rolls items from the prefab once at placement, but template edits will not propagate to it. |
When the targeted container is linked, the C-menu draws a sub-row beneath the header:
Linked: foo X
- The text is informational. Hovering highlights the row.
- The right-side X cell unlinks. On unlink, the resolved pool is snapshotted to the local store first so the menu keeps showing the same entries.
- The toolbar shifts down to make room.
-
Save click: skips
PrefabNameScreen. Action-bar:Linked to 'foo' β edits save automatically. -
Add / Remove / Clear / count / weight / fill min / fill max: every edit is written straight to the
LootPrefabStoreJSON for the linked prefab, then propagated.
Whenever a template is saved (via the C-menu Save, or via any edit on a linked container), ContainerContentsLinkPropagator scans every plot's link map and re-rolls the in-world BlockEntity at every linked position. A unique nanoTime salt is used for each propagation event so the deterministic roller produces visibly different items rather than re-deriving the placement-time roll.
Editor-only by construction: links only exist for containers placed/saved inside an editor plot, so the propagator never touches gameplay-placed containers.
Per position is AUTHORED XOR LINKED β the two states are mutually exclusive:
{
"schemaVersion": 2,
"pools": {
"1,0,2": {
"fillMin": 1,
"fillMax": 5,
"entries": [
{ "id": "minecraft:diamond", "count": 3, "weight": 1 }
]
}
},
"links": {
"0,1,0": "common_loot"
}
}pools and links never key the same position. Setting a link drops the local pool; unlinking snapshots the resolved pool back to local. The links block is omitted from disk when empty. v1 files (no links block) load with no links. Legacy v2 files written before this PR with both pools and links for the same position silently let the link win on read.
| Packet | Direction | Change |
|---|---|---|
ContainerContentsSyncPacket |
S2C | Append optional linkedPrefabId (boolean + UTF when present). |
ContainerContentsEditPacket |
C2S | New Op.UNLINK op (no payload β just clears the link at localPos). |
minecraft:decorated_pot is also a valid C-menu target even though vanilla 1.20.1 doesn't give the pot a real Container BlockEntity. The roller treats it as a virtual single-slot container: the max ceiling reads /1 (vs /27 for chests), and the K-roll either picks 1 (an item rolls) or 0 (no item this carriage), giving the same min/max rarity dial used everywhere else.
Roll storage. Pots have no native item slot in 1.20.1, so the rolled ItemStack is written to a dt_pot_loot BE NBT field. A DecoratedPotBlockEntity mixin teaches the BE to round-trip the field across save/load β without it, vanilla's saveAdditional would strip the field on the next chunk save.
Delivery. When a vase is broken, a BlockEvent.BreakEvent handler reads dt_pot_loot and spills it via Containers.dropItemStack at the pot's world position β same call path as a broken chest. The vanilla sherd shards still drop alongside; the rolled item is additive. Trident-cracked pots and explosion breaks don't fire BlockEvent.BreakEvent and so don't drop the rolled item β out of scope at first ship.
Forward-compat. The native-Container check runs before the decorated_pot fallback. If the project is ever upgraded to a Minecraft version where DecoratedPotBlockEntity natively implements Container (1.20.5+ added ContainerSingleItem), the standard path picks it up and dt_pot_loot becomes dormant β no migration required.
v0.1138.0 (PR #1803). The C menu also opens on suspicious sand and suspicious gravel, even though their BrushableBlockEntity isn't a Container (ContainerContentsRoller.isLootAuthorable; the menu reports 1 slot). An authored pool or a linked loot prefab rolls one item per carriage, using the same single-item roll as vases, so a min/max of 0β1 gives a chance of finding nothing. The item is written under the block entity's item key, and LootTable/LootTableSeed are removed, because vanilla prefers a stored table over item. Brushing the block then drops the authored item. A suspicious block with no pool keeps the vanilla archaeology table (desert_pyramid for sand, trail_ruins_common for gravel) via stampArchaeologyLoot. Vases' Luck-potion bonus doesn't apply to brushables.
The train's per-tick entity wipe (TrainTickEvents) used to discard every non-player entity inside the train's current AABB, which silently nuked vase loot drops (and any other dropped item) on the same tick they spawned. The wipe now targets only the forward look-ahead slab β the runway in front of the train; carriage interiors are spared. The interior is still wiped exactly once at carriage-stamp time via CarriageContentsTemplate.discardEntitiesAt, so train contents stay stable after setup.
The C-menu's hotkey class (ContainerHotkeyClient) originally followed the same pattern as VariantHotkeyClient (Z key), with a static inner class named TickWatcher. Forge's @Mod.EventBusSubscriber auto-registration silently dedupes inner static classes by simple name across a single mod β so two classes both named TickWatcher (in different outer classes) caused one of them to never receive events. Container's was processed first per the auto-subscribe log order, which silently broke the existing Z-tap menu.
Fix: rename Container's inner class to ContainerTickWatcher. The class is now documented with a docstring warning future copies of this pattern away from the same trap.
-
ContainerHotkeyClient.javaβ KeyMapping(KEY_C) + tap-to-toggle (ContainerTickWatcherinner class) -
ContainerContentsMenu.javaβ client singleton state -
ContainerContentsMenuRenderer.javaβ billboarded panel, 5-cell toolbar, per-row layout -
ContainerContentsMenuRaycast.javaβ camera-ray β panel cell hit-test -
ContainerContentsMenuInputHandler.javaβ left-click dispatch, attack/use cancel -
ContainerContentsMenuController.javaβ server: toggle, applyEdit, fill-min/max clamping -
ContainerContentsPool.javaβ immutable pool record (entries + fillMin + fillMax) -
ContainerContentsEntry.javaβ single entry (item ResourceLocation, max count, weight) -
ContainerContentsStore.javaβ per-plot JSON sidecar; two-tier load (config first, bundled resource fallback) -
ContainerContentsRoller.javaβ pure utility: pool β BE NBT, deterministic on(seed, index, pos, slot) -
ContainerContentsPlacement.javaβ decorator overSilentBlockOps.setBlockSilentconsulted at the 3 carriage placement callsites
-
Track and tunnel placements are not hooked. Chest variants placed in
track:*or tunnel plots will spawn empty even with a pool authored. Follow-up issue tracking; the wiring is mechanically the same as the carriage callsites. - No item icons in the menu. Text-only labels (matches the existing block-variant menu's text-only style).
-
Item NBT is limited to random damage, random enchantments and a stored potion. Custom NBT (lore, attribute modifiers, hand-picked enchantments, custom names) is not yet authorable β the random effects fire from a fixed level range (
[1, 30]) against the non-treasure enchantment tag. Fully fixed enchantments / damage / metadata is a follow-up. -
No clipboard copy. Unlike the Z menu's
Copy β variant_clipboardflow, there's no clipboard item for pools yet. Pools are duplicated by hand-editing the sidecar JSON. -
Per-entry count is a max, not a range. The lower bound is hardcoded at
1. To force exact counts, usecount = Nand accept the 1..N variance β full control of stack-size range is a follow-up. -
Search screen is dormant. The
ContainerContentsSearchScreenfile ships but is unreachable from the toolbar (Add captures the held item directly, like the Z menu's Add). Files remain in case a search-by-typing path is added back.