猫与箱子行为(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, ...) |
相关条目
- Iron Chest 方块 -
onBlockActivated与isOcelotSitting的宿主 - Crystal Chest - 唯一
isTransparent()的箱子(与本条目无关,但同属渲染/行为覆写) - 箱子类型开关 · 透明箱子渲染 · 升级黑名单 - 其余配置项