Skip to content

Add opt-in automation effects, usage charges and durable perk management - #76

Draft
BenCodez wants to merge 15 commits into
masterfrom
codex/selected-effects-and-lifecycle
Draft

BenCodez wants to merge 15 commits into
masterfrom
codex/selected-effects-and-lifecycle

Conversation

@BenCodez

@BenCodez BenCodez commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Adds four independently configurable interaction effects, durable personal usage charges, queue management, banked personal time, diagnostics and local statistics. Existing timed perks retain their defaults when the optional settings are absent.

Behavior

  • AutoBlockRefill: refills a depleted placement hand from matching inventory items, preserving metadata and revalidating the hand/slot. Cancelled placements and no-op refills cost nothing.
  • VeinMining: bounded connected ore traversal without loading chunks, native break/protection/tool/drop handling and recursion prevention. Additional successful blocks are the usage unit; the available budget bounds the batch before breaking.
  • RightClickHarvest: main-hand mature crop harvesting, native cancellation/protection checks, one reserved inventory seed and replanting. Reuses AutoPlant requirements and avoids duplicate harvesting.
  • PrecisionMode: owner-selected MCPerks effects are suppressed while sneaking; suppression spends no charges.
  • Personal UUID/effect charge balances are distinct from activation allowances and elapsed duration. Confirm durable reservations before gameplay, release proved-unused units, and retain uncertain units as spent. Shared charged audiences are rejected; unlimited shared perks remain supported.
  • Queue entries retain stable IDs, ordered upcoming entries, requester and meaningful ETA/unknown state. Waiting entries reserve entitlement; starts consume it once behind durable fences. Cancel own waiting entries; staff may pause, remove or reorder. Uncertain starts never automatically replay or refund.
  • Opt-in personal banked time consumes only online eligible elapsed time and supports pause/resume without replaying activation hooks. Legacy absolute expiration remains separate. Persistent/one-shot/periodic effects that cannot safely pause are rejected for banked mode.
  • Diagnose uses actual execution decisions, current definition for new activation advice and retained grant options for running effects. After reload, changed world and activation-limit policy is reflected correctly. Inspection never debits balances.
  • Optional bounded local aggregate activations, queue wait and known skip reasons; successful-operation totals share the charge outcome ledger. Advisory counters reset on restart and use no external analytics service.

Commands and opt-in configuration

# In a perk definition; existing perks do not gain these effects automatically.
Effects: [VeinMining, PrecisionMode]
VeinMining:
  MaxBlocks: 16
  MaxDistance: 8
  Materials: [COAL_ORE, IRON_ORE, DIAMOND_ORE]
PrecisionMode:
  TargetEffects: [VeinMining, RightClickHarvest, AutoBlockRefill]
UsageCharges:
  Enabled: false
BankedTime:
  Enabled: false

Existing PerkQue remains authoritative. Optional LocalStatistics.Enabled is in Config.yml. README documents limits, units, permissions, seed policy and complete examples.

/mcperks SetUsageCharges <player> <effect> <amount>
/mcperks AddUsageCharges <player> <effect> <amount>
/mcperks GetUsageCharges <effect>
/mcperks Queue
/mcperks CancelQueue <entry-id>
/mcperks QueuePause <true|false>
/mcperks QueueRemove <entry-id>
/mcperks QueueMove <entry-id> <position>
/mcperks GetBankedTime <perk>
/mcperks PauseBankedTime <perk>
/mcperks ResumeBankedTime <perk>
/mcperks SetBankedTime <player> <perk> <seconds>
/mcperks Diagnose [player]
/mcperks LocalStatistics

Dependency and compatibility

Requires AdvancedCore PR #360, including the additive shutdown hooks, final-file completion contract and ServerData.mutateFinalData ownership API. The dependency version is 3.8.2-SNAPSHOT; its version string alone is not an immutable artifact identity. AdvancedCore is shaded into MCPerks, so server owners do not install a separate AdvancedCore plugin.

Java 21 minimum is unchanged. MCPerks does not declare Folia support; conditional scheduler paths do not establish full platform support. Existing data and configuration remain readable, with no implicit conversion of legacy duration into banked time or automatic charge refill. Gameplay, storage and arbitrary external commands are not one universal atomic transaction; uncertain side effects remain conservative as documented.

Current native storage follow-up

Exact source commit: 15c87bfe58e97f4ea177be6470cd446412ca1490.

The ordered MCPerks file owner remains available until both shutdown preparation and AdvancedCore's actual final-file publication settle. Final mutations record explicit write intent, preserve independently changed YAML siblings, normalize equivalent parsed numeric values, and publish through the existing ordered worker. Capacity rejection and asynchronous failure do not acknowledge unpublished state. Native reload/bulk mutation respects the inherited publication monitor; custom file ownership remains asynchronous.

Current candidate clean package passed all 348 tests, zero failures/errors/skips, against the exact locally built AdvancedCore candidate from PR #360, commit fd53fd37a6e4de22a99a6fef0aa7b61d5fa58d1b and JAR SHA-256 8a357bf4c2265cbfb26eaf6734069151d25f43e16f1c222766c8ec7fd647c880.

MCPerks JAR SHA-256: 10b2929720b6897110604faafd61f9cf7cbab9253d5600ba77611af9303622dd (9197654 bytes). ZIP integrity, relocated native ownership classes, Java 21 base classes and absence of bundled JUnit/Mockito checked. The unchanged MCPerks native-dependency source retains its scoped independent Sol 6.1 review. A fresh Sol 6.1 Extra High review of the producer legacy-owner compatibility delta also reported No findings, including the current MCPerks adapter dispatch. The exact consumer was rebuilt after the producer change; this is not a new whole-feature review.

PR #76 remains draft. The published snapshot previously probed lacked the required APIs. Local exact-artifact success does not prove remote dependency availability. A compatible producer must be published and this consumer rebuilt against that exact remote artifact before its hosted compatibility and readiness gates can pass. Current-head hosted checks are pending.

Earlier native protocol tests belong to source 0273ec0e7710b2caa3cda462abf7cfc4cf1b39d1 and JAR SHA-256 611a6587d688ed6fa43201157715db40d696106bd86f71ec4706ea15054f4a0b, not this update. Those covered interactions, online/offline bank time, queue ownership, restart and start/cancel timing cases through automation; they were not visual gameplay verification. No current-JAR live Paper, Folia, database or graphical acceptance is claimed. MCPerks does not declare Folia support. No merge, release or deployment is performed.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 534fe35b-4f4f-4a21-a6a1-dc504b24c836
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T18:35:38.582318Z 37c912b New commits
🔒 Security Review ✅ Completed 2026-10-10T00:20:22.298573Z c2d0d2b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c2d0d2b3c8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +520 to +521
private boolean precisionSuppresses(Effect effect, String uuid, String world) {
if (uuid == null || !precisionSneaking.containsKey(UUID.fromString(uuid)) || effect == Effect.PrecisionMode) return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Seed precision state for already-sneaking players

When the plugin is enabled or fully reloaded while a player is already sneaking, precisionSneaking starts empty and is populated only by a later toggle event or one of the three new automation listeners. Consequently, configured targets such as NoFallDamage, Fortune, or McmmoXP remain active until the player toggles sneak, even though PrecisionMode should suppress them immediately. Initialize this cache from online players during startup/reload, or consult the current player state when evaluating precision.

AGENTS.md reference: AGENTS.md:L29-L33

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07d44dc9df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +533 to +536
var definition = getPerkHandler().getPerk(perk);
if (definition == null || !definition.isEnabled()) {
getLogger().warning("Skipping shutdown record for unavailable perk: " + perk);
continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve skipped shutdown records for later restoration

When a perk definition is temporarily disabled, missing, or fails to load during startup, this branch skips its shutdown record, but restoreOfflinePerks() subsequently clears the entire OfflinePerk section. Re-enabling or repairing that perk later can therefore no longer restore the remaining purchased time; retain unavailable entries and clear only records that were successfully restored.

AGENTS.md reference: AGENTS.md:L29-L30

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c58888c0d9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +444 to +447
return plugin.getMcperksServerData().confirmedActivation(() -> {
recordCooldown(user);
activatePerk(user, length);
}).thenCompose(ignored -> com.bencodez.mcperks.userapi.UserStorageConfirmation.confirm(plugin, user));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Persist activation state before executing perk effects

confirmedActivation runs recordCooldown and activatePerk—including command and reward hooks—before persistSnapshot is even submitted. If snapshot serialization rejects an oversized ServerData file, an I/O error occurs, or the server crashes in this interval, the irreversible rewards have already been granted while the cooldown/expiration may remain unconfirmed, allowing the activation to be retried after restart. Stage and durably publish the required state before invoking activation gameplay.

AGENTS.md reference: AGENTS.md:L35-L35

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b769075a14

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +536 to +538
getPerkHandler().activePerk(definition,
getMcperksUserManager().getMCPerksUser(UUID.fromString(uuid)),
(int) timeLast, timestamp);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore timers without replaying activation hooks

For an unexpired finite perk saved during shutdown, this now invokes the full activePerk activation path, which calls EffectHandler.activate; Rewards, Commands, and GlobalCommands therefore run again on every plugin reload where affected players are online (and global commands run regardless). Restore the active timer/effects through a restoration-specific path that does not replay one-shot activation hooks.

AGENTS.md reference: AGENTS.md:L29-L29

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf1ebc8702

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +911 to +914
if (user.getActivations(getPerk()) - plugin.getFeatureState().reserved(owner, "PerkActivations_" + getPerk()) > 0) {
globalActivation = false; user.addActivation(getPerk(), -1);
} else if (user.getActivations() - plugin.getFeatureState().reserved(owner, "Activations") > 0) {
user.addActivation(-1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Acquire the direct-start fence before debiting credits

When PerkQue is disabled and a player with at least two activation credits submits the same perk twice before the first asynchronous activation finishes, both calls decrement a credit here, but the second call is subsequently rejected by activationAdmissions in executeConfirmed. That failed call never refunds or durably associates its debit with gameplay, so rapid retries silently discard a purchased activation; establish the per-player/perk admission before changing either activation balance.

AGENTS.md reference: AGENTS.md:L29-L29

Useful? React with 👍 / 👎.

Comment on lines +570 to +572
private void reloadAfterDrain() {
if (usageEffects != null) usageEffects.invalidate();
if (queuePlanner != null) queuePlanner.invalidate();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retire pending direct activations during reload

If a direct activation has published its shared snapshot but is still waiting for UserStorageConfirmation when a reload reaches this method, the reload barrier does not cover that later user-cache flush. This method invalidates queue and automation work but neither advances featureLifecycle nor replaces the PerkHandler, so verifyAdmission still succeeds and the pre-reload Perk can run its effects, rewards, or commands after definitions have been reloaded—even if that perk was disabled or changed.

AGENTS.md reference: AGENTS.md:L33-L33

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 13e4d21e8f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +915 to +916
if (getInteractionOptions().banked() && plugin.getConfigFile().getLimitActivations()) {
plugin.getPerkHandler().addQue(user, this); return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep queue-disabled banked activations parallel

When BankedTime.Enabled and LimitActivations are enabled but PerkQue is disabled, this unconditional branch still places every bank grant into QueuePlanner; its check() refuses to start while any perk is active. Consequently an unrelated long-lived or permanent perk can block the bank grant indefinitely, and different players' personal banks are serialized despite the queue being disabled. Route the activation through durable atomic debit without imposing queue scheduling when PerkQue is false.

AGENTS.md reference: AGENTS.md:L89-L89

Useful? React with 👍 / 👎.

Comment on lines +937 to +940
if (user.getActivations(getPerk()) - plugin.getFeatureState().reserved(owner, "PerkActivations_" + getPerk()) > 0) {
user.addActivation(getPerk(), -1);
} else if (user.getActivations() - plugin.getFeatureState().reserved(owner, "Activations") > 0) {
user.addActivation(-1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Move direct credit debit into confirmed admission

With limited non-banked activations that start directly, the cached credit is decremented here before executeAdmitted performs its fallible ServerData publication and user-storage confirmation, and no failure path restores it. The newly added admission fence prevents the previously reported concurrent debit, but if snapshot capacity, publication, owner scheduling, or confirmation fails before gameplay, the player is left with a reduced activation balance and no perk; establish durable ownership before changing the credit, or restore it only for failures proven to precede gameplay.

AGENTS.md reference: AGENTS.md:L29-L29

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6d097a02dd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +503 to +504
if (banked && !alreadyConsumed) return plugin.getBankedPerks().grantConfirmed(user, this, length)
.thenCompose(ignored -> confirmCooldown(user));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Publish the bank cooldown before adding entitlement

For a banked perk with LimitActivations disabled, this publishes the additive bank grant first and only then calls confirmCooldown. If the server crashes or cooldown persistence fails between those operations, the durable bank time remains while the old cooldown remains eligible, so retrying the activation adds the same entitlement again for free. Persist the cooldown/admission before the bank addition, or retain a durable uncertainty fence that prevents retries.

AGENTS.md reference: AGENTS.md:L35-L35

Useful? React with 👍 / 👎.

Comment on lines +952 to +953
if (getInteractionOptions().banked() && plugin.getConfigFile().getLimitActivations() && plugin.getConfigFile().getPerkQue()) {
plugin.getPerkHandler().addQue(user, this); return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep idle limited bank starts out of WAITING

When BankedTime, LimitActivations, and PerkQue are enabled, this branch unconditionally creates a WAITING entry even when there is no active perk, paused queue, or predecessor. An otherwise direct purchase can therefore remain queued if the player disconnects before prepare runs, rather than using the durable STARTING direct-start path; only enqueue it when the ordinary queue conditions actually require waiting.

AGENTS.md reference: AGENTS.md:L91-L91

Useful? React with 👍 / 👎.

Comment on lines +556 to +557
var barrier = featureState == null ? java.util.concurrent.CompletableFuture.completedFuture(null) : featureState.runtimeStorage(() -> null);
barrier.whenComplete((ignored, error) -> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wait to report asynchronous reload success

Reload now returns as soon as this asynchronous barrier is registered, but the inspected CommandLoader still sends its “reloaded” success message immediately after calling plugin.reload(). Even a normal reload has not happened when that message is shown, and if this barrier fails the reload is explicitly postponed while the administrator has already been told it succeeded; expose completion or move the success response into the successful callback.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37c912baa6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +55 to +56
if (!runActivationHooks && (effect == Effect.Rewards || effect == Effect.Commands
|| effect == Effect.GlobalCommands)) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude all one-shot effects during restoration

When an unexpired shutdown record contains CureHunger, CureSpells, or HealAll, restoreActivePerk passes false here, but this filter skips only rewards and commands, so effect.runEffect heals or cures players again on every restart/reload. Fresh evidence after the earlier restoration fix is that these remaining one-shot enum cases are still executed; they should be excluded from the restoration path alongside the other activation-only effects.

AGENTS.md reference: AGENTS.md:L29-L30

Useful? React with 👍 / 👎.

Comment on lines +254 to +255
ticking.remove(owner); sessions.remove(owner); for (BankKey key : List.copyOf(clocks.keySet())) if (key.owner().equals(owner)) suspend(key);
clocks.keySet().removeIf(key -> key.owner().equals(owner));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retain failed final bank debit reservations

When a disconnect, world transition, or failed pulse submits its final elapsed debit while the bounded feature-worker queue is full (or publication fails before changing the file), suspend leaves that elapsed interval reserved only inside the clock, but this line immediately deletes the clock without observing the checkpoint future. A later reconnect creates a fresh clock against the unchanged persisted balance, so the already-used interval becomes usable again; retain/retry the reservation or keep the bank unavailable until that final debit is resolved.

AGENTS.md reference: AGENTS.md:L47-L50

Useful? React with 👍 / 👎.

@BenCodez
BenCodez marked this pull request as draft October 10, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant