Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-module) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…fig) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…config)
Remove group/version, java toolchain block, and repos already declared in
root (mavenLocal, mavenCentral, paper, jitpack); drop redundant 'java' plugin
application and duplicate test { useJUnitPlatform() }; fix archiveFileName
to hardcode 'AbstractMenus-' prefix so the shadow artifact is not named
'plugin-<version>.jar'.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…changes) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…plugin jar Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds class-level overview, registration/impl/menu examples, threading notes, and per-method @implNote/@APinote guidance. Style template for future API documentation passes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Intermediate broken build state: references AbstractMenusApi which is added in the next commit. api module re-compiles cleanly after Task 3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…statics Build still fails pending AbstractMenusApi (next task). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…enusPlugin + Types accessors) Resolves the intermediate broken build state from MenuExtension + TypeRegistry commits. :api now compiles cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lugin bridge Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…via ServicesManager Old Types.*.init() registration path continues unchanged. The new api field is just sitting published; no caller yet. Cutover in the CoreExtension task. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ed yet) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…SPI) Removes MenuActions/MenuRules/ItemProps/Activators/Catalogs — content lives in their Core*Bundle counterparts, invoked through CoreExtension via the new AbstractMenusApi SPI. ItemProps.BINDINGS (a public constant co-located with the registrations) was inlined as "bindings" literal in CoreItemPropsBundle during the earlier migration; this commit also updates ActionPropertySet to use the literal directly, removing the last remaining external dependency on ItemProps. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers ~10 files under serializers/, data/, services/, placeholders/. Old Types class in :api module is now unused by plugin code; deletion in next task. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the "bindings" literal inlined during the CoreExtension cutover with a typed constant referenced from both the registration bundle and the single external consumer (actionClear). Keeps the registration and consumption sites in sync at compile time. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…istry Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Intermediate broken build state: plugin's AbstractMenusApiImpl doesn't implement providers() yet. Fixed in the next task. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tests) Tests will run once AbstractMenusApiImpl implements providers() in the next task. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves intermediate broken build state from the two prior commits. Also fixes two StubApi test doubles (CoreExtensionTest, AddonManagerIntegrationTest) that needed to implement the new providers() abstract method. All 237 tests (229 baseline + 8 new ProviderRegistryImplTest) pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…yet invoked) Mirrors AbstractMenus.registerProviders exactly — same guards, same handler constructors, same fallbacks. CoreExtension wires this in the next task. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Transitional dual-path: old Handlers.set* (in AbstractMenus.registerProviders) and new api.providers().register* (in this bundle) both run. Callers migrate in the next task, old path deleted in the task after. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…roviders().* Covers ~78 files across data/, services/, menu/, command/, extractors/, datatype/. Handlers.set* calls in AbstractMenus.registerProviders() remain for one more commit — removed in the next task. Test suites that relied on mutating the static Handlers facade (TestActionCommandBehavior, TestPropNameLorePrecompute, TestCompoundDataTypes, TestPrimitiveDataTypes) now route through a new ApiTestSupport helper that stubs Bukkit.getServicesManager() and installs their placeholder handler via the ProviderRegistry so production code paths (AbstractMenusApi.get()...) resolve correctly under unit tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
All provider registration now flows through ProviderRegistry — core providers via CoreProvidersBundle, external via addon MenuExtension.onEnable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…to-resolve New setConfigDefaults(Function<String,String>) hook lets the impl prefer a server-configured provider id per section. "auto" or null falls through to priority-based auto-resolution. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Defaults to "auto" for every section when absent from user config. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Server-configured provider defaults now take effect at runtime: config.conf
`providers { economy = "playerpoints" }` makes .economy() prefer PP even
when another provider has higher priority.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* takeMoney / giveMoney / hasMoney read optional `provider` string
* Serializer fails-at-load if provider id is not registered
* Runtime resolution: explicit provider via providers().economy(id),
else default via providers().economy() (respects config providers{})
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t-load Covers explicit provider selection, auto-fallback on omission, scalar-form backward compat, and fail-at-load on unknown provider id. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the style established by EconomyHandler — class-level overview, registration example, impl bridge example, menu usage, threading notes, per-method @param/@return/@implNote. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Stanislav Panchenko <brainrtp@yandex.ru>
Signed-off-by: Stanislav Panchenko <brainrtp@yandex.ru>
AddonManager: - loadOne(name): load a single addon by addon.conf name from disk, respecting pluginDependencies and addonDependencies. Used by both /am addons load <name> and the rescan path. - rescan(): scan addons/ and load anything not yet known. Existing addons are left untouched - use reload(name) to rebuild them. - availableNotLoaded(): names of addons present on disk but not yet loaded. Powers tab completion for /am addons load <TAB>. Cost is one jar open + HOCON parse per .jar; acceptable at typical scale. - enableSingle(): private helper extracted from loadAll, owns the pluginDeps + addonDeps + onLoad + onEnable sequence for one addon. CommandAddons: - new subcommands: load <name> and rescan - override tabComplete to suggest: - args[0]: list/reload/info/load/rescan filtered by prefix - args[1] for reload|info: loaded-addon names - args[1] for load: availableNotLoaded() names Command base: - now also implements TabCompleter - default tabComplete: subcommand-key matching at args[0], then recursive drill into the matched subcommand for args[1..] AbstractMenus#registerCommands: - wire setTabCompleter alongside setExecutor for /am, /var, /varp. /var and /varp inherit the default subcommand-key completion.
Brings in master commit 18a5627 (configurable click debounce floors + cooldown refactor) on top of api-merge work. Conflict resolutions: - AbstractMenus.java: kept api/addonManager fields from HEAD; master had no awareness of the new API surface. - MainConfig.java: kept providerDefaults map from HEAD AND added clickDebounceDefaultMs/ShiftMs from master. Both load() blocks merged. - menu/AbstractMenu.java: kept HEAD's Handlers->AbstractMenusApi migration; pulled in master's debounce floor feature (slotClickExpiry, SlotClickKey record, debounceFloorMs helper, click() with cooldown bookkeeping) plus AbstractMenus + MainConfig imports. - config.conf: kept providers{} block from HEAD AND added clickDebounce{} block from master.
Path 1 addons (plugin-as-addon style, e.g. PlayerPointsAddon on the as-plugin branch) declare `depend: [AbstractMenus, ...]` in their plugin.yml and Bukkit only enables them AFTER AbstractMenus' own onEnable returns. If AM loaded menus inline within onEnable, HOCON parse-time validation of provider:per-action references contributed by those addons would fail with 'Unknown economy provider X' even though the addon would register X seconds later. Move the initial loadMenus() call out of onEnable and into a ServerLoadEvent listener. The event fires after every plugin's onEnable has completed (both at server startup and on /reload), so by the time we parse menus all Path 1 contributions are present. Path 2 addons (jars in plugins/AbstractMenus/addons/) are unaffected - AddonManager.loadAll() still runs inline within AM's onEnable, before the listener is even registered. Listener self-unregisters after firing once so any future hypothetical re-fire of ServerLoadEvent does not double-load menus mid-session.
Default Gradle naming was producing 'plugin-<ver>.jar' for the regular
jar task because the subproject directory is named 'plugin'. That
name is misleading on disk - server admins encountering it have no
hint that it's part of AbstractMenus.
Set base.archivesName = 'AbstractMenus' on the :plugin module so both
the thin jar and the shadowJar share the canonical project name. Add
a 'thin' classifier on the regular jar task so it cannot be confused
with the user-facing fat jar:
plugin/build/libs/
AbstractMenus-2.0.0-alpha.jar <- shaded, ships to plugins/
AbstractMenus-2.0.0-alpha-thin.jar <- dev-only, no bundled deps
shadowJar gets archiveClassifier = '' explicitly to drop the default
'all' classifier the shadow plugin would otherwise add.
CI workflows (build.yml + release.yml) updated to skip the -thin jar
when picking the artifact to publish. Without the filter, ASCII sort
order would have selected -thin first ('-' = 0x2D < '.' = 0x2E).
Local file in api/build/libs/ was 'api-<ver>.jar' (default from
project.name = 'api'). On CI artifact downloads or manual SCP it
was hard to tell at a glance which project the jar belonged to.
Set base.archivesName = 'AbstractMenus-api' on :api so the local file
is now 'AbstractMenus-api-<ver>.jar', visually grouping with the
'AbstractMenus-<ver>.jar' shadow jar from :plugin.
The Maven publication is unaffected: maven-publish renames artifacts
to <artifactId>-<version>.jar inside the repository regardless of the
local jar filename, so the Maven coord 'ru.abstractmenus:api:<ver>'
still resolves correctly. Verified via :api:publishToMavenLocal:
~/.m2/repository/ru/abstractmenus/api/2.0.0-alpha/ still contains
api-2.0.0-alpha.{jar,pom,module} as expected.
CI workflows updated to grep AbstractMenus-api-*.jar.
Multi-module layout left release artifacts scattered across two paths:
plugin/build/libs/AbstractMenus-<ver>.jar (fat shadow)
api/build/libs/AbstractMenus-api-<ver>.jar (api binary)
api/build/libs/AbstractMenus-api-<ver>-sources.jar
api/build/libs/AbstractMenus-api-<ver>-javadoc.jar
For ops, manual SCP, and CI artifact uploads it's nicer to have all
four files in one directory. Add a 'dist' Copy task at root that
gathers them into <root>/build/dist/ via the per-task archiveFile
providers (so the Gradle file resolution stays lazy and incremental
caching keeps working).
./gradlew dist # explicit
./gradlew build # implicit (auto-finalizer on root build)
Per-module build/libs/ paths remain unchanged so existing CI grep
patterns and devs' muscle memory keep working - dist is purely
additive, not a replacement.
Root needs the 'base' plugin to have its own 'build' lifecycle task
(otherwise tasks.named('build') has nothing to attach to).
build/dist/ was only refreshed via './gradlew build'. Devs running the fast dev-loop command './gradlew :plugin:shadowJar' got the new jar in plugin/build/libs/ but had to remember to also run :dist (or build) before scp/cp. The two paths drifted. Hook dist as a finalizer on: - :plugin:shadowJar (dev-loop fast path) - assemble (all artifacts, no tests) - build (already; kept for clarity) dist is a Copy task with proper input/output declarations so finalizing it three times in a single invocation does no extra work; Gradle's incremental build skips when sources are up-to-date.
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.
The old
AbstractMenus/apirepo is now part of this one as the:apiGradle subproject. That repo will be archived shortly and no longer maintained. Going forward all API code lives here, alongside the plugin.What changed
:api. Maven coord stays the same:ru.abstractmenus:api:<ver>.plugins/) or as a lightweight jar AM loads itself (Path 2, drop intoplugins/AbstractMenus/addons/).ProviderRegistryfor economy / permissions / levels / placeholders / skins. Multiple providers can register at once; menus pick one withprovider: "..."per action, or via aproviders{}block inconfig.conf.Reference addon: PlayerPointsAddon (separate repo, two branches showing both paths).
Module layout
Build outputs in
build/dist/(aggregated) plus per-modulebuild/libs/.New API basics
AbstractMenusApi.get()- entry point, replacesTypes.*andHandlers.*statics.MenuExtension- the addon contract.onLoad/onEnable/onDisableplus name/version metadata.TypeRegistry<T>- five of these (actions, rules, activators, item properties, catalogs). ReplacesTypes.register*.ProviderRegistry- five sections (economy, permissions, levels, placeholders, skins). Replaces theHandlersstatic facade.All public types have proper javadoc.
Addon system
Two ways to ship an addon. Same runtime behaviour, different load-path.
as-plugin)as-addon)plugins/plugins/AbstractMenus/addons/plugin.ymladdon.conf(HOCON)AddonManager/plugins/am addons/am addonssupportslist,info <name>,reload <name>,load <name>,rescan. Tab completion works for all.Provider system
Old shape: one global handler per kind. New shape: many can register, menus choose.
Resolution order:
provider: "..."field in HOCON.config.confproviders{}block.Money actions accept both forms for backward compat:
config.conf:Core providers register at priority 50; addons typically at 100.
Build outputs
AbstractMenus-<ver>.jar- shadowed plugin jar, drop intoplugins/.AbstractMenus-api-<ver>.jar(+ sources + javadoc) - api artifacts.<root>/build/dist/- all of the above in one place../gradlew shadowJar,./gradlew assemble, and./gradlew buildall refresh it.Breaking changes
Removed:
ru.abstractmenus.api.Handlers-> useAbstractMenusApi.get().providers().*ru.abstractmenus.api.Types-> useAbstractMenusApi.get().{actions, rules, ...}()AbstractMenusPlugin-> useAbstractMenusApiAbstractMenusProvider-> useAbstractMenusApi.get()In-tree call sites are migrated. Out-of-tree consumers need import updates.
Migration
register*now takes an extraMenuExtension ownerparameter (thisif your plugin implementsMenuExtension).