猫与箱子行为(ocelots*)

基本信息

配置项位于 config/ironchest.cfg 的 general 段(IronChest.java:60-71),控制原版豹猫(Ocelot)与本 mod 箱子的交互。本 mod 不注册任何实体,只替换豹猫的 AI 任务并加一个开箱门禁。

键名 类型 默认值 字段 源码描述
ocelotsSitOnChests boolean true IronChest.OCELOTS_SITONCHESTS “Whether or not to allow Ocelots to sit on Iron Chests.”
ocelotsBlockChests boolean true IronChest.OCELOTS_BLOCKCHESTS “Whether or not Ocelots should prevent opening Iron Chests when sitting on top of them.”

两个开关互相独立:ocelotsSitOnChests 控制猫能不能坐上去,ocelotsBlockChests 控制坐着的猫会不会挡住开箱。

ocelotsSitOnChests — 替换坐箱 AI

IronChest.load() 条件注册事件处理器:

if (OCELOTS_SITONCHESTS) {
    MinecraftForge.EVENT_BUS.register(new OcelotsSitOnChestsHandler());
}

OcelotsSitOnChestsHandler 监听 LivingEvent.LivingUpdateEvent,在豹猫刚出生(ticksExisted < 5)时遍历它的 AI 任务表,把 priority == 6 且 action instanceof EntityAIOcelotSit 但不是已经是 IronChestAIOcelotSit 的任务,替换为 new IronChestAIOcelotSit(ocelot, 1.33D)(导航速度 1.33)。

IronChestAIOcelotSit 覆写 func_151486_a(World, int, int, int)(原版 EntityAIOcelotSit.isSittableBlock,经 META-INF/IronChest_at.cfg 映射):

Block targetBlock = world.getBlock(x, y, z);
if (targetBlock == IronChest.ironChestBlock) {
    TileEntityIronChest chest = (TileEntityIronChest) world.getTileEntity(x, y, z);
    if (chest.getNumUsingPlayers() == 0) return true;   // 没人开箱才允许坐
}
return super.func_151486_a(world, x, y, z);

即:本 mod 的任意 metadata 变体(因为判定的是方块对象,不是 metadata)都可坐,且有人正在开这个箱子时猫不能坐上去。

[!IMPORTANT] 覆写只影响"能否开始坐"的判定。猫坐上后玩家再开箱,IronChestAIOcelotSit 不会再检查——那一侧由 ocelotsBlockChests 负责。

ocelotsBlockChests — 坐猫挡开箱

BlockIronChest.isOcelotSitting(World, int, int, int):

if (!IronChest.OCELOTS_BLOCKCHESTS) return false;
List<EntityOcelot> cats = world.getEntitiesWithinAABB(EntityOcelot.class,
        AxisAlignedBB.getBoundingBox(x, y + 1, z, x + 1, y + 2, z + 1));
for (EntityOcelot cat : cats) {
    if (cat.isSitting()) return true;
}
return false;

在 onBlockActivated 中:

if (isOcelotSitting(world, i, j, k)) {
    return true;   // 视为"玩家成功使用",但不开 GUI
}

搜索范围是箱子正上方那一格(y+1 到 y+2 的 1×1×1 AABB),只看 isSitting() 为 true 的个体。多只猫时任意一只坐着就挡住。

判定的执行顺序

onBlockActivated(BlockIronChest.java:108)的检查顺序是固定的:

顺序 检查 结果
1 TE 不是 TileEntityIronChest return true(不打开)
2 箱子正上方是实心方块(isSideSolid(x, y+1, z, DOWN)) return true(不打开)
3 world.isRemote(客户端) return true(GUI 由客户端侧构建)
4 isOcelotSitting(...) return true(不打开,但只在服务端才走到这一步)
5 正常路径 player.openGui(..., te.getType().ordinal(), ...)

因为第 2 步要求上方不是实心方块,所以只有猫坐在箱子上(占据 y+1 的空气格)时第 4 步才有机会生效。

与箱子方块的其它门禁对比

门禁 是否可被配置关闭 源码
正上方是实心方块 否 isSideSolid 硬编码
上方有坐着的猫 是(ocelotsBlockChests) isOcelotSitting
猫能否坐上箱子 是(ocelotsSitOnChests) IronChestAIOcelotSit
有人开箱时猫能否坐 否(硬编码 getNumUsingPlayers() == 0) IronChestAIOcelotSit

数值

数值 默认值 说明
ocelotsSitOnChests true 事件处理器是否注册
ocelotsBlockChests true 开箱门禁是否生效
豹猫导航速度 1.33D 写死在 new IronChestAIOcelotSit(ocelot, 1.33D),不可配置
替换的 AI 优先级 6 硬编码匹配 task.priority == 6
生效时间窗 ticksExisted < 5 只在豹猫出生后 5 tick 内替换一次
阻挡搜索体积 1×1×1(箱子正上方一格) getEntitiesWithinAABB(EntityOcelot.class, ...)

相关条目