OneLiteFeatherNET / OneLiteFeatherNET/AntiRedstoneClock-Remastered

feat: Non-destructive freezing of redstone clocks before escalation

Open
#317 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: needs triage type: feature
Dominant language
Java
Stars
36
Forks
13
Avg merge
1h 41m
Merged PRs (30d)
10

Description

Is your feature request related to a problem?

Detected redstone clocks are currently stopped right away by breaking the block (clock.autoBreak, optionally dropping it via clock.drop). That destroys builds even when a player built the circuit too fast by accident, or when a small change would make it compliant. There is no way to fix the circuit before blocks are lost.

Describe the solution you'd like.

Current state

Clock tracking works on single blocks, not on circuits:

  • Static mode: StaticTrackingService keys testers by exact Location.
  • Dynamic mode: DynamicTrackingService stores a per-block UUID in the block's PDC (CustomBlockData); neighbouring blocks get their own tester.
  • BukkitDecisionService acts on context.location() only.
  • When clock.maxCount is reached, the tester is removed and a new one starts at 0.

Consequences for this feature:

  • A clock made of several blocks produces several independent detections and notifications.
  • Freezing only the triggering block may leave the rest of the circuit running.
  • Strikes cannot be stored on the tester, because the tester is discarded on detection.

Proposal

1. Clock clusters (bounding box)

Group tracked blocks into a cluster:

  • A detected block joins an existing cluster if it lies within clock.freeze.clusterRadius of that cluster's bounding box. Otherwise it creates a new cluster.
  • The cluster holds its bounding box (world + min/max corner), freeze state and strike count. It lives independently of the per-block testers.
  • Works for both tracking modes. Testers keep counting per block, and the cluster aggregates them.
2. Tiered response
  1. Detect: A block in the cluster exceeds clock.maxCount (existing detection).
  2. Freeze: Redstone updates inside the cluster's bounding box are suppressed for a configurable duration. No blocks are removed.
  3. Notify: One notification per cluster, not per block, sent through the existing NotificationService chain (console, admins, discord, sign), including bounding box and remaining freeze time. Notifying the region owner (PlotSquared/WorldGuard) is new and optional.
  4. Rebuild window: The player can modify the circuit while it is frozen.
  5. Re-check: After the freeze expires, the cluster is released and evaluated again.
  6. Escalate: Only after maxStrikes does the existing action apply (REMOVE_AND_DROP / REMOVE_AND_WITHOUT_DROP).

Implementation hook: add a FREEZE value to RedstoneClockMiddleware.ResultState and handle it in DecisionService.

Describe alternatives you've considered.

Detection of a whole redstone machine would need a bounding box or use plotsquared / worldguard integration. But most of our users use plain paper server as freebuild / smp.

Other

Configuration (draft)

clock:
  endDelay: 300
  maxCount: 150
  autoBreak: true
  drop: true
  freeze:
    enabled: true
    durationSeconds: 15
    maxStrikes: 2          # freezes before escalating
    strikeResetSeconds: 300
    clusterRadius: 3       # blocks around the bounding box that still join the cluster
    notifyOwner: true

With clock.freeze.enabled: false, current behavior stays unchanged.

Technical notes

  • Suppress via BlockRedstoneEvent (set the new current back to the old value) and piston/observer/sculk/hopper handling for blocks inside a frozen bounding box. No block changes.
  • The frozen-area lookup runs on every redstone event, so it must be cheap (e.g. index clusters by chunk).
  • Schedule freeze expiry via SchedulerService/RegionService so Paper and Folia behave the same. A cluster spanning several Folia regions needs a defined handling, either rejection or per-region handling.
  • A reload or restart must not leave a cluster frozen forever: discard freeze state on shutdown, or persist it with an expiry time.
  • Clean up clusters once no member block has an active tester and no freeze or strike is pending.
  • /arcm display should list clusters with bounding box, remaining freeze time and strike count.

Acceptance criteria

  • Blocks of one circuit within clusterRadius are grouped into a single cluster in both static and dynamic mode.
  • A detected cluster is frozen on its first violation; no block is removed.
  • Exactly one notification is sent per freeze, with bounding box and freeze duration.
  • After expiry the circuit runs again; if it was rebuilt to be compliant, nothing else happens.
  • After maxStrikes violations within strikeResetSeconds, the existing removal logic applies.
  • Strikes survive the removal of the per-block tester.
  • clock.freeze.enabled: false reproduces the previous behavior.
  • Works on Paper and Folia.

Open questions

  • Does rebuilding during a freeze (block place/break inside the bounding box) reset strikes, or only the timeout?
  • Should escalation remove only the triggering block (current behavior) or all tracked blocks in the cluster?
  • Is there a maximum cluster size, to keep one bounding box from swallowing a whole farm area?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing detection and decisions through StaticTrackingService, DynamicTrackingService, BukkitDecisionService, RedstoneClockMiddleware.ResultState, and DecisionService. Then inspect NotificationService plus BlockRedstoneEvent and SchedulerService/RegionService handling, including the /arcm display entry point. Done means the listed acceptance criteria pass in static and dynamic modes on Paper and Folia, while the open questions are resolved.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
game-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.