时装护甲物品栏
[!INFO] 实现类:
lain.mods.cos.inventory.InventoryCosArmor(服务端 + 客户端各一份)
基本信息
| 属性 | 值 |
|---|---|
| 槽位总数 | 4(ItemStack[] stacks = new ItemStack[4]) |
| 每槽堆叠上限 | 1(getInventoryStackLimit()) |
| 对应原版护甲格 | EntityPlayer.inventory.armorInventory[0..3] |
| 槽位容器名 | 空字符串(getInventoryName() 返回 "",hasCustomInventoryName() 返回 false,因此不参与 NBT 键名) |
| 数量上限 | 无(isItemValidForSlot() 对任意 ItemStack 都返回 true,校验全部在 Slot 层) |
| 使用权限 | 无(isUseableByPlayer() 恒为 true;ContainerCosArmor.canInteractWith() 也恒为 true) |
功能
在玩家身上挂载第二套纯装饰护甲。这套护甲只参与渲染,不参与伤害计算、不被原版护甲值读取、也不影响摔落/爆炸等护甲减伤判定。玩家同时拥有原版护甲格和本物品栏两套数据。
InventoryCosArmor 除 IInventory 全部方法外还维护一个 boolean[] isSkinArmor = new boolean[4],表示该槽是否处于「不穿」状态(皮肤模式),详见 皮肤模式开关。
槽位索引映射
InventoryCosArmor 的数组下标与原版 armorInventory 完全对齐,而容器内部为了画在正确的高度做了 3 - i 的翻转(ContainerCosArmor 构造函数第 69~71 行 invCosArmor.getSizeInventory() - 1 - i):
| 存储下标 | 对应原版 armorInventory |
部位 | ItemArmor.armorType |
容器槽位号 | 容器内 Y 坐标 | 皮肤模式按钮 ID |
|---|---|---|---|---|---|---|
| 0 | armorInventory[0] |
靴子 | 3 | 12 | 8 + 3×18 = 62 | 83 |
| 1 | armorInventory[1] |
护腿 | 2 | 11 | 8 + 2×18 = 44 | 82 |
| 2 | armorInventory[2] |
胸甲 | 1 | 10 | 8 + 1×18 = 26 | 81 |
| 3 | armorInventory[3] |
头盔 | 0 | 9 | 8 + 0×18 = 8 | 80 |
容器槽位号在成品界面中由上至下是 9(头盔) / 10(胸甲) / 11(护腿) / 12(靴子),即界面上方是头盔,与原版玩家背包一致。
槽位合法性校验
ContainerCosArmor 的 4 个时装槽各自重写了 isItemValid(ItemStack)(第 85~93 行),与 4 个原版护甲槽(第 55~63 行)逻辑完全相同:
Item item = stack == null ? null : stack.getItem();
boolean isValidArmor = false;
if (item instanceof ItemArmor) isValidArmor = ((ItemArmor) item).armorType == j;
return item != null
&& (isValidArmor || ((item instanceof ItemBlock || item instanceof ItemSkull) && j == 0));
j是容器绘制序号(0=头盔行,3=靴子行),不是存储下标。- 头盔行(
j == 0)额外接受ItemBlock与ItemSkull——这让玩家可以把方块或头颅塞进「时装」里做外观展示。 - 头盔以外的三行只接受
armorType完全匹配的ItemArmor。 - 注意
IInventory.isItemValidForSlot()恒返回true,所以只有通过界面放入才会被限制;setInventorySlotContents()与网络包可以写入任意ItemStack。
容器槽位总数
ContainerCosArmor 构造时共注册 49 个 Slot:
| 区段 | 槽位号 | 数量 | 坐标 |
|---|---|---|---|
| 合成产物 | 0 | 1 | (144, 36) |
| 2×2 合成网格 | 1~4 | 4 | (106, 26) 起,步进 18 |
| 原版护甲格 | 5~8 | 4 | (8, 8 + i×18) |
| 时装护甲格 | 9~12 | 4 | (80, 8 + i×18) |
| 玩家背包 | 13~39 | 27 | (8 + j×18, 84 + i×18) |
| 快捷栏 | 40~48 | 9 | (8 + i×18, 142) |
容器自带一个 InventoryCrafting(this, 2, 2) 与 InventoryCraftResult,onCraftMatrixChanged() 用 CraftingManager.findMatchingRecipe(craftMatrix, player.worldObj) 实时算产物,因此成品界面可以就地合成。
搬运与交互行为
全部沿用原版 Container 逻辑,transferStackInSlot() 的分区(无任何自定义右键/Shift+左键分支):
| 源槽位号 | 目标区间 | 说明 |
|---|---|---|
| 0(合成产物) | 13~49 | 先尝试整叠搬运 |
| 1~4(合成网格) | 13~49 | false,不整叠 |
| 5~12(两套护甲) | 13~49 | false,不整叠 |
| 13~39(玩家背包) | 40~49 | 优先快捷栏 |
| 40~48(快捷栏) | 13~40 | 优先背包 |
另有一段原版自动穿装备快捷逻辑(第 159~164 行):当拖动的物品是 ItemArmor 且 5 + armorType 号槽为空时,先尝试合并到 j = 5 + armorType(原版护甲格),失败再尝试 j + 4 = 9 + armorType(同一部位的时装格)。因此 Shift 拖动一件护甲会优先装到原版护甲位,只有该位被占用时才落到时装位。
func_94530_a() 被重写为对合成产物槽返回 false,即禁止 Shift+左键从产物槽取货。
onContainerClosed() 关闭界面时把 2×2 网格里的 4 件物品用 player.dropPlayerItemWithRandomChoice(stack, false) 丢回玩家(不是扔在地上),并清空产物槽。