Repository navigation
feat!: modernise BetterGoPaint for Minecraft 26 and AntiRedstoneClock quality - #34
Merged
Merged
Conversation
Compile against Paper API 26.2 and FastAsyncWorldEdit 2.16.1 with Gradle 9.8 and Java 25. Versions move into one catalog, shadow/plugin-yml/run-paper/hangar/spotless use their current coordinates, and build-logic, ServerLib, paperlib and EldoNexus publishing are dropped. Translations use MiniMessageTranslationStore because Adventure removed TranslationRegistry; extra language files in lang/ now fall back to the bundled English bundle. run-<version> tasks start Paper with FastAsyncWorldEdit installed. BREAKING CHANGE: requires Paper 26.1.1 or newer and Java 25. Servers on 1.21 stay on 1.1.x. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
JUnit 6, AssertJ and Mockito with JaCoCo reports. Covers brush cycling and lookup, the Paint Brush curve and translation key completeness. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Mirror the AntiRedstoneClock-Remastered pipeline: pr-lint, multi-OS PR builds on Java 25, Release Please on main with a Trivy gate before Hangar/Modrinth publishing and an SBOM upload, weekly Trivy scan, shared Renovate presets and new issue forms. Snapshot publishing on every push and release-drafter are removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Tutorial, how-to guides, reference pages for brushes, commands, permissions, configuration and supported versions, background pages and developer guides, published through GitBook. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
OpenSpec changes for the four delivered parts (platform upgrade, release pipeline, tests, documentation) and the planned follow-ups: cloud commands, brush menu hardening, non-blocking update check and dependency injection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
The first update check ran on the main thread during onEnable. It now runs from an async timer with connect and request timeouts, logs failures at debug level, tells the console once per new version and players only on join. generic.check-for-updates turns it off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
One command tree /gopaint (aliases /gp, /bgp) through cloud's PaperCommandManager with per-subcommand permissions, a generated help, range-checked and tab-completed sizes and messages from the translation bundle. The Bukkit Command subclass and the separate reload command are gone. BREAKING CHANGE: /gopaint reload needs bettergopaint.command.admin.reload (granted by the bettergopaint.admin bundle); every subcommand needs its own bettergopaint.command.* node, which defaults to true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
…m data The menu and the brush picker are recognised by their InventoryHolder instead of the title, so foreign inventories with the same title are no longer hijacked. Menu text comes from the translation bundle, rendered for the player's locale. Exported brushes are stored as versioned data under bettergopaint:brush; renamed or edited items keep working and 1.x items are converted on first use without ever throwing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Settings no longer extend FAWE's Config, which on Paper 26 could not set the plugin's fields and ignored every value in config.yml. They are now immutable records behind SettingsHolder, read by a small YAML loader that writes every key back with its comment, replaces invalid values with their default and swaps the snapshot atomically on reload. Listeners, commands and services receive narrow dependencies through Guice modules instead of the plugin instance. Guice, jakarta.inject and aopalliance are shaded and relocated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
All eight changes are implemented. Their delta specs are merged into openspec/specs/; the steps that need a game client, GitHub repository settings or GitBook access are listed as manual follow-ups in the archived task lists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Unit Test Results 23 files 23 suites 12s ⏱️ Results for commit de922fa. ♻️ This comment has been updated with latest results. |
A setup tutorial for admins, how-to guides for upgrading from 1.x, limiting builders, applying config changes, turning off update notices and reporting bugs, reference pages for console messages and files, and background on how settings are loaded and why 2.x needs Paper 26. ReferenceDocsTest fails the build when config keys, defaults, permissions, commands, supported versions or the navigation drift from the code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Two OpenSpec changes: brushes compute on WorldEdit extents instead of the Bukkit world, which also makes strokes thread-safe, and scheduling plus shared state become Folia-ready while the Folia flag stays off until FastAsyncWorldEdit supports it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
…ushes Add an immutable StrokeContext that is captured on the player's thread, a factory that converts the brush settings to WorldEdit types without asking the world for anything, a WorldEdit mask for the BetterGoPaint mask and a runner that executes a stroke in the player's WorldEdit session. Tests get a map-backed MemoryExtent and mock block types, because the WorldEdit block registry cannot initialise without a server. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Brushes now compute their blocks from a StrokeContext and an Extent. The geometry helpers (Sphere, Height, Surface, ConnectedBlocks) and the Bezier curve use BlockVector3 and Vector3, so no Bukkit world, block or location call remains in objects/ and utils/. InteractListener captures the context on the player's thread and queues a WorldEdit Brush that runs in the player's edit session with its global mask and one history entry. Brushes read all positions before they write, which keeps the result the same as when the Bukkit world was read. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Explain the stroke context, the player's WorldEdit session and //gmask in the stroke explanation, document how brushes are tested without a server and note where the implementation differs from the design decisions. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
The legacy BukkitScheduler is not available on Folia. Run the update check with Bukkit.getAsyncScheduler().runAtFixedRate and cancel the returned ScheduledTask on shutdown. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
PlayerBrushManager keeps its per-player brushes in a ConcurrentHashMap and takes a brush factory so the concurrency behaviour can be tested without a server. The Paint Brush stroke points move from a static map into the brush instance and are dropped with the player's brush state on quit. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
paper-plugin.yml declares folia-supported only when -PfoliaSupported=true is passed. Without it the flag stays false, so release builds cannot declare Folia support by accident. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
run-folia-<version> starts a local Folia test server with run-paper's Folia downloads. It installs FastAsyncWorldEdit from -PfoliaFaweUrl. Without that property the task fails when it runs, with a message that names the property, so normal builds are unaffected. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Scope and non-goals now says BetterGoPaint is prepared for Folia but does not declare support until a stable FastAsyncWorldEdit release supports it. Supported versions links to that page, and the testing guide describes run-folia-<version> for local testing only. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Without -PfoliaSupported=true the test server starts but Folia skips BetterGoPaint, which looks like a broken setup. The task now fails early and names both required properties. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Both changes are implemented; their specs move to openspec/specs/. In-game checks with a client and a Folia test with a FAWE fork remain listed as manual follow-ups. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed changes
Brings BetterGoPaint to the newest stable Minecraft line and to the quality bar of AntiRedstoneClock-Remastered. The work is planned and recorded as OpenSpec changes. All eight are implemented and archived under
openspec/changes/archive/, and their specs live inopenspec/specs/.Platform
api-versionis 26.1.build-logicbuild, ServerLib, paperlib and EldoNexus publishing are removed.run-<version>starts Paper with FAWE already installed.Behaviour fixes
config.ymlis honoured again. The settings extended FAWE'sConfig, which on Paper 26 could not set the plugin's fields. Every edit was ignored, with one "Failed to set config option" warning per key. Settings are now immutable records behindSettingsHolder. A small YAML loader writes every key with a comment, replaces invalid values with their default and swaps the settings atomically on/gopaint reload.onEnable. It now runs in the background with timeouts and can be turned off withgeneric.check-for-updates.InventoryHolderinstead of their title, so other plugins' chests with the same title are no longer hijacked.bettergopaint:brush. Renamed or edited items keep working, and items exported by 1.x are converted on first use without throwing.lang/fall back to the bundled English messages.Commands and texts
/gopaint(aliases/gp,/bgp) is now built with cloud and Brigadier. It has a generated help, range-checked and tab-completedsize, and one permission per subcommand.bettergopaint.propertiesand is rendered in the player's language.Architecture
Tooling
main. pr-lint/commitlint enforce Conventional Commits. PR builds run on Linux, Windows and macOS with Java 25. A Trivy gate runs before Hangar/Modrinth publishing, plus SBOM upload, a weekly security scan and the shared Renovate presets.docs/for GitBook (tutorial, how-tos, reference for brushes, commands, permissions, configuration and versions), plus new issue forms and CONTRIBUTING.md.Types of changes
Breaking: requires Paper 26.1.1+ and Java 25; servers on 1.21 stay on 1.1.x.
/gopaint reloadnow needsbettergopaint.command.admin.reload, which thebettergopaint.adminbundle grants. Each subcommand has its ownbettergopaint.command.*node, defaulting totrue.Checklist
Further comments
Verified:
./gradlew clean buildis green, with 40 tests and the Spotless license check.openspec validate --all --strictpasses. Onrun-26.2andrun-26.1.2the plugin enables without errors or config warnings,/gopaint,infoandreloadrespond,config.ymlis written with comments, and alang/folder containing only a German file loads.Not verified: painting with each brush in game, because the environment had no Minecraft client. Please run
./gradlew run-26.2, try every brush once and//undo.Manual steps for maintainers, also listed in the archived OpenSpec task lists:
mainup to date and make it the default branch; Release Please runs onmain.mainand requireBuild Pull Request Branch,Conventional PR titleandConventional commits.HANGAR_KEYandMODRINTH_KEYsecrets, and confirm the Dependency-Trackparent-uuidinrelease-please.yml, which was copied from AntiRedstoneClock.docs/.Commits follow Conventional Commits, so the first release through Release Please becomes 2.0.0.
🤖 Generated with Claude Code
https://claude.ai/code/session_01QLYZtULzHeMRpNygcFFWgp
Generated by Claude Code