OneLiteFeatherNET / OneLiteFeatherNET/AntiRedstoneClock-Remastered
feat: Non-destructive freezing of redstone clocks before escalation
Nobody has claimed this yet.
- 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:
StaticTrackingServicekeys testers by exactLocation. - Dynamic mode:
DynamicTrackingServicestores a per-block UUID in the block's PDC (CustomBlockData); neighbouring blocks get their own tester. BukkitDecisionServiceacts oncontext.location()only.- When
clock.maxCountis 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.clusterRadiusof 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
- Detect: A block in the cluster exceeds
clock.maxCount(existing detection). - Freeze: Redstone updates inside the cluster's bounding box are suppressed for a configurable duration. No blocks are removed.
- Notify: One notification per cluster, not per block, sent through the existing
NotificationServicechain (console, admins, discord, sign), including bounding box and remaining freeze time. Notifying the region owner (PlotSquared/WorldGuard) is new and optional. - Rebuild window: The player can modify the circuit while it is frozen.
- Re-check: After the freeze expires, the cluster is released and evaluated again.
- Escalate: Only after
maxStrikesdoes 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/RegionServiceso 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 displayshould list clusters with bounding box, remaining freeze time and strike count.
Acceptance criteria
- Blocks of one circuit within
clusterRadiusare grouped into a single cluster in bothstaticanddynamicmode. - 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
maxStrikesviolations withinstrikeResetSeconds, the existing removal logic applies. - Strikes survive the removal of the per-block tester.
-
clock.freeze.enabled: falsereproduces 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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