Skip to content

Dirty Effect Hack

Quick Start: Spice it up with twists.

What the warning means

Potion effects in JManhunt are owned by one shared ledger: each modifier writes its own named entries through the pfx tags and the engine merges every entry onto the player's live effects (see Shared Effects). The engine remembers the merged winners it last applied per player.

When another modifier edits a ledger-managed effect directly (an effect command, another plugin, or a datapack) and the live effect comes out stronger than the ledger holds (higher amplifier, or longer remaining than the winner plus a small tolerance), the engine's next refresh logs this once per player per match:

Dirty Effect Hack detected for <name>: <effect> is stronger than
the ledger holds. Another modifier is editing effects directly;
switch it to the pfx tags:
https://jruk8.github.io/JManhunt/mods/dirty-effect-hack/

The engine then re-applies the merged winners, so the direct edit loses under vanilla merge rules whenever the ledger dose wins.

Missing effects never warn: milk, totems of removal, and rival clears are legitimate, and the next ledger mutation re-applies the merged view.

Why direct edits break

A modifier that fires a blind write only knows its own doses. Two such modifiers overwrite each other, and any pfx user recomputes from the ledger and silently wipes both. Through the ledger every modifier keeps its own entry and all of them merge per effect, with infinite entries always winning.

How to fix a flagged modifier

Replace the direct edit with ledger tags under one id per modifier (the modifier's own name, via <id>, is a good id):

# Before: clobbers every other effect change.
- <run:effect give <p> minecraft:blindness 30 0>

# After: merges with every other entry.
- <pfx.set:<p>,<id>,[[blindness,0,30]]>

Use pfx.get to read the modifier's own entry ([] when unset), pfx.duration to read the live seconds left for one effect under one id (-1 runs forever, null when absent), and pfx.clear to drop entries the modifier no longer needs. Modifiers that write infinite doses should clear their own id in an ON_CLEANUP block so the hold ends with the match even if the engine teardown is what finally strips it.