Iustitia

Iustitia # Iustitia A purely client-sided anticheat for Minecraft Java **1.21.11** (Fabric). Detects **both 1.8-era and 1.21.11-era cheats** by passively observing *other* players through the packets the server already rebroadcasts to you — no server component, no network transmission, no outgoing packets. **Local-only alerts and overlays. No bans. No interference. No outgoing packets.**

What’s new in 1.2.0

Detection pipeline, IustitiaConfig.CONFIG_VERSION, and ClipCodec.VERSION are unchanged from v1.1.0 — settings and .iusclip files carry straight over.


What it is

Iustitia is a Fabric client mod that watches every other player on your server and flags impossible world/combat interactions — the kind of thing a reach hack, a killaura, a fly hack, or a timer cheat produces. It does this entirely on your client:

It is a detection/inspection tool, not an enforcement tool: it tells you who looks like a cheater. It does not kick, ban, or report anyone, and it sends nothing anywhere.

Requirements

Dependency Version
Minecraft 1.21.11
Fabric Loader 0.19.3+
Fabric API 0.141.3+1.21.11 (any compatible)
fabric-language-kotlin 1.13.9+kotlin.2.3.10 (any compatible)
Yet Another Config Lib (YACL) 3.8.2+1.21.11 (any compatible)
Java 21
Recommended: ViaFabricPlus for playing on 1.8-era servers via protocol translation

All three library mods (Fabric API, fabric-language-kotlin, YACL) are standard and can be installed alongside any other modpack. Iustitia is written to fail-open and not crash when other mods are present.

Installation

  1. Install Fabric Loader 0.19.3+ for Minecraft 1.21.11.
  2. Drop Fabric API, fabric-language-kotlin, and YACL into your mods/ folder.
  3. Drop iustitia-1.2.0.jar into your mods/ folder.
  4. (To detect cheats on 1.8-era servers) Install ViaFabricPlus so your 1.21.11 client can join them.
  5. Launch. A one-time first-launch wizard asks how you use Iustitia (General / Moderation / Ranked Player) and pre-sets sensible defaults. Join any server with other players.

That’s it. Alerts appear in chat; other players get a colored tier prefix on their nametag (where the server allows it — see Nametag prefixes).

Quick start

/ius                 # list checks + enabled state (alias of /iustitia)
/ius status          # health panel: master, tracked players, protocol, alerts
/ius help            # in-game command help
/ius help reach      # describe a check + its live config (or /ius help spectate, transcript, …)
/ius hist            # session top offenders (searchable screen)
/ius hist <name>     # a player's profile card + recent flags
/ius spectate <name> # watch follow-cam on a player (or your crosshair target; /ius spectate off to stop)
/ius transcript <name>  # copyable session timeline (or /ius transcript panel <name> for the side panel)
/ius evidence <name>    # one-line summary of their last few seconds of flags
/ius note <name> <cat> <text…>  # tag a player (closet/blatant/needsReview/legit); /ius note <name> to read
/ius session         # session summary: tracked players, tier counts, who peaked highest
/ius report <name>   # full report card → clipboard (markdown, json, or text)
/ius snapshot [name] # one-line evidence snapshot of your crosshair target → clipboard
/ius replay <name> <sec> [1|0.5|0.25]  # rewind the last N seconds in-world as ghost models (1× by default; 0.5/0.25 = slow-mo)
/ius replay pause|resume|seek <s>|step +|-|speed 1|0.5|0.25|cam free|follow|pov|freecam|off  # playback controls while a replay runs
/ius clip <sec> [name]  # export the last N seconds of positions + alerts (+ the loaded chunk world) to a portable .iusclip file
/ius playclip [name] [1|0.5|0.25]  # play a saved clip back in-world as a solid textured world + ghosts, relocated to you (/ius playclip off to stop; bare = list clips)
/ius deleteclip <name>  # delete a saved .iusclip by name (alias /ius delclip <name>)
/ius clips           # open the clip manager screen (list / play / delete saved .iusclip files)
/ius preset <name>   # apply a named config preset (built-ins: strict/standard/lenient/debug/moderation; or a custom preset)
/ius createpreset <name>  # save the current config as a custom preset (persists to .iustitia/presets/<name>.json)
/ius deletepreset <name>  # delete a custom preset (built-ins can't be deleted)
/ius presets         # list all presets (built-in + custom)
/ius sonar [on|off]   # directional audio alerts — pan = direction, pitch = distance (additive to chat)
/ius clear <name|all> # reset one player's flags (tier→green) or everyone's (exemptions untouched)
/ius exempt [name [on|off]]  # exempt a player from all checks (bare = list exempted); persists across sessions
/ius alerts          # mute/unmute all chat alerts (detection keeps running)
/ius keybinds        # open the keybind hub screen
/ius config          # open the YACL config screen

There are also twelve keybinds (snapshot, transcript, session, keybinds, config, note, compact, watch, plus four numpad replay controls: pause/resume, seek +5s, seek −5s, exit) — configurable in vanilla Controls → Miscellaneous, and listed with conflict-detection in the keybind hub (/ius keybinds).

See USERMANUAL.md for a non-developer walkthrough.

Architecture

                 ┌─────────────────────────────┐
   server packets │  ClientPlayNetworkHandler   │  (read-only mixin — no send path)
   ──────────────►│  Mixin → PacketSignals       │
                  └──────────────┬──────────────┘
                                 │  swing / hurt / position / metadata
                                 ▼
                      ┌──────────────────────┐
                      │   EntityTrackerManager │  server-space model of every other player
                      │   + ProtocolDetector    │  (1.8-era vs modern combat timing)
                      └──────────┬───────────┘
                                 │  TrackedPlayer (pos, yaw/pitch, deltas, sprint, hurtTick…)
                                 ▼
                      ┌──────────────────────┐   per tick:  ClientTickEvents.END_CLIENT_TICK
                      │   36 Checks (combat +  │   ──► Check.process() / onAttack() / onSwing()
                      │   movement/rotation/   │   ──► vl += level ; decay each clean tick
                      │   packet)              │
                      └──────────┬───────────┘
                                 │  flag() when vl > setbackVL
                                 ▼
                      ┌──────────────────────┐
                      │  AlertManager +       │  ──► chat alert (throttled, join-grace)
                      │  FlagHistory + CheckInfo│ ──► /ius hist, status, nametag tier
                      └──────────────────────┘

                 ┌─────────────────────────────┐
   render thread  │  PlayerEntityRendererMixin  │  nametag tier prefix + burst pulse
                  │  ArmorStandEntityRendererMx │  nametag fallback for armor-stand holograms
                  │  PlayerListHudMixin          │  tab-list tier badge
                  │  CameraMixin                │  offender-selfie + watch follow-cam (auto-reverting)
                  │  EntityRendererMixin         │  hides live players during an instant replay
                  └─────────────────────────────┘  (all render-only, no visibility hack, no send path)

Mixin set (the only bytecode touched)

No @Redirect or @Overwrite is used anywhere. No send-path mixins. No local-player mutation (the watch follow-cam overrides the camera only, and is the sole deliberate exception — see above).

Protocol awareness

ProtocolDetector distinguishes 1.8-era combat (via ViaFabricPlus) from modern 1.21.11 combat and adjusts the hurt-confirmation lookback (3 ticks on 1.8 vs 2 on modern), so attack-inference timing is correct on both. Checks that depend on server ticking (timer/blinker, teleport) carry a server-lag exemption so a lagging server doesn’t manufacture false positives.

The 36 checks

Each check has its own config slice (enabled, setbackVL, decay, threshold) editable live via /ius or YACL. Checks marked definitive can prove cheating and drive the red nametag tier; the rest are inferential and drive yellow.

Combat (16)

id detects definitive
reach Hit a victim beyond vanilla melee reach (lag-compensated).
multiTarget Struck ≥2 distinct victims in one tick (multi-aura).
clickStatistics Click cadence too uniform / too fast (autoclicker).  
throughWalls Attacked a victim with no line-of-sight to the torso.
criticals Spoofed a grounded crit hop to crit while on the ground.
maceSmash Warped Y around an attack to inflate mace smash fall-damage (MaceKill).
noKnockback Took a hit without the expected knockback (anti-KB).  
keepSprint Kept sprinting through an attack instead of the legit slowdown.  
wTap Reset sprint KB pattern mismatch (W-Tap / SuperKB cheat).  
jumpOnHurt Jumped instantly on taking damage (anti-KB hop).  
backtrack Hit a victim from a stale (backtracked) position.  
hitsWithoutSwing Dealt melee damage with no swing animation (no-swing / hit-select).  
killAura Silent-aim / aim-snap suite (ten sub-components, one VL pool).  
autoBlock Swung while a shield was raised (auto-block / block-hit).
hitFlick Redirected aim off the hitbox at the attack tick (HitFlick).
triggerbot Auto-attacked the instant the crosshair reached a hitbox (sub-reaction).  

killAura is a port of Rain-Anticheat’s 1.8.9 silent-aim suite (corroborator-tier — ten sub-components, one VL pool); hitFlick is a Vape/Slinky-style knockback-redirect detector; triggerbot is a lax, blatant-only rising-edge reaction-timing detector (deliberately not definitive — yellow tier — pending live validation). maceSmash catches the 1.21 mace fall-damage fake; hitsWithoutSwing is a weak no-swing corroborator that never initiates a tier alone.

Movement / rotation / packet (20)

id detects definitive
speedEnvelope Moved horizontally faster than the vanilla speed envelope.  
flyEnvelope Vertical motion broke vanilla physics (fly / hover / ascend).
spider Climbed a solid wall with no ladder/vine/scaffold (wall-climb).
noFallDamage Spoofed on-ground to avoid fall damage.  
stepHeight Stepped up a block higher than the vanilla step height.  
teleport Position jumped in a way that isn’t a vanilla teleport/pearl.
longJump Covered too much horizontal distance in one air tick.
noSlow Moved at full speed while using an item that should slow you.  
backwardSprint Sprinted backward (OmniSprint) — blatant-only, KB-exempt.  
wallSprint Held sprint metadata while pressed against a wall (OmniSprint wall-sprint).
sprintHack Sprint metadata set where vanilla cancels it — in water, while sneaking, or while Blind.
waterWalk Walked on water (Jesus / water-walk).
elytraSpeed Elytra glide exceeded the vanilla speed cap.  
rotationTracking Aim rotated too uniformly while tracking a target.  
rotationSnapBack Aim snapped back after an attack (aim-snap).  
phaseClip Moved through a solid block (phase / no-clip).
packetGap Packet timing gap inconsistent with vanilla ticking (timer/blinker).  
aimWrap Aim rotated faster than a legit flick (>threshold°/tick).  
pitchBound Pitch outside the vanilla [-90, 90] bound.  
scaffoldRotation Scaffold placement rotation inconsistent with legit bridging.

Alerts

The fixed alert layout:

§8[§diustitia§8] §f(Name) §<sev>(Check) §<sev>(VL)

Severity color scales with the violation ratio vl / setbackVL: <2× yellow (§e), <3× orange (§6), ≥3× red (§c). The trailing number is the violation count (ceiling of VL).

The line is self-documenting and interactive (both are local chat-component events — no packet is sent):

Alerts are throttled per (player, check) and suppressed during a join-grace window (default 30s) so a player who just rendered in doesn’t burst-fire.

Nametag prefixes

Other players get a tier prefix drawn on their nametag (vanilla visibility is respected — no wallhack; the prefix only appears when vanilla would show the nametag):

prefix tier meaning
§a[+]§r green no chat alerts this session (clean / low-flag)
§e[!]§r yellow ≥1 primary red-capable alert has fired (suspect)
§c[X]§r red ≥2 distinct red-capable checks have proven cheating (sticky for the session, decays one tier per ~10 min idle)

When nametag burst pulse is on (default), the prefix briefly pulses white/tier-color for ~3 s after a fresh yellow/red alert. Display-only (no check logic changed). The numeric confidence score behind a tier is available in /ius hist, /ius session, the snapshot, and the crosshair confidence HUD — not on the nametag itself.

The prefix is written at the HEAD of PlayerEntityRenderer.renderLabelIfPresent (the draw method), so it survives label batching, and is mirrored into the Tab list by PlayerListHudMixin.

Server coverage caveat: the prefix only appears on servers that populate the vanilla nametag field (displayName). This works on most servers, including minemen.club and 1.8-era servers. Some servers suppress the vanilla nametag and render their own server-side name hologram instead — on those, Iustitia has no displayName to attach to and the prefix will not appear. This is by design (the alternative would be a wallhack-style visibility hack, which Iustitia refuses to do). Confirmed-affected: stray.gg and mcpvp.club (the latter shows a black-background label that is actually the server’s BELOW_NAME health indicator, not the vanilla name).

Observer tooling & render overlays

v1.1.0 adds a control surface and a visual layer that turn raw detections into a moderation workflow — all still read-only and client-sided.

Evidence commands

Keybinds

Twelve configurable binds registered in vanilla Controls → Miscellaneous: snapshot, transcript, session, keybinds, config, note, compact, watch (default F9), plus four numpad replay controlsreplayPause (numpad 5), replaySeekFwd (numpad +, +5s, works while playing), replaySeekBack (numpad −, −5s), and replayExit (numpad 0). /ius keybinds opens a hub screen that lists them all and highlights any that conflict with another bind in red.

Watch follow-cam

/ius spectate [name] (or the watch keybind, default F9) starts a sustained follow-cam on a player: it forces F1, shows a third-party view of the target (all entities — including yourself — still rendered), and lets you orbit with the mouse (the target stays centered). It auto-stops when you move >0.5 blocks, get hit, or the target leaves render range; /ius spectate off (or the bind again) stops it manually. The camera auto-reverts to your view the instant it stops (vanilla re-derives it each frame, so it can never get stuck).

Instant replay, sonar & evidence clips

A moderator-style “instant replay” of the scene, an eyes-free directional audio alert, and a portable evidence-clip format — all client-side, all render/sound-only (no detection logic touched):

Player management

All four instant-replay tools have toggles in /ius config (Replay capture buffer / Replay hides live players / Replay player models / Relocate scene to me / Clip captures full world / Chunk capture radius / Clip chunk render distance / Sonar alerts / Sonar volume). /ius replay plays ghosts at their exact recorded world coordinates (it’s instant, same-server/same-dimension — no anchoring, v1.1.0 behavior); /ius playclip relocates the scene to you (the focus player starts at your spot), gated by Relocate scene to me. /ius replay never carries the map (same-server, same-map use); only /ius clip captures it and only /ius playclip renders it. Note the chunk-world capture is loaded-chunks-at-save only (the client only has chunks in render distance, and only the ones still loaded when you run /ius clip) and is radius-bounded to keep the file size down — a larger radius means a bigger file. The Clip chunk render distance slider (default 6, range 4..12) bounds how far the clip’s solid world draws around the camera each frame — a lower value trades visible distance for FPS (the per-chunk block draw is the main playclip cost), a higher value shows more of the captured world at once. The chunk world also bakes lazily: only in-range chunks are built, nearest-first a few per frame, so the world streams in from the camera outward instead of loading in one spike — far-from-focus chunks are never built unless you fly toward them.

World/HUD overlays (all render-only, depth-tested — no wallhack)

Each overlay has its own toggle in /ius config and is off-able independently.

Configuration

Each check’s threshold is check-specific (Reach→max reach, MultiTarget→min victims, ClickStatistics→CPS cap, SpeedEnvelope→bps cap, Triggerbot→min fast-hits, etc.). /ius help <check> prints the live config + description for any check.

Building from source

git clone https://github.com/ThoriaDevelopment/Iustitia.git
cd Iustitia
./gradlew build

The built mod jar is at build/libs/iustitia-<version>.jar. A sources jar is also produced. Requires JDK 21 and internet access on first build (Loom downloads Minecraft + mappings).

./gradlew runClient   # launch a dev client with Iustitia loaded

Privacy

Iustitia is purely client-sided. It reads incoming server packets that your client already receives, runs detection locally, and writes to your local chat and your local config file. It does not transmit, upload, or report anything to any server, endpoint, or third party. There is no telemetry, no analytics, no network code beyond reading what the server sends you.

By default, muting, tiering, flag history, moderator notes, and evidence data are all in-memory and cleared on restart (or /ius reset). The optional Persist across sessions toggle (persistenceEnabled) writes moderator notes, tier/flag history, evidence snapshots, transcript/evidence exports, and the player exemption list to %APPDATA%/.iustitia on your own machine so they survive a restart — still local, still never uploaded. Evidence clips (.iustitia/clips) and the exemption list (exemptions.json) always write when you explicitly create them. Nothing else is written to disk unless you turn persistence on.

Known limitations

License

MIT — see LICENSE.