被动破坏与翻动 AI(griefing-ai)
基本信息
| 属性 | 值 |
|---|---|
| 类名 | toast.specialAI.ai.grief.EntityAIGriefBlocks |
| 实例化 | AIHandler 在 onEntityJoinWorld 中根据 GRIEFING && GRIEF_TAG 与 FIDDLING && FIDDLE_TAG 调用 |
| 互斥位 | MOVEMENT + FACING |
| 优先级 | 与 wander/watch/lookIdle 同级(getPassivePriority) |
功能
实体在无事可做时(被任何更高级 AI 抢占前),周期性扫描附近方块并执行:
- GRIEFING:破坏可破坏方块(默认 farmland, bed, crafting_table, wooden_door, trapdoor, fence_gate, ladder;或所有光强>1 的方块)
- FIDDLING:右键交互方块(默认 lever, button, comparator, repeater, cake;通过构造
EntityFakePlayer触发onBlockActivated)
Activity 状态机
| 状态 | 触发 | 行为 |
|---|---|---|
NONE |
初始 / 重置 | 不做任何事 |
GRIEFING |
isValidTargetForGriefing 命中 |
走过去 → 视线确认 → 持续伤害方块直到破损 |
FIDDLING |
isValidTargetForFiddling 命中 + fiddleDelay <= 0 |
走过去 → 视线确认 → 调一次 targetBlock.onBlockActivated(fakePlayer) |
两个状态都通过
tryTargetBlock(x,y,z)在同一函数里独立判定,griefing 优先。
扫描循环(shouldExecute)
每 tick 最多 SCAN_COUNT(默认 24)次随机采样,受 AIHandler.canScan() 全局配额(scan_count_global)限制。采样范围:
x = X + nextInt(scanRange) - nextInt(scanRange) // 默认 [X-11, X+11]
y = Y + nextInt(scanRangeY) - nextInt(scanRangeY) // 默认 [Y-5, Y+5]
z = Z + nextInt(scanRange) - nextInt(scanRange)
scanRange = max(0, scan_range_config) + 1,保证至少 1×1 半径。 还需要游戏规则mobGriefing = true。
视线确认(checkSight)
对候选方块发射 3 条 rayTrace:
- 朝方块中心上/下偏 0.5(取决于实体相对高度)
- 朝方块中心左/右偏 0.5(取决于实体相对 X)
- 朝方块中心前/后偏 0.5(取决于实体相对 Z)
任一命中候选方块或可顺路破坏的遮蔽方块即视为视线可达。sightCounter 控制重新检测节奏(基础 10~14 tick,命中延长 3 tick)。
GRIEFING 详细
| 步骤 | 行为 |
|---|---|
| 路径 | tryMoveToXYZ(blockX, blockY, blockZ, 1.0) |
| 视线确认 | 见上 |
| 抵达后 | 锁死路径 + 锁死视线(连续 swingItem() + 播放方块 stepSound) |
| 伤害累加 | blockDamage += BlockHelper.getDamageAmount(targetBlock, ...) |
| 进度展示 | worldObj.destroyBlockInWorldPartially(entityId, ..., (int)(blockDamage * 10) - 1) |
| 破坏后 | 若为 farmland → 改为 dirt;否则 setBlockToAir,可选 dropBlockAsItem 留物品 |
| 音效 | playAuxSFX(2001, ..., Block.getIdFromBlock(targetBlock)) 破坏音;break_sound=true 时再播 1012 远处破碎音 |
giveUpDelay > 400 强制放弃。
MAD_CREEPERS 特性
若实体是 EntityCreeper 且 mad_creepers = true:
startExecuting不记录stepSound等updateTaskGriefing直接setCreeperState(1)+blockDamage = 1.0F,等下一 tick 立即引爆resetTaskGriefing调用setCreeperState(-1)取消点燃
FIDDLING 详细
构造 EntityFakePlayer(同坐标、同 motion),调用:
targetBlock.onBlockActivated(worldObj, x, y, z, fakePlayer, 0, 0.5F, 0.5F, 0.5F);
fakePlayer.updateWrappedEntityState();
失败时输出 Failed to fiddle with block! ({blockId})。完成后 10 tick 冷却(fiddleDelay = 10)。
NBT 个性化字段
AI 在 NBT 上为每个实体覆盖默认行为:
| 字段 | 含义 |
|---|---|
GriefScanRange |
自定义 scanRange(>0 时生效) |
GriefScanRangeVertical |
自定义 scanRangeY |
GriefNeedsTool |
该实体是否需要正确工具 |
GriefLights |
该实体是否瞄准光强方块 |
GriefBlocks |
该实体的目标方块列表(字符串) |
GriefBlacklist |
该实体的黑名单(字符串) |
FiddleBlocks |
该实体的翻动目标 |
FiddleBlacklist |
该实体的翻动黑名单 |
字段不存在时回落到
passive_griefing配置项。
方块列表语法(BlockHelper.newBlockSet)
farmland— 任意 metadatacake 0— 仅 metadata=0(未咬过的蛋糕)minecraft:*— 整个命名空间所有方块(递归 BlockRegistry)- 多项用
,分隔