TableBlockMixin

基本信息

属性 值
Mixin 目标 thaumcraft.common.blocks.BlockTable
注入方式 @Redirect(不是 @Inject)
注入方法 onBlockActivated
Mixin 数量 1 个(mixins.ThaumcraftResearchTweaks.json 的 mixins 数组仅 "TableBlockMixin")
require 4

配置文件

src/main/resources/mixins.ThaumcraftResearchTweaks.json:

{
  "required": true,
  "minVersion": "0.7.11",
  "package": "elan.tweaks.thaumcraft.research.frontend.integration.table.mixin",
  "target": "@env(DEFAULT)",
  "compatibilityLevel": "JAVA_8",
  "mixins": ["TableBlockMixin"],
  "injectors": { "defaultRequire": 1 }
}

注意 refmap 字段在源码中存在(mixins.ThaumcraftResearchTweaks.refmap.json),由构建生成。

require = 4 与 TC 源码精确对应

BlockTable.onBlockActivated 中恰好有 4 处 EntityPlayer.openGui 调用(thaumcraft4/thaumcraft/common/blocks/BlockTable.java):

行号 GUI ID 触发方块
181 13 TileArcaneWorkbench(奥术工作台)
185 8 TileDeconstructionTable(解构台)
189 10 TileResearchTable(研究台,本方块)
197 10 相邻方块中的 TileResearchTable(扫描 4 个水平方向)

require = 4 与之精确匹配——若 TC 增减 openGui 调用点,Mixin 会因 required: true + defaultRequire: 1 而启动失败,而非静默失效。

重定向逻辑

@Mixin(BlockTable::class)
abstract class TableBlockMixin {
  private val `tcrt$THAUMCRAFT_RESEARCH_TABLE_GUI_ID`: Int = 10

  @Redirect(method = ["onBlockActivated"],
      at = At(value = "INVOKE",
              target = "net.minecraft.entity.player.EntityPlayer.openGui(Ljava/lang/Object;ILnet/minecraft/world/World;III)V",
              remap = false),
      require = 4)
  private fun correctGuiCallFor(entityPlayer, mod, modGuiId, world, x, y, z) {
    return if (modGuiId == `tcrt$THAUMCRAFT_RESEARCH_TABLE_GUI_ID`) {
      entityPlayer.openGui(ThaumcraftResearchTweaks, ThaumcraftResearchGuiHandler.IDs.RESEARCH_TABLE, world, x, y, z)
    } else {
      entityPlayer.openGui(mod, modGuiId, world, x, y, z)   // 原样放行
    }
  }
}
输入 GUI ID 处理
10(研究台) 改开 TRT 自己的 GUI,ID = 0
13 / 8 原样放行,仍打开 TC 本体 GUI

remap = false 是必需的:目标是 net.minecraft.entity.player.EntityPlayer.openGui,一个未混淆的 Minecraft 类;若让 SpongePowered 尝试重映射会失败。

相邻研究台(GUI 10 第二处)行为正确

TC 的第 197 行会扫描 4 个水平方向找相邻的研究台,并以偏移后坐标打开 GUI:

for (int a = 2; a < 6; a++) {
    TileEntity tile = world.getTileEntity(x + ForgeDirection.getOrientation(a).offsetX, ...);
    if (tile != null && tile instanceof TileResearchTable) {
        player.openGui(Thaumcraft.instance, 10, world,
                       x + ForgeDirection.getOrientation(a).offsetX,
                       y + ForgeDirection.getOrientation(a).offsetY,
                       z + ForgeDirection.getOrientation(a).offsetZ);
        break;
    }
}

Mixin 处理函数声明的 7 个参数恰好对应 openGui 的 7 个实参,故 x, y, z 绑定的是调用点传入的坐标(此处理解为偏移坐标),重定向后仍传偏移坐标。

TRT 的 GUI 处理器据此取 TileEntity(ThaumcraftResearchGuiHandler.kt):

private fun World.getTableTileEntity(x: Int, y: Int, z: Int) =
    getTileEntity(x, y, z) as TileResearchTable

坐标一致,取到的仍是 TileResearchTable,行为正确。

新 GUI ID

ThaumcraftResearchGuiHandler.IDs.RESEARCH_TABLE = 0(ThaumcraftResearchGuiHandler.kt:21-23):

object IDs { const val RESEARCH_TABLE = 0 }

与 TC 的 8 / 10 / 13 不冲突(不同模组的 GUI ID 空间独立,且由 NetworkRegistry.INSTANCE.registerGuiHandler(ThaumcraftResearchTweaks, …) 注册)。

处理器对未知 ID 记 logger.error("Received unknown gui id: $id") 并返回 null。

相关条目