@@ -66,18 +66,31 @@ contents, and asks the client block entity's `screenItems()` what each slot acce
6666holds, so a click is predicted the way the server will answer it. It's only asked about rules, so its
6767contents don't need to be synced.
6868
69- Return the ` ItemStorage ` itself. A wrapper around it , or another ` ReservedSlots ` implementation,
70- loses the guards below and the client's copy of the plans .
69+ Return the ` ItemStorage ` itself, or a handler/wrapper implementing ` ReservedSlots ` , including
70+ ` plan(slot) ` , so both menu sides receive and enforce the same reservations .
7171
7272When the machine has reserved items in a slot (see [ capabilities] ( capabilities.md#reservations ) ),
7373the menu keeps them from being taken or replaced:
7474
7575- Left and right click, Q and Ctrl+Q, and shift-click take only what is free.
7676- Clicking the slot with a different item is refused.
77- - A number key is refused on a slot with a plan, because vanilla would move the whole stack .
77+ - Number- key and offhand swaps move only the unreserved portion .
7878- Double-clicking a slot with a plan doesn't collect from elsewhere. Double-clicking another slot
7979 still takes the planned slot's free part.
8080
81+ Machine slots show reservations at the top right. Both reservation and held quantities use
82+ 87.5% of vanilla's font size:
83+ ` -2 ` means two items reserved for input, and ` +1 ` means space reserved for one output. The held
84+ quantity stays at the bottom right, using the same size even when no reservation is present.
85+ An empty planned output shows its item model at 50%
86+ opacity with ` +1 ` at the top, without creating a real stack. Mixed consume/produce plans show
87+ both signed counts on the top row. Tooltips provide reservation counts and the planned output's
88+ name. Clearing the plan removes the badge and ghost. Player inventory, equipment and filter
89+ slots are unaffected.
90+ Chance outputs show their reserved capacity, not a guarantee that the product will be rolled.
91+ No extra packet or XML binding is needed; ` MachineMenu.reservationPlan(index) ` exposes the existing
92+ synchronized snapshot for real machine slots.
93+
8194The client's menu works out the same answer from the slot's plan, which arrives with the screen's
8295values, so clicks don't flicker. Bars and numbers still come from the getters named in the XML; a
8396feature's own client sync (see [ block entities] ( block-entities.md#machine-features ) ) doesn't
@@ -338,7 +351,7 @@ payload contains both lane index and state. The server restricts that selector t
338351in its XML property. These settings persist with the machine. The graphical smoke run checks
339352focus, typing, cancellation, resizing, view changes, release outside bounds and server rejection.
340353
341- The expanded menu protocol is version ** 6 ** , including a session token in menu-opening data.
354+ The expanded menu protocol is version ** 9 ** , including a session token in menu-opening data.
342355Client and server must use matching MMDLib builds.
343356
344357## Files and IDs
@@ -446,7 +459,7 @@ inventory slots keeps the machine's `screenDestinations` routing. JEI recipe tra
446459only the ordinary inventory and hotbar, leaving equipped items alone.
447460
448461Optional ` <inventory-controls> ` goes after the main body and before tabs/popouts. Its button
449- children form a right-aligned row above the player inventory (for example redstone and pause
462+ children form a right-aligned row above the player inventory (for example manual pause
450463toggles). Automation's reusable ` InventoryColorButtonBar ` shares that row on the left, with
451464scrollable overflow. Both sides align with the nine-column storage grid, leaving the equipment
452465column clear. Flat controls fit in the inventory's existing top row; taller controls add only
@@ -783,7 +796,10 @@ darker icon rail as the other drawers. Large inventories are paged with the arro
783796between eligible equipped containers. The main panel stays stationary, opening storage
784797closes a left information drawer, and the right automation drawer remains independent.
785798If the window has insufficient space, the tab explains how to make room. Unequipping,
786- replacing or resizing a container closes the drawer; stale clicks are rejected by the server.
799+ replacing or resizing a container closes the drawer; requests for an old container or page are
800+ rejected by the server. Live item-count or icon updates do not cancel drags or block clicks:
801+ transfers use the current server contents, filters and limits. Both equipment drawers share one
802+ menu-local Curios discovery per tick, refreshed before and after item actions.
787803The drawer respects the capability's insertion/extraction filters and limits.
788804
789805Some items expose storage only after being initialized through their own normal UI. Such
@@ -817,6 +833,87 @@ to the available slot groups or counts closes the old view and invalidates stale
817833reopening shows the updated slots. Curios stays optional, with no tab or class-loading
818834requirement when absent. This drawer does not change slot definitions or rendering toggles.
819835
836+ ## Redstone face drawer
837+
838+ Implement ` ScreenHost.screenRedstone() ` to return a persistent ` RedstoneControl ` . Its right-side
839+ drawer uses the inventory drawer's neighbour grid, directional badges and shared frame. Clicking
840+ a different face selects it; clicking the selected face cycles Ignore, Read and Emit (right-click
841+ cycles backwards). Faces have a spaced selection outline and small background-free signal numbers:
842+ bright green incoming strength for Read, orange emitted strength for Emit, with thin glyph outlines.
843+
844+ - ** Ignore:** no input gate and no emitted signal.
845+ - ** Read:** a single bar has a minimum handle above and a maximum below. Endpoints are inclusive,
846+ and dragging either past the other pushes both together. Between highlights the selected interval;
847+ Outside highlights its complement. The icon toggle sits to the left of the bar: inward arrows
848+ between boundaries mean Between, outward arrows beyond boundaries mean Outside. Equal endpoints
849+ simplify only the info text to For N / Except N; ranges touching 0 or 15 use a single
850+ above/below condition (including equality for Between). The icon stays unchanged. Processing pauses when
851+ the face receives a highlighted level.
852+ The default is Between 115. Dragging previews locally, release applies both endpoints atomically,
853+ and Escape cancels the drag. Any Read face requesting pause holds processing.
854+ - ** Emit:** click the colour swatch or sprite and source name to cycle outputs; right-click
855+ cycles backwards. Resource fullness entries come first in the companion, followed by each
856+ processor's own Processing, Paused/idle and Progress entries. A small reverse-arrows button
857+ before the picker toggles Revert (` 15 - level ` ). Until a source is selected, or if that source
858+ no longer exists, the face emits zero even when reverted.
859+
860+ These controls are built in: there are no redstone upgrade items or slots. Each face saves its
861+ interval, Between/Outside choice, stable output ID and inversion independently. Changing the
862+ face mode retains those settings. The small yellow info box explains the selected source and
863+ current signal. The drawer fits its content and scrolls when the viewport cannot fit it. The
864+ old main redstone button is removed; manual pause remains above the inventory. Right drawers
865+ are mutually exclusive, and drawer/face selection is remembered for the current connection.
866+
867+ ### Output providers
868+
869+ Runtime parts opt in by implementing ` api.redstone.IRedstoneOutput ` . Its ` redstoneOutputs() `
870+ returns a stable, ordered list of ` RedstoneOutput ` descriptors. Each descriptor has:
871+
872+ - A stable ID unique across this machine, used for saved selections.
873+ - Translatable name and description components, used by the picker and yellow info box.
874+ - An RGB colour and optional GUI sprite ID, used as the picker's swatch or icon.
875+ - A server-side ` IntSupplier ` whose result is clamped to 0-15.
876+
877+ Construct ` RedstoneControl(owner, parts) ` after registering the parts; it discovers only parts
878+ implementing the interface and rejects duplicate IDs. The catalog must have the same order and
879+ metadata on client and server. Descriptors use common-side types, without client rendering
880+ classes. Suppliers are evaluated only on the server, once per selected source per output update.
881+ ` FeatureHost ` implements the interface by collecting outputs from participating features.
882+
883+ ` RedstoneOutput.resource(group, fullnessSupplier) ` adapts an existing ` ResourceGroup ` , preserving
884+ its ID, label and colour. Fullness is 0-1 and maps to ` floor(fullness * 15) ` . The companion measures
885+ item groups by average slot fullness, fluid groups by amount/capacity, and energy by stored/capacity.
886+ The resource-only ` RedstoneControl(owner, groups, fullnessFunction) ` constructor remains available.
887+
888+ Each ` RecipeProcessor ` contributes three independent sources, prefixed by its saved feature key:
889+
890+ | Source | Signal |
891+ | ---| ---|
892+ | Processing | 15 while actively processing (including the start and completion ticks), otherwise 0 |
893+ | Paused/idle | 15 while paused, idle, blocked, energy-stalled or held by the host; otherwise 0 |
894+ | Progress | ` floor(completedTicks / recipeTicks * 15) ` ; retained while held/paused, 15 on completion, 0 when idle |
895+
896+ Use the constructor accepting a display-name ` Component ` to label processors clearly; the original
897+ constructor defaults to the feature key. Multiple processors produce multiple sets of entries.
898+ There is no aggregate machine-wide running signal.
899+
900+ Tick in this order on the server:
901+
902+ ``` java
903+ redstone. readInputs();
904+ features. tick(level, ! redstone. paused() && otherProcessingGates);
905+ // Perform any automatic transfers here.
906+ redstone. updateOutputs();
907+ ```
908+
909+ Passing ` false ` to ` FeatureHost.tick ` invokes each feature's ` suspended ` callback instead of
910+ processing it, so a held processor cannot retain a stale running signal. Save/load the controller
911+ tag and return ` signal(direction) ` from the block's redstone output hook. The direction passed
912+ to ` signal ` is Minecraft's query direction, not the outward face. Stateless hosts can call
913+ ` redstone.tick() ` to read inputs and update outputs together. The companion emits weak power,
914+ keeps transfers running while processing is held, and migrates old inventory selections and
915+ the previous global redstone mode. Manual pause remains independent.
916+
820917## Proper use
821918
822919These are guidance for screen authors, not rules MMDLib can check:
0 commit comments