# Staff tools Source: https://tehoclient.dev/modules/staff SDK: 1.0.0 Teho gives your moderators a full staff client that works only on your server: X-Ray, ESP, freecam, an inspector, an action wheel, alerts and more, with no hacked clients and no extra mods. Grants are per player. Each moderator accepts them once per server in a prompt that names your server, and can revoke them at any time. ## Grant tools The easy way is by permission in [`config.yml`](https://tehoclient.dev/owners/configuration#staff-tools). From code: ```java teho.staff().grant(StaffGrant.of(StaffTool.XRAY, StaffTool.PLAYER_ESP, StaffTool.FREECAM) .reason("Moderator") .build()); teho.staff().grant(StaffGrant.everything().reason("Senior moderator").radius(64).build()); teho.staff().revoke(StaffTool.FREECAM); teho.staff().revokeAll(); ``` A grant **replaces** the player's previous grant from your server. To add tools, start from `granted()`. | `StaffGrant.Builder` | Notes | |---|---| | `of(tools…)`, `of(Collection)`, `everything()` | Which tools. | | `reason(String)` | Shown in the consent prompt. | | `xray(XrayBlock…)` | Blocks X-Ray shows, such as `XrayBlock.of("minecraft:diamond_ore", 0x5FE0DC)`. Defaults to common ores and spawners. | | `storage(XrayBlock…)` | Blocks storage ESP shows. Defaults to chests, shulkers, hoppers and similar. | | `entities(XrayBlock…)` | Entity types entity ESP shows. | | `radius(blocks)` | Scan radius from 8 to 128. Default 48. | ### Who has what | Method | Returns | |---|---| | `granted()` | Tools you granted. | | `accepted()` | Tools the moderator accepted. | | `active()` | Tools switched on right now. | | `supported()` | Tools this client build can render. | `TehoStaffToolEvent` fires whenever a tool switches on or off, for example to vanish a moderator who enters freecam. ## Tools | Id | `StaffTool` | What it does | |---|---|---| | `xray` | `XRAY` | Shows the configured ores, spawners and custom blocks through terrain. | | `storage_esp` | `STORAGE_ESP` | Outlines chests, shulkers, hoppers and other storage. | | `player_esp` | `PLAYER_ESP` | Player outlines and info through walls, coloured by `espColors`. | | `nametags` | `NAMETAGS` | Nametags through walls. | | `entity_esp` | `ENTITY_ESP` | Outlines the configured entity types. | | `tracers` | `TRACERS` | Lines from the crosshair to tracked players. | | `fullbright` | `FULLBRIGHT` | Full brightness. | | `highlights` | `HIGHLIGHTS` | Shows highlights your server sends. | | `lag_map` | `LAG_MAP` | Chunk heat map of entities and tile entities. | | `trails` | `TRAILS` | Draws a player's recent movement. | | `inspector` | `INSPECTOR` | Look at a player, block or entity for a card of facts and actions. | | `combat_overlay` | `COMBAT_OVERLAY` | CPS, best reach and hits above nearby players who are fighting. | | `spectate` | `SPECTATE` | A follow camera locked to a player. | | `freecam` | `FREECAM` | Detached camera. The moderator's body stays put. | | `action_wheel` | `ACTION_WHEEL` | A radial menu of actions on whatever the moderator is looking at. | | `alerts` | `ALERTS` | An alert feed in the HUD, with one-key teleport and spectate. | | `click_teleport` | `CLICK_TELEPORT` | Teleport to the block the moderator clicks. | ## Highlights Mark a player, a block or an area for every moderator with the `highlights` tool. ```java teho.staff().highlight(Highlight.entity("vanished:" + mod.getUniqueId(), mod.getUniqueId()) .label("Vanished") .color(0xB07CFF) .tracer(true) .build()); teho.staff().highlight(Highlight.area("claim-42", 100, 60, 100, 140, 90, 140) .label("Disputed claim") .style(Highlight.Style.BOTH) .lifetime(60_000) .build()); teho.staff().removeHighlights("claim-42"); ``` Styles are `OUTLINE`, `FILL` and `BOTH`. ## ESP colours ```java teho.staff().espColors(Map.of(suspectId, 0xFF5555), Map.of(suspectId, "Flagged: Reach")); ``` ## Alerts Push an alert into the feed of every moderator you send it to. Severities are `INFO`, `WARN` and `HIGH`. ```java StaffAlert alert = StaffAlert.builder("ac-" + suspect.getUniqueId(), "Reach (VL 12)") .severity(StaffAlert.Severity.HIGH) .body("3.4 blocks on " + suspect.getName()) .player(suspect.getUniqueId()) .build(); TehoApi.get().players().stream() .filter(teho -> teho.staff().active().contains(StaffTool.ALERTS)) .forEach(teho -> teho.staff().alert(alert)); ``` With no code, point your anticheat at `/tehoapi alert %player% high Reach_VL_%vl%`. ## Inspector cards When a moderator inspects something, the built-in Bukkit kit answers with health, ping, game mode, first join and Teho Client for players, type, biome and contents for blocks, and type, health and age for entities. Answer `TehoInspectEvent` to add your own card: ```java @EventHandler public void onInspect(TehoInspectEvent event) { if (event.getTarget().kind() != Target.Kind.PLAYER) { return; } UUID id = event.getTarget().id(); event.getResponder().reply(InspectCard.builder("Skyline profile") .subtitle(rankOf(id)) .row("Alts", altsOf(id).size()) .row("Warnings", warningsOf(id), 0xFFC24D) .action("history", "Punishment history") .action("ban", "Ban") .lifetime(10_000) .build()); } ``` Card actions arrive as `TehoStaffActionEvent` with the action id. ## Action wheel The wheel comes from `staff.action-wheel` in config. From code: ```java teho.staff().actionWheel("Skyline staff", Arrays.asList( WheelAction.of("freeze", "Freeze", "ice", Target.Kind.PLAYER), WheelAction.of("history", "History", "book", Target.Kind.PLAYER).color(0xFFC24D), WheelAction.of("lagmap", "Lag map", "hopper", Target.Kind.NONE))); ``` ```java @EventHandler public void onAction(TehoStaffActionEvent event) { if (event.getAction().equals("history")) { openHistory(event.getPlayer(), event.getTarget().id()); } } ``` ## Target stats, trails, spectate and lag map ```java teho.staff().targetStats(suspectId, Arrays.asList( StatRow.of("CPS", 17, 0xFF5555), StatRow.of("Reach", "3.4")), 2000); teho.staff().trail(suspectId, points, 0xFFC24D, "Last 5 minutes", "overworld", 30_000); teho.staff().spectate(suspectId, 4); teho.staff().stopSpectating(); teho.staff().lagMap("overworld", Arrays.asList( LagCell.of(12, -4, 92, "412 item frames"), LagCell.of(13, -4, 40, "88 hoppers")), 60_000); ``` Each trail point is an `int[]` of `{x, y, z}`. ## Built in on Bukkit With no code, the Bukkit plugin already provides the action wheel (freeze, spectate, teleport, inventory view, screenshot, mod check, path history, lag map, kick), inspector cards, freeze, screenshot and mod-check requests, movement trails, the combat overlay and the alert feed. See [Commands](https://tehoclient.dev/owners/commands#staff). **Known gaps** - Freecam inside terrain can cull chunk sections, since there is no spectator-style culling override yet. Clicks still act from the body. - On 26.x, staff overlays can trail the camera by one frame. - On legacy clients the moderator's own body is not drawn in freecam, and controller look still turns the body. - Entity ESP on 1.7.10 and 1.8.9 misses sub-variants that became separate ids later, such as wither skeletons and elder guardians. - Trails and lag maps only draw while their tool is switched on.