Allow part configurations to be copied and pasted with the Wrench - #1721
Conversation
Adds a new CONFIG mode to the Wrench, in which shift+right-clicking a part copies its configuration into the Wrench, and right-clicking another part of the same type pastes it. The configuration consists of three sections: the general part settings (update interval, priority, channel, target side override and target offset), the statically configured aspect properties, and all variable cards (the active variable inventory, the aspect setting variables and the offset variables). Pasted variable cards get a new variable id, and each of them consumes one blank Variable Card from the player's inventory, unless they are in creative mode. If there are not enough blank cards, the settings are still applied and the player is told how many more cards are needed. Cards that were already present in the target part are given back to the player. The Settings and Aspect Settings screens also get copy and paste buttons, which only copy and paste what those screens show. In the Aspect Settings screen, settings are matched by property type instead of by aspect, so settings can be copied between different aspects that share a property. Closes #859 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
Replaces the copy and paste buttons in the Settings and Aspect Settings screens with separate Wrench modes, so that copying a subset is a property of the tool rather than of the screen you happen to have open. The Wrench now has four configuration modes: Copy Configuration takes the whole configuration and only pastes onto a part of the same type, while Copy Part Settings, Copy Aspect Settings and Copy Variable Cards each take one section and can be pasted onto any part. Copying now only stores values that differ from the defaults of a freshly placed part, so pasting never resets a setting that was left alone on the copied part. Copying a part that is still fully default reports that there is nothing to copy instead of storing an empty configuration. The Wrench tooltip lists what was copied and how many blank Variable Cards pasting it needs, and the active mode is shown on the Wrench item through a small coloured badge per mode. The paste result is now reported as what was actually applied, with the warnings sent to the chat rather than appended to the action bar line, where they did not fit. Closes #859 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
The configuration sections now match the two things a player configures on a part, and each Wrench mode maps onto one of them: * Copy All takes both, and still only pastes onto a part of the same type * Copy Settings takes the update interval, priority, channel, target side and target offset, together with the offset variables * Copy Aspect takes the active variable, the aspect properties and the aspect setting variables Every variable inventory belongs to exactly one section, so the offset variables travel with the settings and the active and aspect setting variables travel with the aspects, rather than all of them forming a section of their own. This replaces the former Copy Aspect Settings and Copy Variable Cards modes, which split the same data along a line that did not match any screen a player uses. Counts in the messages and the tooltip moved to the end of their sentence, so that they read correctly for a single card as well. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
The active variable was already covered, but the aspect setting variables and the offset variables travel through the same copy, so assert their ids change too and that the cards they replace are given back to the player. Both tests were checked against a deliberately broken copy that reuses the original id, so that they can actually fail. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
The mode explanation moved behind the same shift that already reveals the item info, so the resting tooltip is only the state that matters: the mode, where the configuration came from, what it includes and how many blank Variable Cards pasting it needs. The explanations themselves are shorter, as they used to wrap over three lines. The mode badges on the Wrench are now small glyphs instead of plain coloured squares, so that they say what the mode does rather than having to be memorised by colour: two linked positions for the offset modes, echoing the Part Offsets button, two overlapping sheets for Copy All, a grid of fields for Copy Settings, echoing the Part Settings button, and a round aspect icon for Copy Aspect. Also renames the copied section in the tooltip from "settings" to "part settings". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
The two offset badges were flat blobs that only differed by a single pixel, and their outlines vanished against the dark inventory slot. They become move arrows for the saved offset, and an arrow pointing at a face for the saved offset and side. The copy-all badge no longer uses a generic copy glyph, but combines the badges of the two modes it covers: the settings grid next to the aspect orb. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
They become a cube linked to the cube at the offset position, and the same with sides instead of cubes for the mode that also saves a side. Both are outlined in black, so that they stay readable on the light backgrounds that the item is drawn on outside of inventory slots. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
The offset badge becomes a cube with a line running out to the offset position, and the badge of the mode that also saves a side keeps that same cube, with the side next to it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
rubensworks
left a comment
There was a problem hiding this comment.
Also do these things:
- Even when the default of offset mode is shown, it shows in the tooltip the copied target and "Included". This is not necessary; hide it for those modes.
- Can you manually test using clientdevbridge that this copying also works correctly for Integrated Tunnels interfaces, exporters, and importers?
- Don't modify the changelog yourself.
| * An immutable snapshot of the configuration of a part, which can be pasted onto another part. | ||
| * | ||
| * Only things that a player can configure are stored, | ||
| * so no part id, max offset, enabled state, error messages or active aspect. |
There was a problem hiding this comment.
Regarding max offset, could we make it so that offset enhancements can also be copied? And then taken care of in the same way as variables; the player needs the correct amount of them to paste. It also needs to be shown in the tooltip.
There was a problem hiding this comment.
Done in 74649c1. The maximum offset is now part of PartSettings (so it belongs to the Copy Settings section), stored only when it is above the default of zero.
Pasting raises the target part to that maximum offset by consuming Offset Enhancements from the player, in the same shape as the variable cards: if the player is short, nothing is consumed and PartConfigApplyResult reports how much value is still needed, as a chat warning. A target that already has a higher maximum offset is left alone, and creative players do not pay. Applying it happens before the target offset, so the copied offset now lands instead of failing on a fresh part.
One thing worth flagging: enhancements cannot be split, so if the player only has enhancements that do not add up exactly (needing 8, holding a 4 and a 5), they spend 9 and the part gets 9. consumeOffsetEnhancements takes the smallest ones first to keep that waste as low as possible.
The tooltip shows Offset Enhancement value needed: N next to the blank card requirement, for the sections the current mode pastes. Covered by five new game tests (consuming, insufficient, creative, keeping a higher existing offset, and the Aspect mode not touching it) plus unit tests for the new snapshot field.
Generated by Claude Code
| NeoForge.EVENT_BUS.addListener(this::onPlayerLoggedOut); | ||
| } | ||
|
|
||
| public void onClientSetup(FMLClientSetupEvent event) { |
There was a problem hiding this comment.
Please move this to the ItemWrenchConfigClient. (if this class does not exist yet, make it. This pattern should exist for other configs that require client-only things)
There was a problem hiding this comment.
Done in 74649c1. There was no item-level client config in this repo yet, so I added ItemWrenchClientConfig, following the BlockCableClientConfig pattern: it extends CyclopsCore's ItemClientConfig and registers its own mod event bus listener. ClientProxy no longer knows about the wrench.
Two notes on how it is wired:
- I named it
ItemWrenchClientConfigrather thanItemWrenchConfigClient, to matchBlockCableClientConfigand CyclopsCore's ownItemClientConfig/BlockClientConfig. Say the word if you prefer the other order. - This required moving
ItemWrenchConfigfromItemConfigtoItemConfigCommon, as only the latter has thegetItemClientConfighook (the same splitBlockCableConfigalready uses). The other item configs in this repo still useItemConfig; I left them alone. SincegetItemClientConfigis not cached by the base class, the config caches its instance so the listener is only registered once.
Verified in a dev client that the mode still shows on the item.
Generated by Claude Code
Copy the offset enhancements of a part as well, consuming enhancements from the player just like the variable cards do, and show what a paste needs in the Wrench tooltip. Drop the unused Wrench lookup that was left over from the gui buttons, as the Wrench that a player acts with always comes from the interaction itself. Move the wrench mode item property into an item client config, and replace the lombok accessors of the apply result by plain ones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
A configuration stays in the Wrench when switching modes, so the source part and the included sections were also shown in the modes that do nothing with it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
|
Sorry, I acted on your inline comments first and missed the three points in the review body. All three are handled now. Tooltip in non-config modes (7dad1fb): the copied source and Changelog (7dad1fb): reverted, Integrated Tunnels, manually tested with clientdevbridge: I ran a dev client with IntegratedTunnels 1.21.1-1.11.1 in the mods folder and copied between pairs of parts, configuring each source through its own gui:
Copy All correctly refused to paste an Item Interface configuration onto an Item Exporter, and the tooltip named the source part properly ( One gap worth deciding on: the Item Interface's Interface Channel ( If you want that covered, the smallest change on this side is an extra Generated by Claude Code |
Part types, and the part types that addons add in particular, hold state that a configuration snapshot can not know about. They can now store it per section, read it back when pasting, tell the player what a paste took, and state in the tooltip what a paste is going to need. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
|
Added the extension point in c599bc6, kept generic so any addon part type can use it.
CompoundTag snapshotConfigExtra(ValueDeseralizationContext ctx, S state, PartConfigSection section);
void applyConfigExtra(ValueDeseralizationContext ctx, PartTarget target, S state, PartConfigSection section,
PartConfigSnapshot snapshot, Player player, PartConfigApplyResult result);
List<Component> getConfigExtraRequirements(PartConfigSnapshot snapshot, PartConfigSection section);Design points:
For the Item Interface, Integrated Tunnels would override the first two on its interface part types and move Two game tests cover the plumbing, using a part type proxy that stores and reads back a value: one asserts the value survives a copy and paste and that the part type's own message reaches the player, the other asserts Copy Aspect neither stores nor pastes a Generated by Claude Code |
Widening it to public broke every part state outside of this mod that overrides it, such as the ones in Integrated Tunnels, so the public accessor that snapshots need is a separate method that delegates to it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF
Closes #859
What
The Wrench gains three configuration modes. Shift+right-clicking a part copies into the Wrench, right-clicking another part pastes.
Every variable inventory belongs to exactly one section, so the offset variables travel with the settings and the active and aspect setting variables travel with the aspects.
Copy Allis exactlyCopy Settings+Copy Aspect.Only non-default values are copied. A setting left alone on the source part is not stored, so pasting never resets it on the target. Copying a part that is still entirely default says so instead of storing an empty configuration.
Blank Variable Cards are checked before anything is consumed. Each pasted card costs one blank Variable Card (skipped in creative). If there aren't enough, the settings still apply, the cards are skipped, and the player is told how many more are needed. The Wrench tooltip lists the requirement up front, scoped to what the current mode will actually paste:
The active mode is visible on the item — a small coloured badge per mode in the corner of the Wrench texture, driven by a
wrench_modeitem property and one model override per mode.Cards already in the target part are given back to the player (dropped if the inventory is full), and pasted cards always get a new variable id.
Implementation
core/part/PartConfigSection:PART_SETTINGSandASPECT, plusforInventoryNamewhich decides which section a variable inventory belongs to.core/part/PartConfigSnapshot: versioned, codec-backed, stored as aCompoundTagin a newwrench_part_configdata component. Every part setting is anOptional, so absent means "was default, don't touch".core/helper/PartConfigHelpers: snapshot/apply, non-default filtering, card copying, blank consumption, inventory resolution.IPartType#snapshotConfig/#applyConfigandIPartState#getDefaultUpdateInterval, alldefaultmethods so addons keep compiling.Tests
GameTestsWrenchConfig: full copy/paste, part type mismatch, each mode in isolation, the offset variables belonging to Settings and the active variable to Aspect, subset across part types, card ids and ejection, insufficient blanks, creative, out-of-range offset, copying a default part, pasting not resetting untouched settings, sneak-clicking not removing the part, and mode cycling../gradlew buildpasses and all 959 game tests pass.Verified in a dev client
Driven with clientdevbridge-cli. Confirmed in-game: the six mode badges are distinct; each mode's tooltip lists only what that mode pastes; a part with a changed update interval and an active variable copies as
partSettings:{updateInterval:40}under Copy Settings, asvariableCards:[$active]under Copy Aspect, and as both under Copy All; a default part reports nothing to copy; sneak-clicking in a config mode copies without removing the part; the full mode refuses a different part type while the subset modes accept it; and with no blank cards the settings still apply with the warning legible in chat.Three bugs were found and fixed this way: the subset modes fell through to the part-removal branch, the combined result message ran off both edges of the screen, and the counts read as "1 blank Variable Cards".
🤖 Generated with Claude Code
https://claude.ai/code/session_01LBAgcFp6jWcYRWz9N8h7AF