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-24
77 changes: 77 additions & 0 deletions openspec/changes/add-proxy-observer-render-settings/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
## Context

Peripheral Proxy and Remote Observer are already Ultimate Configurator modes with client overlays, but their air-click handlers and settings screens do not exist and their target presentation is hard-coded. Network Manager recently established the desired text styles (`none`, `regular`, `bold`), box styles (`none`, `outline`, `filled`, `flare`), client-only screen opening, authenticated serverbound mutations, and reusable box/flare rendering behavior.

Unlike Network Manager's per-category configurator preferences, Proxy and Observer settings apply uniformly to all targets and must belong to the block so computers and every player observe the same configuration. The core implementation must remain loader-independent; Fabric and Forge only bridge client screen opening and packet transport.

## Goals / Non-Goals

**Goals:**

- Give both configurator modes one consistent target-render settings screen.
- Store, synchronize, and render one text style and one box style per block.
- Preserve existing target presentation when old block data lacks the new fields.
- Expose the same persisted values through `getConfiguration` and validated Lua setters.
- Reuse the Network Manager style vocabulary and rendering primitives.

**Non-Goals:**

- Configurable colors, source-marker styles, overlay range, or per-target styles.
- Changes to target membership, Proxy peripheral-side lookup, Observer capacity/duplicate behavior, or other existing APIs.
- Changes to Network Manager configuration ownership or rendering behavior.
- New container menus, dependencies, or loader-specific business logic.

## Decisions

### Share style types and rendering controls

Move the Network Manager text and box style enums to a shared core location and update Network Manager to use them. This keeps persistence, packets, UI labels, Lua serialization, and rendering on one vocabulary instead of introducing equivalent Proxy/Observer enums. Reuse or minimally extract the existing bidirectional style button and target box/text rendering primitives where that reduces duplication; do not generalize the full Network Manager screen or renderer.

Alternative considered: keep mode-specific enums and duplicate controls. Rejected because three representations of the same closed value set would require repeated parsing and drift-prone rendering branches.

### Store settings on each block entity

Peripheral Proxy and Remote Observer block entities each hold `textStyle` and `boxStyle`, save their enum names to NBT, and provide one validated mutation path that marks data dirty and synchronizes it to clients. Missing or invalid NBT uses type-specific defaults: Proxy `regular` plus `flare`, Observer `none` plus `flare`.

Alternative considered: store preferences on the Ultimate Configurator like Network Manager. Rejected because the requested setting is peripheral configuration, must be available to Lua, and applies to all players rather than one held item.

Remote Observer direct tracking mutations also use the existing block-entity synchronization path, and incoming NBT replaces rather than appends tracked positions so removed targets do not remain in client overlays.

### Use one lightweight screen and packet path

Both configurator modes implement `onBlockMiss`, retain the existing dimension guard, and request a shared target-render settings screen through `ModClientPlatform`. The screen entry resolves the bound client block entity and opens only for a Proxy or Observer. The screen presents one text-style control and one box-style control with the same forward/ reverse cycling behavior as Network Manager.

Style changes update the synchronized client value immediately for responsive controls and send a serverbound message. The server accepts a mutation only when the player holds a main-hand Ultimate Configurator bound to the same mode, dimension, and block position and the expected block entity is loaded. The authoritative block-entity mutation then synchronizes the result.

Alternative considered: separate screens and packets per block type. Rejected because the fields, controls, validation flow, and interaction are identical.

### Keep target-specific labels and distinguish source connections

Proxy text remains the assigned remote peripheral name. Observer text is the target block's translated display name. Text remains white. Proxy and Observer source effects are green, Observer targets are orange, and Proxy targets are orange except for the green face to which the Proxy connects in outline and filled modes. Target flares remain orange. The selected box style applies to the bound block and every target, so selecting `none` suppresses all box effects.

Alternative considered: coordinates for Observer labels or configurable colors. Rejected because block names were selected and color configuration is outside the requested scope.

### Expose lowercase Lua values

Both peripherals add lowercase `textStyle` and `boxStyle` strings to `getConfiguration`. `setTextStyle` accepts exactly `none`, `regular`, or `bold`; `setBoxStyle` accepts exactly `none`, `outline`, `filled`, or `flare`. Invalid input returns `false` with an explanatory error and leaves state unchanged; valid input returns success and uses the same synchronized block-entity mutation as the UI.

Alternative considered: case-insensitive parsing or uppercase enum names. Rejected in favor of the explicitly selected lowercase-only API contract.

## Risks / Trade-offs

- [Moving shared style enums touches existing Network Manager code] -> Keep it a mechanical type relocation and retain its persisted enum names and behavior.
- [A client screen can outlive or lose its bound block entity] -> Resolve the expected entity before opening and close or disable mutation when it is no longer available.
- [Optimistic controls can briefly differ from rejected server state] -> Apply the authoritative synchronized block value on the next update and test packet validation paths.
- [Translated Observer names depend on client resources] -> Derive labels from the synchronized target block state and use Minecraft's normal translated block name.

## Migration Plan

1. Add shared style types and block-entity fields with missing/invalid-value fallbacks that reproduce current visuals.
2. Add synchronized mutations, Lua exposure, screen opening, and rendering consumption.
3. Verify existing Network Manager behavior and both loaders through build, GameTests, and TypeScript fixtures.

No data fixer is required. Rolling back leaves unknown NBT fields that older versions ignore; existing tracked targets remain intact.

## Open Questions

None.
31 changes: 31 additions & 0 deletions openspec/changes/add-proxy-observer-render-settings/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Why

Peripheral Proxy and Remote Observer overlays are currently fixed, while Network Manager overlays can be adjusted to suit a player's visibility needs. Extending the same text and box style controls to these blocks makes configurator behavior consistent and lets their shared block-level presentation be managed from both the UI and Lua.

## What Changes

- Open a dedicated render-settings screen when a bound Ultimate Configurator is right-clicked in the air for a Peripheral Proxy or Remote Observer.
- Configure one text style and one box style for all targets of the bound block, using the Network Manager style choices.
- Render Peripheral Proxy target peripheral names and Remote Observer target block names according to the selected text style.
- Apply the selected box style with green bound blocks, orange Observer targets, and orange Proxy targets with a green attached face.
- Persist and synchronize render settings on each Peripheral Proxy and Remote Observer block entity.
- Synchronize direct Remote Observer tracking additions and removals so clients discard stale targets.
- Include `textStyle` and `boxStyle` in each peripheral's `getConfiguration` result and expose `setTextStyle` and `setBoxStyle` Lua methods.
- Preserve existing visuals by default: Peripheral Proxy uses regular text with flare boxes, and Remote Observer uses no text with flare boxes.

## Capabilities

### New Capabilities
- `configurable-target-rendering`: Configurator UI, rendering behavior, persistence, synchronization, and Lua configuration for Peripheral Proxy and Remote Observer target overlays.

### Modified Capabilities

None.

## Impact

- Shared configurator mode, screen, rendering, and networking code in the core module.
- Peripheral Proxy and Remote Observer block entities, client renderers, and ComputerCraft peripheral APIs.
- Loader client-platform bridges used to open screens.
- Client GameTests, server GameTests, TypeScript fixtures, localization, and generated Lua API documentation.
- No new dependencies and no breaking changes; persisted blocks without the new fields retain their current presentation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
## ADDED Requirements

### Requirement: Bound configurators open target render settings
The system SHALL open a target render settings screen when a player right-clicks the air without crouching while holding a main-hand Ultimate Configurator bound to a Peripheral Proxy or Remote Observer in the current dimension.

#### Scenario: Open Peripheral Proxy settings
- **WHEN** a player uses a configurator bound to a loaded Peripheral Proxy and the use ray misses all blocks
- **THEN** the client opens the target render settings screen for that Peripheral Proxy

#### Scenario: Open Remote Observer settings
- **WHEN** a player uses a configurator bound to a loaded Remote Observer and the use ray misses all blocks
- **THEN** the client opens the target render settings screen for that Remote Observer

#### Scenario: Bound block is unavailable
- **WHEN** the bound position is in another dimension, unloaded, removed, or no longer contains the expected block entity
- **THEN** the system does not open a settings screen and reports that the target is unavailable

#### Scenario: Crouching air use remains detach behavior
- **WHEN** a player crouch-right-clicks the air with a bound Ultimate Configurator
- **THEN** the configurator detaches from its bound block instead of opening the target render settings screen

### Requirement: One screen configures all targets
The target render settings screen SHALL show the block's current text style and box style and SHALL apply each selected style uniformly to every target tracked by that block.

#### Scenario: Cycle text style forward
- **WHEN** the player left-clicks the text style control
- **THEN** the control cycles through `none`, `regular`, and `bold` in forward order and applies the selected value to the block

#### Scenario: Cycle box style backward
- **WHEN** the player right-clicks the box style control
- **THEN** the control cycles through `none`, `flare`, `filled`, and `outline` from the initial `none` value and applies the selected value to the block

#### Scenario: Reopen settings
- **WHEN** the player closes and reopens the screen for the same block
- **THEN** the controls show that block's persisted text and box styles

### Requirement: Style mutations are server-authoritative
The system MUST accept configurator style mutations only for a loaded Peripheral Proxy or Remote Observer matching the main-hand configurator's bound mode, position, and dimension, and SHALL synchronize accepted values to clients.

#### Scenario: Valid configurator mutation
- **WHEN** a player changes a style for the block to which the held configurator is validly bound
- **THEN** the server stores the new style and synchronizes it to observing clients

#### Scenario: Invalid configurator mutation
- **WHEN** a mutation names an invalid style or does not match the held configurator's mode, position, dimension, or target block type
- **THEN** the server rejects the mutation without changing the block's settings

### Requirement: Peripheral Proxy renders configured targets
While Peripheral Proxy configurator rendering is active, the system SHALL render every tracked target using the Proxy's one configured text style and one configured box style.

#### Scenario: Proxy text style
- **WHEN** the Proxy text style is `regular` or `bold`
- **THEN** each target displays its assigned remote peripheral name in white using the selected weight

#### Scenario: Proxy text disabled
- **WHEN** the Proxy text style is `none`
- **THEN** no target peripheral names are rendered

#### Scenario: Proxy box style
- **WHEN** the Proxy box style is `outline`, `filled`, or `flare`
- **THEN** the Proxy displays the selected green box effect
- **AND** each target displays the selected orange box effect, with its attached face green for outline and filled styles
- **AND** target flares are orange
- **AND** no fixed flare is also displayed

#### Scenario: Proxy boxes disabled
- **WHEN** the Proxy box style is `none`
- **THEN** no target box or target flare is rendered

### Requirement: Remote Observer renders configured targets
While Remote Observer configurator rendering is active, the system SHALL render every tracked target using the Observer's one configured text style and one configured box style.

#### Scenario: Observer text style
- **WHEN** the Observer text style is `regular` or `bold`
- **THEN** each target displays the target block's translated name in white using the selected weight

#### Scenario: Observer text disabled
- **WHEN** the Observer text style is `none`
- **THEN** no target block names are rendered

#### Scenario: Observer box style
- **WHEN** the Observer box style is `outline`, `filled`, or `flare`
- **THEN** the Observer displays the selected green box effect
- **AND** each target displays the selected orange box effect
- **AND** no fixed flare is also displayed

#### Scenario: Observer boxes disabled
- **WHEN** the Observer box style is `none`
- **THEN** no target box or target flare is rendered

### Requirement: Remote Observer tracking changes synchronize
The system SHALL synchronize direct Remote Observer tracking additions and removals and SHALL replace stale client tracking state when updates arrive.

#### Scenario: Remove a tracked position through Lua
- **WHEN** a computer removes a tracked position from a Remote Observer
- **THEN** observing clients remove that position from the Observer overlay

### Requirement: Box style includes the source block
The system SHALL render the bound Peripheral Proxy or Remote Observer in green using the same box style selected for its targets.

#### Scenario: All box effects disabled
- **WHEN** box style is `none`
- **THEN** source and target box effects are absent

### Requirement: Render settings persist with compatibility defaults
The system SHALL persist text and box styles in each Peripheral Proxy and Remote Observer block entity and SHALL safely fall back to the block type's compatibility defaults when either value is absent or invalid.

#### Scenario: Peripheral Proxy legacy data
- **WHEN** a Peripheral Proxy loads without valid render-style fields
- **THEN** its text style is `regular` and its box style is `flare`

#### Scenario: Remote Observer legacy data
- **WHEN** a Remote Observer loads without valid render-style fields
- **THEN** its text style is `none` and its box style is `flare`

#### Scenario: Persist configured styles
- **WHEN** a configured block is saved and loaded again
- **THEN** its valid text and box style values are restored

### Requirement: Lua exposes and changes render settings
Peripheral Proxy and Remote Observer peripherals SHALL include lowercase `textStyle` and `boxStyle` values in `getConfiguration` and SHALL expose `setTextStyle` and `setBoxStyle` methods that mutate the same persisted block settings.

#### Scenario: Read configuration
- **WHEN** a computer calls `getConfiguration`
- **THEN** the returned table includes the block's current `textStyle` and `boxStyle` lowercase strings

#### Scenario: Set valid text style
- **WHEN** a computer calls `setTextStyle` with exactly `none`, `regular`, or `bold`
- **THEN** the method succeeds, persists the selected text style, and synchronizes it to clients

#### Scenario: Set valid box style
- **WHEN** a computer calls `setBoxStyle` with exactly `none`, `outline`, `filled`, or `flare`
- **THEN** the method succeeds, persists the selected box style, and synchronizes it to clients

#### Scenario: Reject invalid Lua style
- **WHEN** a computer passes any other spelling or letter case to either style setter
- **THEN** the method returns `false` with an explanatory error and leaves both settings unchanged
37 changes: 37 additions & 0 deletions openspec/changes/add-proxy-observer-render-settings/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## 1. Shared Render Styles

- [x] 1.1 Move text and box style enums into shared core types and update Network Manager references without changing its persisted values or behavior.
- [x] 1.2 Extract only the reusable style-cycle control and target text/box rendering needed by all three configurator renderers.

## 2. Persisted Peripheral Settings

- [x] 2.1 Add persisted and synchronized text/box styles to Peripheral Proxy with `regular` and `flare` compatibility defaults and safe invalid-NBT fallback.
- [x] 2.2 Add persisted and synchronized text/box styles to Remote Observer with `none` and `flare` compatibility defaults and safe invalid-NBT fallback.
- [x] 2.3 Centralize each block entity's style mutation so UI and Lua changes share validation, dirty marking, and client synchronization.
- [x] 2.4 Synchronize direct Remote Observer tracking changes and replace stale tracked positions on client reload.

## 3. Lua Configuration API

- [x] 3.1 Add lowercase `textStyle` and `boxStyle` values to Peripheral Proxy and Remote Observer `getConfiguration` results.
- [x] 3.2 Add lowercase-only `setTextStyle` and `setBoxStyle` Lua methods with success results and non-mutating explanatory failures.
- [x] 3.3 Update TypeScript fixtures to exercise defaults, valid mutations, synchronized configuration values, and invalid/case-mismatched values for both peripherals.

## 4. Configurator Screen And Networking

- [x] 4.1 Add non-crouching air-use screen opening to Peripheral Proxy and Remote Observer modes while preserving dimension checks and crouching detach behavior.
- [x] 4.2 Add the shared target render settings screen and client entry validation for loaded Proxy/Observer block entities.
- [x] 4.3 Add the serverbound style message and loader registrations, validating main hand, bound mode, position, dimension, block type, and style value before mutation.
- [x] 4.4 Add Fabric and Forge client-platform screen bridges plus localized screen labels, style values, and unavailable feedback.

## 5. Target Rendering

- [x] 5.1 Update Peripheral Proxy rendering to use persisted styles for white peripheral-name text, a green source, and orange targets with green attached faces.
- [x] 5.2 Update Remote Observer rendering to use persisted styles for translated white block-name text, a green source, and orange targets.
- [x] 5.3 Verify `none`, `regular`, `bold`, `outline`, `filled`, and `flare` produce the specified effects without duplicate target flares.

## 6. Verification

- [x] 6.1 Add server GameTests for style defaults, valid/invalid mutation, persistence, and synchronization on both block entities.
- [x] 6.2 Add client GameTests for opening each screen, forward/reverse style cycling, unavailable targets, and retained crouching detach behavior.
- [x] 6.3 Run `:typescript-tests:compileTestLua` and fix fixture or generated API regressions.
- [x] 6.4 Run the Xvfb-backed Fabric and Forge GameTests and the timed multi-loader build, fixing all regressions including Network Manager rendering and settings tests.
Loading
Loading