界面与按钮

基本信息

属性 值
GUI ID 仅 1(GuiHandler 中 if (id == 1),其他 ID 返回 null)
注册方式 NetworkRegistry.INSTANCE.registerGuiHandler(this, new GuiHandler())
客户端 GUI lain.mods.cos.client.GuiCosArmorInventory extends InventoryEffectRenderer
服务端容器 lain.mods.cos.inventory.ContainerCosArmor
界面底图 cosmeticarmorreworked:textures/gui/cosarmorinventory.png
界面尺寸 176 × 166(GuiEvents 硬编码用于按钮定位)
注入方式 Forge GuiScreenEvent.InitGuiEvent.Post / ActionPerformedEvent.Post / DrawScreenEvent.Post
权限 无。ContainerCosArmor.canInteractWith() 恒为 true

GuiHandler.getServerGuiElement() 用服务端的 getCosArmorInventory(uuid),getClientGuiElement() 用客户端的 getCosArmorInventoryClient(uuid)——两侧容器结构完全一致(见 时装护甲物品栏)。

按钮 ID 总表

本 mod 共注入 4 类、7 个按钮实例,全部由 GuiEvents.guiPostInit() 在原版背包界面和成品界面同时创建:

按钮 ID 类 尺寸 定位(相对 guiLeft/guiTop) 作用
76 GuiCosArmorButton 10×10 +66, +67 在原版背包 ↔ 成品界面之间切换
77 GuiCosArmorToggleButton 5×5 +60, +72 全局开关 客户端护甲渲染替换
80 GuiCosArmorToggleButton 5×5 +97, +61(+7 + 18×3) 头盔槽(存储下标 0)皮肤模式开关
81 GuiCosArmorToggleButton 5×5 +97, +43 胸甲槽(存储下标 1)
82 GuiCosArmorToggleButton 5×5 +97, +25 护腿槽(存储下标 2)
83 GuiCosArmorToggleButton 5×5 +97, +7 靴子槽(存储下标 3)

按钮 80~83 只在成品界面生效:initGui() 是 GuiCosArmorInventory 的覆写方法,在原版背包界面里不会被调用;GuiEvents 只创建 76 和 77 两个按钮。按钮 76~83 也会在原版背包界面上出现(ID 76/77),其行为分支靠 event.gui instanceof GuiCosArmorInventory 区分。

按钮 76:界面切换

在 GuiEvents.guiPostAction() 中处理,按所在界面分两种路径:

点击时所在界面 行为 发出的封包
原版背包(GuiInventory) 保持界面不变,交给服务端 openGui(..., 1, ...) 切换 PacketOpenCosArmorInventory(判别字 3)
成品界面(GuiCosArmorInventory) 客户端先 displayGuiScreen(new GuiInventory(...)),服务端再把 openContainer 改回 inventoryContainer PacketOpenNormalInventory(判别字 4)

两条路径都是客户端先本地切界面、服务端封包后到,因为容器状态无法跨端直接同步。详见 网络封包。

按钮图标取自同一张贴图:普通态 drawTexturedModalRect(x, y, 10, 166, 10, 10),悬停态 (x, y, 0, 166, 10, 10),用混合打开。悬停提示由 GuiEvents.guiPostDraw() 在 DrawScreenEvent.Post 阶段绘制,文本来自 I18n.format(displayString):原版背包界面为 cos.gui.buttonCos,成品界面为 cos.gui.buttonNormal。

按钮 77 / 80~83 的状态绘制

GuiCosArmorToggleButton.drawButton() 贴图取 (0 + 5 × state, 176) 处的 5×5 像素,所以 state 字段直接决定贴图列偏移:state = 0 取第 0 列,state = 1 取第 5 列。初始化时 GuiEvents 用 isRenderActive() ? 0 : 1、成品界面用 isSkinArmor(j) ? 1 : 0 预置,因此渲染开启 = 状态 0,渲染关闭 = 状态 1(按钮 77 的语义与 80~83 相反)。

GuiScreenTooltipHelper 的作用

GuiEvents.guiPostDraw() 需要遍历 event.gui.buttonList 并调用 GuiScreen.func_146283_a(...)(原版 drawHoveringText,SRG 名)。这两个成员在原版里是 protected,模组自己的类无法访问。net.minecraft.client.gui.GuiScreenTooltipHelper 通过把自己放进 net.minecraft.client.gui 包来解决——Java 的 protected 成员在同包内可直接访问,因此无需 Mixin、无需 Access Transformer、无需 coremod:

方法 实现 对应原版成员
static void drawTooltip(GuiScreen, List<String>, int, int) screen.func_146283_a(textLines, mouseX, mouseY) GuiScreen#func_146283_a(即 drawHoveringText)
static List<GuiButton> getButtonList(GuiScreen) return screen.buttonList; GuiScreen#buttonList 字段

该类是 final + 私有构造函数,两个方法都是纯转发,不含任何逻辑。它只服务于「给按钮加悬停提示」这一件事,并且提示只会在按钮可见且被悬停时绘制(cosButton.visible && cosButton.isHovered() && tooltip != null),且遍历中 break,因此同一时刻最多显示一个按钮提示。

界面内嵌功能

  • 成品界面继承 InventoryEffectRenderer,因此药水附魔的装备在界面内会渲染光效。
  • 2×2 合成网格可用,产物槽禁止 Shift 取货(见 时装护甲物品栏)。
  • 界面中会绘制可自由转动的玩家模型:drawPlayerModel() 复制自原版 GuiInventory,通过鼠标 X/Y 偏移(xSizeFloat / ySizeFloat,在 drawScreen() 末尾记录)驱动 rotationYaw / rotationPitch。
  • 按钮 0/1 被复用为原版「成就」/「统计」界面(GuiAchievements / GuiStats),但 GuiCosArmorInventory.initGui() 先 buttonList.clear() 再 super.initGui(),因此重建的是 GuiContainer 的默认按钮。

相关条目