NoName_mods PlayerAPI

NoName_mods PlayerAPI

客户端Fabric库,为模组提供简洁、高级API,用于玩家输入、物品栏、世界查询、视角控制、事件、调度以及类人自动化,使模组无需接触Minecraft内部代码。这是Ceres、Poseidon和ESP的共享基础。

PlayerAPI

一个客户端 Fabric 库,提供了清晰、高级的 API,用于玩家交互、世界查询和类人自动化。设计为一个共享基础,以便其他模组无需重新实现相同的低级 Mixin。

GitHub: https://github.com/noname-mods/PlayerAPI


对于玩家

PlayerAPI 本身不执行任何操作。如果你下载了它,说明你使用的另一个模组将其作为依赖项。只需将 .jar 文件与该模组一起放入 mods 文件夹即可。


Minecraft 版本支持

此库一次只针对一个 Minecraft 版本。 当它更新到新的 Minecraft 版本时,之前的版本将不会得到任何进一步的支持 —— 不会向后移植,不会修复错误,并且永远不会发布同时支持多个 Minecraft 版本的版本。请使用与你游戏版本和依赖它的模组相匹配的 PlayerAPI 构建版本。


对于开发者

PlayerAPI — 设计与 API 参考

版本: 1.12.0 Minecraft: 26.1.2 (Fabric) Maven 坐标: com.playerapi:playerapi:1.12.0


目录

  1. 概述与理念
  2. 架构
  3. 添加 PlayerAPI 作为依赖项
  4. 线程模型
  5. 事件 — PlayerAPIEvents
  6. 调度器
  7. 强制动作
  8. 人类动作
  9. 信息(只读查询)
  10. 数据类型
  11. 按键名称参考
  12. 已知限制

1. 概述与理念

PlayerAPI 是一个客户端 Fabric 库,为客户端自动化或实用模组所需的所有与本地玩家交互的操作,提供了一个清晰、稳定的抽象层。它的存在使得消费模组无需直接导入 Minecraft 内部代码——所有游戏交互都通过 PlayerAPI 的公有 API 类进行。

核心设计原则:

  • 关注点分离。 每个 API 类都有明确的职责:Info 类只读取状态,Action 类只执行动作。职责不混淆。
  • 处处都有安全默认值。 如果玩家不在世界中,每个读取玩家状态的方法都会返回一个安全默认值(0、false、""、空列表、EMPTY 快照)。消费模组永远不需要进行空值检查。
  • 仅主线程。 所有的动作调用和事件回调都在游戏主线程上运行。无需管理并发。
  • 强制 vs. 人类。 有两个并行的动作系统。强制动作是即时且计算机精确的(适合精确定位)。人类动作会添加反应延迟、弹簧物理视角插值和鼠标噪声(适合看起来自然)。消费模组可以选择适合其用例的系统。
  • 无内部状态泄露。 快照类型(ItemSnapshot、EntitySnapshot、BlockSnapshot、EffectSnapshot)是不可变的 Java 记录。它们可以被自由存储和比较,而不会受到底层游戏对象过时的影响。

2. 架构

┌─────────────────────────────────────────────────────────┐
│                    Consumer Mod                         │
│   (depends on PlayerAPI, never imports MC internals)    │
└───────────────────┬─────────────────────────────────────┘
                    │ uses
┌───────────────────▼─────────────────────────────────────┐
│                   PlayerAPI Public Surface               │
│                                                         │
│  Events          Scheduler       Actions (Forced)        │
│  PlayerAPIEvents  Scheduler      MovementActions         │
│                                 LookActions              │
│  Info (read)                    InventoryActions         │
│  PlayerInfo                     InteractionActions       │
│  InventoryInfo                  ChatActions              │
│  WorldInfo                      SoundActions             │
│  TabListInfo                    DisplayActions           │
│                                                         │
│  Actions (Human)   Data Types                           │
│  HumanActions      ItemSnapshot                         │
│  HumanProfile      EntitySnapshot                       │
│                    BlockSnapshot                         │
│                    EffectSnapshot                        │
└───────────────────┬─────────────────────────────────────┘
                    │ wraps
┌───────────────────▼─────────────────────────────────────┐
│               PlayerAPI Internals (not public)          │
│                                                         │
│  PlayerAPIMod      — wires Fabric events, drives ticks  │
│  KeyStateTracker   — held-key set, mixin read target    │
│  SchedulerState    — tick-based task queue              │
│  HumanLookState    — spring-damper look interpolation   │
│  MovementInputMixin — @Mixin(KeyboardInput) override    │
│  PlayerInventoryAccessor — @Mixin accessor for slots    │
└─────────────────────────────────────────────────────────┘

滴答流程(每个游戏滴答)

ClientTickEvents.END_CLIENT_TICK
        │
        ├─ 1. SchedulerState.tick()         — fires due scheduled tasks
        ├─ 2. HumanLookState.tick()         — advances spring interpolation
        ├─ 3. diff-based event checks       — health, position changes
        └─ 4. PlayerAPIEvents.TICK.invoke() — consumer mod tick callbacks

按键覆盖机制

MovementInputMixin 是一个用于 KeyboardInput 的 @Mixin,在其 tick() 方法中有一个 TAIL 注入。在每个原版输入滴答结束时,如果 KeyStateTracker.isActive() 为 true,mixin 会将 input.pressingForward、input.pressingBack、input.pressingLeft、input.pressingRight、input.jumping 和 input.sneaking 覆盖为 KeyStateTracker 中存储的值。这意味着覆盖对于游戏的其他部分是完全透明的——移动、疾跑物理和服务器数据包的行为都正常。


3. 添加 PlayerAPI 作为依赖项

build.gradle

repositories {
    mavenLocal()
}

dependencies {
    modImplementation "com.playerapi:playerapi:1.12.0"
}

gradle.properties

playerapi_version=1.12.0

fabric.mod.json

"depends": {
    "playerapi": ">=1.12.0"
}

首先构建 PlayerAPI:

cd PlayerAPI
./gradlew publishToMavenLocal

然后正常构建你的模组。


4. 线程模型

所有 PlayerAPI 的调用必须从主游戏线程进行。 这是运行 ClientTickEvents、渲染帧和处理网络数据包的线程。实际上这意味着:

  • 在 PlayerAPIEvents.TICK 处理器内部 — ✅ 始终安全
  • 在注册到主线程的任何 Fabric 事件处理器内部 — ✅ 安全
  • 从后台线程或 CompletableFuture — ❌ 从不安全;请使用 MinecraftClient.getInstance().execute(() -> ...) 编组回主线程

Scheduler 总是在主线程上触发回调。


5. 事件 — PlayerAPIEvents

所有事件都位于 com.playerapi.PlayerAPIEvents 上。在你的模组的 onInitializeClient() 中注册监听器。

PlayerAPIEvents.TICK.register(() -> {
    // runs every tick
});

所有事件都使用 Fabric 的 EventFactory.createArrayBacked 模式——多个模组可以独立注册,并且所有监听器都会触发。


TICK

Event<PlayerAPIEvents.Tick> TICK

每个游戏滴答触发一次,在 END_CLIENT_TICK 之后,在调度器处理完到期的任务之后。

接口:

@FunctionalInterface
interface Tick {
    void onTick();
}

备注:

  • 这是任何每滴答自动化逻辑的主要入口点。
  • 如果你的逻辑需要已加载的世界,请在顶部调用 PlayerInfo.isInWorld()。
  • 调度器在这个事件触发之前运行,因此从上一个滴答计划的任务在你的 TICK 处理器运行时已经完成。

CHAT_RECEIVED

Event<PlayerAPIEvents.ChatReceived> CHAT_RECEIVED

当任何聊天消息到达时触发——玩家聊天、系统消息或游戏消息。涵盖已签名的玩家消息和未签名的服务器消息。

接口:

@FunctionalInterface
interface ChatReceived {
    void onChatReceived(String sender, String message);
}
参数 描述
sender 发送者的显示名称,已去除颜色代码。对于系统/游戏消息为空字符串。
message 完整消息文本,已去除颜色代码。

备注:

  • 动作栏消息(overlay=true)不会被转发。
  • ClientReceiveMessageEvents.CHAT(玩家消息)和 ClientReceiveMessageEvents.GAME(系统/游戏消息)都会汇集到这个单一事件中。

HEALTH_CHANGED

Event<PlayerAPIEvents.HealthChanged> HEALTH_CHANGED

每当本地玩家的生命值以任意量变化时触发。

接口:

@FunctionalInterface
interface HealthChanged {
    void onHealthChanged(float oldHealth, float newHealth);
}

备注:

  • 如果生命值降至 0,PLAYER_DEATH 首先触发,然后 HEALTH_CHANGED 紧随其后触发。
  • 在加入世界时不会触发(初始生命值读取)。仅在第一个滴答之后的变化时触发。

INVENTORY_CHANGED

Event<PlayerAPIEvents.InventoryChanged> INVENTORY_CHANGED

当玩家的主背包发生变化时触发。

接口:

@FunctionalInterface
interface InventoryChanged {
    void onInventoryChanged(int slot, String newItemId);
}
参数 描述
slot 发生变化的背包格子。-1 表示批量/未知变化。
newItemId 该格子中新物品的命名空间 ID,例如 "minecraft:diamond_sword"。空-格-子为 "minecraft:air"。

POSITION_CHANGED

Event<PlayerAPIEvents.PositionChanged> POSITION_CHANGED

当玩家自上次触发以来移动超过 0.1 格时触发。这是一个基于阈值的事件——它不会每个滴答都触发,只在有意义的移动时触发。

接口:

@FunctionalInterface
interface PositionChanged {
    void onPositionChanged(double x, double y, double z);
}

备注:

  • 坐标是玩家的脚部位置。
  • 0.1 格大约是正常渲染比例下可见的最小移动。
  • 不适合毫米级精度追踪——对于那种精度,请在 TICK 中使用 PlayerInfo.getX/Y/Z()。

WORLD_JOIN

Event<PlayerAPIEvents.WorldJoin> WORLD_JOIN

在客户端连接到服务器或加载世界并且玩家实体可用后触发一次。

接口:

@FunctionalInterface
interface WorldJoin {
    void onWorldJoin();
}

备注:

  • 生命值/位置差异状态在加入世界时重置,因此 HEALTH_CHANGED 和 POSITION_CHANGED 不会在第一个滴答时错误触发。
  • 在此事件触发时,PlayerInfo.isInWorld() 返回 true。

WORLD_LEAVE

Event<PlayerAPIEvents.WorldLeave> WORLD_LEAVE

当客户端断开连接或离开世界时触发。所有按住的按键会被释放,任何激活的人类视角插值会在此事件触发前自动取消。

接口:

@FunctionalInterface
interface WorldLeave {
    void onWorldLeave();
}

PLAYER_DEATH

Event<PlayerAPIEvents.PlayerDeath> PLAYER_DEATH

当玩家的生命值达到 0 时触发。

接口:

@FunctionalInterface
interface PlayerDeath {
    void onPlayerDeath();
}

备注:

  • HEALTH_CHANGED 也会紧随其后触发,newHealth = 0。
  • 在此事件触发时,玩家实体仍然存在(死亡画面稍后出现)。

TAB_LIST_UPDATED

Event<PlayerAPIEvents.TabListUpdated> TAB_LIST_UPDATED

当服务器更新 Tab 列表玩家列表时触发。限速为每秒最多一次(根据游戏帧率,即每 Tick 一次)。

接口:

@FunctionalInterface
interface TabListUpdated {
    void onTabListUpdated();
}

BLOCK_BROKEN

Event<PlayerAPIEvents.BlockBroken> BLOCK_BROKEN

当本地玩家成功破坏一个方块时触发。由 Fabric 的 ClientPlayerBlockBreakEvents.AFTER 支持。

接口:

@FunctionalInterface
interface BlockBroken {
    void onBlockBroken();
}

备注:

  • 瞬间破坏的方块(作物、高草丛、花)会立即在客户端触发,无需等待服务器确认。这是农耕自动化最重要的场景。
  • 生存模式下的方块(石头、木头等)会在服务器确认破坏后触发。
  • 不传递位置或方块类型信息。如果你需要这些,请从之前的 TICK 事件中读取 WorldInfo.getBlockAtCrosshair()。

6. 调度器

com.playerapi.Scheduler — 基于游戏刻的任务调度(在主游戏线程上执行)。

1 刻 ≈ 50 毫秒(在 20 TPS 下)。

所有回调都是 Runnable,并在它们到期的刻结束时在主游戏线程上触发。


schedule(int delayTicks, Runnable task) → int

调度一个在 delayTicks 刻后运行的任务。返回一个取消令牌。

Scheduler.schedule(20, () -> doSomethingAfterOneSecond());
// token = return value, save it if you need to cancel
  • delayTicks = 0 会在下一立即执行。
  • 如果游戏低于 20 TPS,任务不保证精确的定时,但它们永远不会提前执行。

scheduleMs(long delayMs, Runnable task) → int

便捷重载。将毫秒转换为刻(除以 50,向上取整,最小为 1)。

Scheduler.scheduleMs(500, () -> doSomethingAfterHalfSecond());

scheduleRepeating(int periodTicks, int times, Runnable task) → int

调度一个重复任务。

参数 描述
periodTicks 每次调用之间的间隔刻数。
times 触发次数。传入 0 表示无限次(运行直到被取消)。
task 要运行的回调。
// Fire 5 times, once per second:
Scheduler.scheduleRepeating(20, 5, () -> BotLogger.info(“tick!”));

// Fire forever (infinite loop — cancel manually):
int token = Scheduler.scheduleRepeating(20, 0, () -> doPeriodicCheck());
// later:
Scheduler.cancel(token);

重要: 无限重复任务每次触发后会重新调度自己。取消初始令牌只能阻止当前待处理的调用触发——如果任务已经触发过一次,请使用 cancelAll() 或自己跟踪重新调度的令牌以实现硬取消。


cancel(int token)

通过令牌取消一个待处理的任务。使用无效/已触发的令牌调用是安全的。


cancelAll()

取消使用此调度器的所有模组的每个待处理任务。在 stopBot() 中有用,以确保在停止后没有残留的延迟动作触发。


getCurrentTick() → long

返回由 PlayerAPI 跟踪的当前全局刻数。在模组加载时从 0 开始,并在每次 END_CLIENT_TICK 时递增。对于时间戳和速率限制很有用。

long start = Scheduler.getCurrentTick();
// ...later...
long elapsed = Scheduler.getCurrentTick() - start; // in ticks
double seconds = elapsed / 20.0;

7. 强制动作

强制动作是即时且计算机精确的。它们会在下一个游戏刻立即生效,没有延迟、噪声或弹簧物理。在精度比外观更重要时使用这些。


7.1 MovementActions

控制玩家按住了哪些移动键。只有当调用了 setActive(true) 时,覆盖才生效。

有效的按键名称: “forward”、“back”、“left”、“right”、“sprint”、“sneak”、“jump”、“attack”、“use”


setActive(boolean active)

启用或禁用移动按键覆盖。禁用时,所有按键释放,玩家恢复完全的手动控制。在按下任何按键之前调用 setActive(true)。

MovementActions.setActive(true);
MovementActions.pressKey(“forward”);
MovementActions.pressKey(“sprint”);
// player now walks forward

isActive() → boolean

返回移动覆盖当前是否已启用。


pressKey(String key)

无限期按住一个键。该键在随后的每个刻中保持按住状态,直到调用 releaseKey 或 releaseAll。

MovementActions.pressKey(“jump”); // holds space bar

releaseKey(String key)

释放一个之前按住的键。

MovementActions.releaseKey(“sprint”);

releaseAll()

释放所有当前按住的键(forward, back, left, right, sprint, sneak, jump, attack, use)。不会禁用覆盖——setActive 状态保持不变。


tapKey(String key, long durationMs)

按下某个键 durationMs 毫秒,然后自动释放。内部转换为刻。

MovementActions.tapKey(“jump”, 100); // tap space for 100 ms (2 ticks)

pressKeys(Iterable<String> keys)

同时按下多个键。等同于为每个键调用 pressKey。


releaseDirectionKeys()

仅释放四个方向键(forward、back、left、right)。疾跑、潜行和跳跃状态不变。在保持疾跑模式的同时停止移动时很有用。


getHeldKeys() → Set<String>

返回当前所有按住的键名的不可修改快照。


isPressed(String key) → boolean

如果指定的键当前被覆盖系统按住,则返回 true。


randomDelay() → long

返回一个介于 50 毫秒和 260 毫秒之间的随机延迟。在编程按键之间作为定时抖动有用,用于反模式检测。


7.2 LookActions

立即设置玩家的视角方向。所有更改立竿见影——没有动画。

Minecraft 偏转角约定:

  • 0° = 南 (+Z)
  • 90° = 西 (−X)
  • 180° = 北 (−Z)
  • 270° = 东 (+X)

俯仰角: −90° = 正上方,0° = 水平,90° = 正下方。


setYaw(float yaw)

将玩家的水平旋转精确设置为 yaw 度。


setPitch(float pitch)

将玩家的垂直旋转精确设置为 pitch 度。自动限制在 [−90, 90] 范围内。


lookAt(double x, double y, double z)

立即旋转视角以查看一个精确的世界坐标。从玩家当前的眼睛位置自动计算所需的偏转角和俯仰角。

LookActions.lookAt(100.0, 64.0, -200.0);
// For level aim: pass player.getY() + 1.62 as the y argument

lookAtBlock(int x, int y, int z)

立即查看方块的中心(x+0.5,y+0.5,z+0.5)。


lookAtBlock(BlockPos pos)

同上,接受一个 BlockPos。


lookAtBlock(int x, int y, int z, Direction face)

查看方块特定面的中心。face 是 Minecraft 的 Direction 枚举值(UP、DOWN、NORTH、SOUTH、EAST、WEST)。

LookActions.lookAtBlock(10, 64, -5, Direction.UP); // aim at top face

lookAtBlock(int x, int y, int z, double xOffset, double yOffset, double zOffset)

查看方块内部的自定义点。偏移量是 [0,1] 范围内的分数,其中 0.5,0.5,0.5 是方块中心。

LookActions.lookAtBlock(10, 64, -5, 0.5, 1.0, 0.5); // top-face centre

snapToNearestCardinal()

将玩家的偏转角对齐到最接近的 90° 倍数。在朝向基本方向移动之前进行对齐时有用。


getSnappedYaw() → int

返回当前偏转角舍入到最近的基本方向(0、90、180 或 270)。


7.3 InventoryActions

直接的背包操作。所有操作在下一个刻立即生效。


switchToSlot(int slot)

将选定的快捷栏格子切换到 slot(0–8)。如果 slot 超出范围则无效果。


switchToItem(String displayName) → boolean

切换到第一个显示名称完全匹配的快捷栏物品(不区分大小写)。如果找到并切换则返回 true,如果不在快捷栏中则返回 false。

InventoryActions.switchToItem(“Wheat Hoe”);

switchToItemStartingWith(String prefix) → boolean

切换到第一个物品显示名称以指定前缀开头的快捷栏格子(不区分大小写)。对于分级物品很有用,例如 “Pest Repellent I” / “Pest Repellent MAX”,你只知道前缀。

InventoryActions.switchToItemStartingWith(“Pest Repellent”);

switchToItemId(String idSubstring) → boolean

切换到第一个物品的命名空间 ID 包含 idSubstring(不区分大小写)的快捷栏格子。当物品名称被本地化或可能更改时,比显示名称匹配更稳定。

InventoryActions.switchToItemId(“diamond_hoe”);

dropItem()

从当前手持的物品堆中丢弃一个物品(相当于 Q 键)。


dropStack()

丢弃当前手持的整个物品堆(相当于 Ctrl+Q)。


dropAllInHotbar(String displayName)

切换到每个匹配 displayName 的快捷栏格子,并丢弃整个物品堆。之后恢复原始选中的格子。


7.4 InteractionActions

玩家与物品、方块和实体的交互。


useItem()

使用(右键点击)主手中的物品。向服务器发送相应的使用物品数据包。适用于消耗品、投掷物、放置方块、打开方块等。


useOffhandItem()

与 useItem() 相同,但适用于副手格子。


useItemHeld(long durationMs)

持续每刻发送 useItem(),持续 durationMs 毫秒。适用于需要按住右键的物品(钓鱼竿、弓、蓄力弩)。

InteractionActions.useItemHeld(1500); // hold right-click for 1.5 seconds

attackTargeted()

攻击当前位于玩家准星下的实体(client.targetedEntity)。如果没有目标实体则无效果。


attackBlockAtCrosshair()

为当前位于准星下的方块发送一个左键点击方块事件。每刻调用以模拟按住左键挖掘方块。如果准星没有对准方块则无效果。


interactTargeted()

与当前位于准星下的实体进行右键交互(client.targetedEntity)。用于与 NPC 交谈、骑乘实体等。


closeScreen()

关闭任何当前打开的界面(背包、容器、告示牌等)。相当于按 Escape 键。


respawn()

向服务器发送重生请求。当玩家处于死亡画面时调用此方法来重生。


7.5 ChatActions


sendChat(String message)

代表玩家发送一条普通的聊天消息。不要在开头包含 /。

ChatActions.sendChat(“Hello, world!”);

sendCommand(String command)

发送一条命令,不包含前导斜杠。PlayerAPI 会在内部添加斜杠。

ChatActions.sendCommand(“tp 0 64 0”);  // sends /tp 0 64 0
ChatActions.sendCommand(“warp garden”); // sends /warp garden

7.6 SoundActions

播放来自内置 Minecraft 音效库或你自己的模组 .ogg 文件的音效。

浏览所有 Minecraft 音效 ID: https://misode.github.io/sounds/


registerSound(String namespace, String name) → SoundEvent

注册一个新的音效事件。在 onInitializeClient() 期间调用一次。.ogg 文件必须位于你模组资源 jar 中的 assets/<namespace>/sounds/<name>.ogg 路径下。

SoundActions.registerSound(“mymod”, “my_alert”); // assets/mymod/sounds/my_alert.ogg

play(Identifier soundId, float volume, float pitch)

通过 Identifier 播放音效。适用于已注册的模组音效和所有内置的 Minecraft 音效。

参数 范围 描述
volume 0.0 – 2.0 1.0 = 正常音量
pitch 0.5 – 2.0 1.0 = 正常音调/速度

play(String namespace, String name, float volume, float pitch)

便捷重载,接受命名空间和名称作为单独字符串。

SoundActions.play(“minecraft”, “entity.player.levelup”, 1.0f, 1.0f);

playById(String fullSoundId, float volume, float pitch)

通过完整字符串 ID 播放,例如 “minecraft:entity.player.levelup”。如果名称中没有命名空间的冒号,则默认为 “minecraft”。

SoundActions.playById(“entity.experience_orb.pickup”, 1.0f, 1.5f);

playRepeated(Identifier soundId, float volume, float pitch, int times, int intervalTicks)

播放音效 times 次,每次间隔 intervalTicks 刻。内部使用调度器。

// Play level-up sound 3 times, 1 second apart:
Identifier id = Identifier.of(“minecraft”, “entity.player.levelup”);
SoundActions.playRepeated(id, 1.0f, 1.0f, 3, 20);

playRepeated(Identifier soundId, float volume, float pitch, int times)

同上,但固定为 20 刻(1 秒)的间隔。


playByIdRepeated(String fullSoundId, float volume, float pitch, int times, int intervalTicks)

playRepeated 的字符串 ID 便捷版本。

SoundActions.playByIdRepeated(“minecraft:entity.player.levelup”, 1.0f, 1.0f, 5, 20);

stopAll()

停止所有当前正在播放的音效。


7.7 DisplayActions

显示游戏内 HUD 文本,而无需直接依赖 Minecraft 内部代码。


showTitle(String title, String subtitle)

显示标题和可选的副标题,使用默认时序(10 刻淡入 / 70 刻停留 / 20 刻淡出)。

支持 § 颜色代码。为任一参数传入 “” 以使其留空。

DisplayActions.showTitle(“§aBot Started”, “§7Primary path loaded”);

showTitle(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks)

同上,但使用自定义时序。


showActionBar(String message)

在动作栏上显示一条简短消息——即出现在快捷栏上方的行。大约 2 秒后消失。支持 § 颜色代码。

DisplayActions.showActionBar(“§ePaused — waiting for repellent”);

7.8 EntityHighlightActions

绘制一个半透明的、经过深度测试的彩色框,与实体的碰撞箱匹配。基于 Minecraft 的 Gizmos 调试绘制 API,因此它独立于原版的实体轮廓(发光)渲染通道——它不会像发光轮廓那样被视线遮挡削弱,也不受渲染器模组(Sodium 等)实现轮廓通道的方式影响。

高亮通过一个 owner 字符串进行命名空间隔离,以便多个消费模组可以同时高亮实体而不会相互覆盖。PlayerAPI 每刻重绘所有所有者的高亮;消费者只需发布他们当前的集合。

在 1.10.0 中添加。


setHighlights(String owner, Map<Integer, Integer> idToColor, float alpha)

在一次调用中替换 owner 的所有高亮。键是实体 ID,值是打包的 RGB int(0xRRGGBB)。alpha 是框的不透明度,0.0–1.0。

Map<Integer, Integer> highlights = Map.of(
        entity.getId(), 0xFF5555);
EntityHighlightActions.setHighlights(“esp”, highlights, 0.35f);

setHighlight(String owner, int entityId, int color, float alpha)

在 owner 下添加或更新单个实体的高亮,不触及该所有者的其他高亮。


clearHighlight(String owner, int entityId)

从 owner 的高亮集合中移除一个实体。


`clearOwner(String owner)**

移除在 owner 下注册的每一个高亮。当你的功能被禁用或玩家离开世界时调用。


7.9 BlockHighlightActions

在世界方块坐标周围绘制彩色框——一种“方块 ESP” / X光式高亮。每个框都是始终在最上层绘制的,因此穿过墙壁也可见(这是对 EntityHighlightActions 的补充,后者的实体叠加是经过深度测试/仅限视线遮挡的)。基于相同的 Gizmos API,并通过 owner 字符串进行命名空间隔离。

在 1.11.0 中添加。


setHighlights(String owner, Collection<BlockPos> positions, int color, float alpha)

将所有 owner 的方块高亮替换为给定的坐标,全部使用一种颜色(0xRRGGBB)。alpha 是填充不透明度(0.0–1.0);轮廓绘制得稍强一些,以便框保持可读性。

BlockHighlightActions.setHighlights(“esp-blocks”, positions, 0x55FFFF, 0.35f);

clearOwner(String owner)

移除在 owner 下注册的每一个方块高亮。当你的功能被禁用或世界发生变化时调用。


8. 人类动作

人类 API 镜像了强制 API,但添加了类人的不完美性:反应延迟、带过冲的弹簧物理摄像头移动、移动结束时的随机噪声以及滚轮槽切换。所有时序参数都可以通过 HumanProfile 进行调整。


8.1 HumanActions


视角方法(平滑,弹簧物理)

所有视角方法都开始一个朝向目标的弹簧阻尼插值。在移动开始前有一个可配置的反应延迟,摄像头加速朝向目标,自然过冲,并以小的随机噪声偏移稳定下来。如果弹簧太慢,一个 3 秒的看门狗会强制完成。

方法 描述
lookAt(float yaw, float pitch) 平滑查看给定的偏转角/俯仰角对。
lookAt(double x, double y, double z) 平滑查看一个精确的世界坐标。
lookAt(int x, int y, int z) 平滑查看方块的中心(整数坐标)。
lookAt(BlockPos pos) 平滑查看一个方块坐标。
lookAt(int x, int y, int z, Direction face) 平滑查看方块的特定面。
lookAt(BlockPos pos, Direction face) 同上,使用 BlockPos。
lookAt(int x, int y, int z, double xOffset, double yOffset, double zOffset) 平滑查看方块内的自定义点。
lookYaw(float yaw) 仅改变偏转角,保持当前俯仰角。
lookPitch(float pitch) 仅改变俯仰角,保持当前偏转角。
cancelLook() 中止任何进行中的视角插值。视图保持当前位置。
isLooking() → boolean 当视角(包括反应延迟)激活时返回 true。

按键方法(带反应延迟