Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-25
74 changes: 74 additions & 0 deletions openspec/changes/add-configurator-target-history/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
## Context

The Ultimate Configurator currently persists one active configurator mode, block position, and dimension. Crouch-right-clicking air clears that binding and mode-specific item data; a detached configurator has no air-use behavior. Four configuration modes are registered from block-state predicates, and existing client screens use loader-neutral screen-opening hooks plus validated serverbound messages.

This change adds item-local target history and favorites. Records can outlive loaded chunks, removed blocks, and dimension changes, so stored identity and every mutation must be validated without loading chunks or trusting client screen state.

## Goals / Non-Goals

**Goals:**

- Preserve three distinct recently attached targets and up to 16 favorites on each configurator.
- Make detached configurators a fast, native UI entry point for reattachment and favorite management.
- Keep the item stack's server-side NBT authoritative while providing responsive client controls.
- Safely retain cross-dimension and temporarily unavailable records.

**Non-Goals:**

- Loading chunks, teleporting players, or remotely configuring a stored target.
- Sharing target lists between configurators or players.
- Preserving mode-specific screen selections and rendering preferences per history entry.
- Adding a container menu, external dependency, or Lua API.

## Decisions

### Store compact target records on the item

Store history order and favorite metadata as separate NBT lists. Each target record contains the configurator mode ID, dimension ID, and block position; favorite records may additionally contain a custom name. A target's identity is its dimension and position. Attaching at an existing identity replaces its stored mode and moves it to the front of history, which retains every favorite and the three latest non-favorites.

Favoriting changes metadata without changing last-use order, duplicate favorite requests do not create another record, and the server rejects additions after 16 entries. Selecting any target promotes it through the shared attachment path; renaming does not reorder it. Existing stacks whose three-entry history omits older favorites append those favorites after known last-used entries.

Alternative considered: store timestamps on each target. Rejected because one bounded order list plus favorite metadata directly represents the required ordering without clock data or migration.

### Open a non-container screen only while detached

A normal right-click on air with no active mode opens a client `Screen` through the existing loader-neutral client platform. The screen reads the held stack's history and favorite NBT and displays one last-used list. Default rows show the translated target block name, dimension, and coordinates. A named favorite displays only its custom name with a golden outline.

Each row provides immediate selection. Non-favorite recent rows provide a favorite action, while favorite rows provide an edit action that opens a focused child screen for renaming or removing the favorite. Submitting an empty name removes the custom name and restores the default label; non-empty names are limited to 64 characters. The screen remains non-pausing and closes after a successful selection.

The detached screen also has a Settings tab. It uses vanilla item hover-name storage for the configurator name and the shared `TextStyle`/`BoxStyle` enums for favorite world rendering. Favorite records may override text and box colors through the existing network-manager color picker.

The central configuration render registry handles detached configurators by passing current-dimension favorites directly to `TargetRenderHelper`. Attached configurators retain their mode-specific renderer; detached rendering never loads chunks or resolves block entities.

Alternative considered: add a `Menu` and synchronized container. Rejected because no inventory slots or continuously authoritative world data are involved; normal item synchronization and explicit mutations are smaller.

### Route all changes through validated serverbound actions

Selection, favorite toggling, and rename submission use a loader-neutral serverbound message carrying the requested action and target identity rather than accepting replacement NBT from the client. The handler requires the player's main-hand item to be an Ultimate Configurator and detached, then resolves the referenced target from its current NBT.

Favorite and rename actions mutate only records already present in the server's recent or favorite lists. Rename additionally requires the target to be a favorite and enforces the 64-character limit. The item is synchronized after successful mutation.

Selection requires the player to be in the target dimension, the target position to be loaded, and the current block state to resolve to the stored configurator mode. A successful selection uses the same active-mode save path as direct attachment, updates recent history, synchronizes the item, and closes the screen. A rejected selection leaves the item detached and provides feedback.

Alternative considered: have the client directly edit item NBT or attach from historical data without checking the world. Rejected because either path permits stale or forged targets and bypasses current block compatibility.

### Record history at the shared attachment path

The shared active-mode save operation records recent history, covering both direct crouch-click attachment and menu selection once. Detaching clears only active mode and mode-specific transient data; it does not clear recent targets or favorites.

Alternative considered: update history in each interaction caller. Rejected because it duplicates ordering and trimming behavior and can miss future attachment paths.

## Risks / Trade-offs

- [A stored block is removed, changed, unloaded, or in another dimension] -> Keep the record visible and editable, but reject selection until the player is in the dimension and the loaded block matches the stored mode.
- [A client acts on a stale row after item state changes] -> Resolve identity against current server NBT and require a detached main-hand configurator for every action.
- [Mode IDs or malformed records become invalid after upgrades] -> Ignore invalid records when reading and bound both lists whenever writing.
- [Long dimensions or coordinates overflow a row] -> Use clipped or scrolling row presentation while retaining the full value in hover text where needed.

## Migration Plan

Existing configurators have no history or favorite tags and therefore open an empty detached menu. The first successful attachment initializes recent history; no data fixer is required. Rolling back leaves unknown item tags that older versions ignore.

## Open Questions

None.
30 changes: 30 additions & 0 deletions openspec/changes/add-configurator-target-history/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Why

Detaching an Ultimate Configurator currently discards convenient access to its previous target, forcing players to revisit blocks whenever they want to switch configurations. A detached-item menu with recent and favorite targets makes repeated configuration work faster while keeping each configurator self-contained.

## What Changes

- Record all favorites plus the three most recently attached distinct non-favorite blocks on the Ultimate Configurator, ordered by last use.
- Allow up to 16 recorded targets to be favorited and unfavorited from a detached configurator menu.
- Open a native target-selection menu when the player right-clicks air with a detached Ultimate Configurator.
- Reattach immediately when the player selects a valid stored target.
- Display each stored target's configurator type and coordinates, including its dimension, and allow favorites to be renamed.
- Hide a renamed favorite's coordinates behind its custom name and mark it with a golden outline; clearing the name restores the type-and-coordinate label.
- Provide a Settings tab for naming the configurator and choosing favorite text and box render styles, with per-favorite color overrides.
- Render favorites in the world while a detached Ultimate Configurator is held.
- Persist recent targets, favorites, and favorite names in the Ultimate Configurator's NBT.

## Capabilities

### New Capabilities

- `configurator-target-history`: Detached Ultimate Configurator target history, favorites, naming, validation, and selection UI.

### Modified Capabilities

None.

## Impact

- Affects Ultimate Configurator attachment and air-use behavior, item NBT, client screen opening, loader-neutral networking, localization, and client/server GameTests.
- Adds no external dependencies and does not change configured block data or Lua APIs.
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
## ADDED Requirements

### Requirement: Target history
The Ultimate Configurator SHALL persist one last-used target order containing every favorite and the three most recently attached distinct non-favorites. Each target SHALL include its configuration type, dimension, and block coordinates, and target identity SHALL be determined by dimension and coordinates.

#### Scenario: Attach a new target
- **WHEN** a player attaches the configurator to a configurable block not already in its history
- **THEN** the system stores that target first and retains every favorite plus at most the three newest distinct non-favorites

#### Scenario: Reattach a stored target
- **WHEN** a player attaches the configurator to a dimension and coordinates already in its history
- **THEN** the system updates the stored configuration type, moves that target to the first position, and does not create a duplicate

#### Scenario: Detach the configurator
- **WHEN** a player detaches an Ultimate Configurator
- **THEN** the system clears its active binding without clearing recent targets or favorites

### Requirement: Detached target menu
The system SHALL open a non-pausing native target menu when a player right-clicks air with a detached main-hand Ultimate Configurator. The menu SHALL display one list containing all favorites and the three latest non-favorites, ordered by last use.

#### Scenario: Open detached configurator menu
- **WHEN** a player normally right-clicks air with a detached Ultimate Configurator in the main hand
- **THEN** the system opens the target menu and displays the configurator's stored targets in last-used order

#### Scenario: Use an attached configurator on air
- **WHEN** a player normally right-clicks air with an attached Ultimate Configurator
- **THEN** the system preserves the active configuration mode's existing air-use behavior instead of opening the target menu

#### Scenario: Empty history
- **WHEN** the target menu opens for a configurator with no stored targets
- **THEN** the system displays the list as empty without creating records

### Requirement: Favorite target management
The target menu SHALL show a favorite action for non-favorites and an edit action for favorites. Each Ultimate Configurator SHALL persist no more than 16 distinct favorites while preserving last-use ordering in the combined target list.

#### Scenario: Favorite a recent target
- **WHEN** a player favorites a recent target and fewer than 16 favorites exist
- **THEN** the system marks it as a favorite without changing its last-used position

#### Scenario: Favorite an existing favorite
- **WHEN** a duplicate favorite action references a target already in the favorite list
- **THEN** the system retains one favorite record and does not exceed the limit

#### Scenario: Reach the favorite limit
- **WHEN** a player attempts to add a distinct seventeenth favorite
- **THEN** the server rejects the addition and retains the existing 16 favorites

#### Scenario: Unfavorite a target
- **WHEN** a player removes a target from favorites
- **THEN** the system removes its favorite record and retains it only if it remains among the three latest non-favorites

#### Scenario: Select or rename a favorite
- **WHEN** a player selects an existing favorite
- **THEN** the system promotes it to the first last-used position
- **WHEN** a player only renames an existing favorite
- **THEN** the system preserves its last-used position

### Requirement: Favorite target names
The target menu SHALL allow a player to open a favorite editor and assign a custom name of at most 64 characters. A named favorite SHALL display only its custom name with a golden outline; an unnamed target SHALL display its translated block name, dimension, and coordinates.

#### Scenario: Rename a favorite
- **WHEN** a player submits a non-empty valid custom name for a favorite
- **THEN** the system persists the name on the configurator and hides that row's type, dimension, and coordinates behind the custom name

#### Scenario: Clear a favorite name
- **WHEN** a player submits an empty custom name for a named favorite
- **THEN** the system removes the custom name and restores the type, dimension, and coordinate label

#### Scenario: Reject an oversized name
- **WHEN** a player submits a custom name longer than 64 characters
- **THEN** the server rejects the mutation and preserves the previous name

#### Scenario: Rename a non-favorite target
- **WHEN** a client requests a rename for a target that is not currently a favorite
- **THEN** the server rejects the mutation

### Requirement: Configurator appearance settings
The detached menu SHALL provide a Settings tab for assigning a custom Ultimate Configurator name and favorite text and box render styles. A favorite editor SHALL allow each favorite to override text and box colors using the existing color picker.

#### Scenario: Change configurator settings
- **WHEN** a player submits a valid name or favorite render style from the Settings tab
- **THEN** the server persists it on that Ultimate Configurator and synchronizes the item

#### Scenario: Override favorite colors
- **WHEN** a player selects a valid text or outline color in a favorite editor
- **THEN** the server persists that color on the favorite and the target list uses it instead of the configurator default

### Requirement: Detached favorite rendering
While a detached Ultimate Configurator is held in the main hand, the client SHALL render all favorites in the current dimension using the configured text and box styles and each favorite's colors.

#### Scenario: Render detached favorites
- **WHEN** a player holds a detached Ultimate Configurator with current-dimension favorites
- **THEN** the client renders their configured labels and box effects in the world

#### Scenario: Hide cross-dimension favorites
- **WHEN** a favorite belongs to another dimension
- **THEN** the client does not render it in the current world

### Requirement: Validated target selection
Selecting a stored target row SHALL immediately reattach the configurator and close the menu only when the target is in the player's current dimension, its position is loaded, and its current block state supports the stored configuration type.

#### Scenario: Select a valid target
- **WHEN** a player selects a stored target in the current dimension whose loaded block still supports its stored configuration type
- **THEN** the server attaches the configurator, promotes the target in recent history, synchronizes the item, and closes the menu

#### Scenario: Select a target in another dimension
- **WHEN** a player selects a stored target outside the current dimension
- **THEN** the system leaves the configurator detached, keeps the record, and reports that the target is unavailable

#### Scenario: Select an unloaded target
- **WHEN** a player selects a stored target whose position is not loaded
- **THEN** the system does not load the position, leaves the configurator detached, keeps the record, and reports that the target is unavailable

#### Scenario: Select a changed or removed target
- **WHEN** a player selects a loaded stored target whose block no longer supports the stored configuration type
- **THEN** the system leaves the configurator detached, keeps the record, and reports that the target is unavailable

### Requirement: Server-authoritative item mutations
The server SHALL accept target selection, favorite, unfavorite, and rename actions only for a detached Ultimate Configurator in the player's main hand and SHALL resolve each requested target against that stack's current stored records.

#### Scenario: Mutate a stale or forged target
- **WHEN** a client requests an action for a target absent from the server-side configurator history and favorites
- **THEN** the server rejects the action without changing item NBT

#### Scenario: Mutate a different item state
- **WHEN** a client requests an action while the main-hand item is not a detached Ultimate Configurator
- **THEN** the server rejects the action without changing either item
27 changes: 27 additions & 0 deletions openspec/changes/add-configurator-target-history/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## 1. Target Data And Attachment

- [x] 1.1 Add bounded NBT serialization and parsing for target records, a last-used history containing all favorites plus three non-favorites, a 16-favorite limit, and optional 64-character favorite names.
- [x] 1.2 Record recent targets in the shared active-mode save path while preserving history and favorites during detach.
- [x] 1.3 Add item mutation helpers for favorite toggle, rename/reset, and validated reattachment using current dimension, loaded position, and registered block mode.

## 2. Networking And Interaction

- [x] 2.1 Add and register a loader-neutral serverbound target action message that validates a detached main-hand configurator and resolves target identity from authoritative item NBT.
- [x] 2.2 Synchronize successful item mutations and report rejected, unavailable, and favorite-limit actions without loading target chunks.
- [x] 2.3 Open the target-history screen on client-side normal air use only when the Ultimate Configurator is detached, preserving all attached-mode air interactions.

## 3. Target Menu

- [x] 3.1 Add the loader-neutral client platform hook and non-pausing screen entry for the held detached configurator.
- [x] 3.2 Implement one last-used target list with multi-row pagination, default block/dimension/coordinate labels, and golden-outlined custom-name-only favorite labels.
- [x] 3.3 Implement immediate row selection, non-favorite Favorite actions, favorite Edit actions, and a favorite edit screen with rename/reset/removal controls, a 64-character client limit, and server-authoritative refresh/close behavior.
- [x] 3.4 Add English and Ukrainian localization source entries for the screen, controls, empty states, and mutation feedback, then regenerate loader resources.
- [x] 3.5 Add a Settings tab for configurator naming and favorite text/box styles, plus per-favorite text and box color pickers.
- [x] 3.6 Render current-dimension favorites in the world while a detached configurator is held.

## 4. Verification

- [x] 4.1 Add server GameTests for MRU deduplication/trimming, detach retention, favorite ordering/limit, rename validation, malformed NBT handling, and target-selection validation.
- [x] 4.2 Add client GameTests for detached air-use opening, section rendering and labels, favorite/rename controls, successful selection closure, and attached-mode interaction precedence.
- [x] 4.3 Run the root Fabric and Forge GameTests under Xvfb with an explicit timeout and fix failures.
- [x] 4.4 Run the timed root multi-loader build and fix failures.
Loading
Loading