仅存一物

仅存一物

告别重复物品

唯一物品

唯一物品(Only One Item)是一个 Minecraft 1.12.2 模组,用于通过将等效的物品堆叠重定向到一个共同目标,来减少整合包中的重复物品和流体。它在运行时需要 MixinBooter >= 8.0。

本项目受 OneEnoughItem 启发。它既不是该项目的分支,也未使用该项目的代码。其功能与 UniDict 有所重叠,但是独立实现的。

项目介绍

唯一物品是一个独立的 Minecraft 1.12.2 模组,用于统一整合包中等效的物品和流体。它会将创建、复制或修改的物品堆叠重定向到配置的目标,并在运行时需要 MixinBooter >= 8.0。

本项目受 OneEnoughItem 启发,但既不是其分支,也不包含其衍生代码。它是 UniDict 的独立替代方案。

配置文件

三个配置文件分别为 config/ooi/ooi_item.json、config/ooi/ooi_fluid.json 和 config/ooi/ooi_item_black_list.json。物品文件接受物品 ID/元数据和矿物词典匹配源,流体文件映射流体名称,黑名单接受 Item、ModID 和 OreDict 条目。参见 JSON 示例。

最终生效的 JSON 和 CRT 配置会被写回所有三个文件。注释和原始格式不会被保留,因此编辑前请备份文件。无效目标会被忽略并记录日志。

CraftTweaker 主要用于生成或完善这三个 JSON 文件,有效的注册条目会被写入 JSON。在添加或更改 CRT 脚本后的首次启动时,替换结果可能不完整或不准确。启动后请检查生成的 JSON,并重启游戏或服务器。JSON 确认无误后,后续启动可直接使用 JSON;CRT 脚本并非必须保留。

CraftTweaker

当前 API 包括 mods.ooi.ConversionItem(create(IItemStack)、addMatchItem(...) 重载及 register())、mods.ooi.ConversionFluid(create(ILiquidStack)、addMatchFluid(...) 重载及 register())和 mods.ooi.BlackList(针对物品、矿物词典条目、模组 ID 及可变参数的 addMatchItem(...) 重载)。参见 共享 ZenScript 示例。在调用 register() 前添加匹配源;黑名单条目可直接添加。CRT 主要是生成或完善 JSON 配置的一种方式,有效的注册条目会持久化到 JSON 中。

配方处理

矿物词典条目可用作物品匹配源。唯一物品会分析重复的工作台配方,并在满足其合并规则时进行合并;它不会无条件地合并所有物品或流体配方。如果加载了 UniDict,唯一物品将跳过自身的工作台配方清理。

项目定位

唯一物品在物品或流体堆叠创建、复制和修改时应用映射,使功能重复但注册名不同的内容可以使用统一目标。它适合用于减少整合包中的重复物品、流体和由此产生的配方碎片。

本项目受到 OneEnoughItem 启发,但不是其分支,也没有使用其代码。本项目可以作为 UniDict 的独立替代方案。

配置文件

配置目录是 config/ooi,包含以下三个文件:

  • ooi_item.json:物品和矿辞 source 到目标物品的映射。
  • ooi_fluid.json:流体 source 到目标流体的映射。
  • ooi_item_black_list.json:不参与物品替换的物品、模组或矿辞。

ooi_item.json

[
  {
    "matchItems": [
      {
        "id": "minecraft:gold_ingot",
        "meta": 0
      },
      {
        "oreName": "ingotGold"
      }
    ],
    "targetID": "minecraft:gold_ingot",
    "targetMeta": 0
  }
]

matchItems 可以包含具体物品(id + meta)或矿辞(oreName)。上例把 minecraft:gold_ingot:0 和 ingotGold 枚举出的 source 指向 minecraft:gold_ingot:0;目标相同时只是语法示例。

ooi_fluid.json

[
  {
    "matchFluids": [
      "water",
      "some_mod:water"
    ],
    "targetID": "water"
  }
]

matchFluids 和 targetID 使用流体注册表名称;最终阶段会检查目标流体是否存在,不存在的目标映射会被丢弃。

ooi_item_black_list.json

[
  {
    "type": "Item",
    "name": "minecraft:gold_ingot",
    "meta": 0
  },
  {
    "type": "ModID",
    "name": "minecraft"
  },
  {
    "type": "OreDict",
    "name": "ingotGold"
  }
]

Item 按物品 ID 和 meta 排除,ModID 按模组 ID 排除,OreDict 按矿辞名称排除。黑名单会阻止匹配到的物品或矿辞参与统一。

注意事项

最终有效配置会写回 config/ooi/ooi_item.json、config/ooi/ooi_fluid.json 和 config/ooi/ooi_item_black_list.json。文件会被规范化覆盖,手工注释和原始排版不会保留,编辑前请备份。无效目标会被忽略并记录日志。

CRT 在本模组中主要用于生成或补全这三份 JSON 配置,脚本注册的有效条目会写入 JSON。首次加入或修改 CRT 脚本的那次启动,运行中的替换结果可能不完整或不准确;启动完成后请检查生成的 JSON 并重启游戏或服务端。确认 JSON 无误后,后续启动以 JSON 为准,不要求继续保留 CRT 脚本。

CraftTweaker API

当前 ZenScript 类名和方法如下:

  • mods.ooi.ConversionItem:create(IItemStack)、addMatchItem(IItemStack)、addMatchItem(IOreDictEntry)、addMatchItem(Object...)、register()。
  • mods.ooi.ConversionFluid:create(ILiquidStack)、addMatchFluid(String)、addMatchFluid(ILiquidStack)、addMatchFluid(Object...)、register()。
  • mods.ooi.BlackList:addMatchItem(IItemStack)、addMatchItem(IOreDictEntry)、addMatchItem(String)、addMatchItem(Object...)。

ConversionItem 和 ConversionFluid 先用 addMatch... 添加 source,再调用 register() 提交目标;BlackList.addMatchItem(...) 可直接添加黑名单项。

以下脚本可用于批量生成上述 JSON;首次运行请先阅读注意事项。

import mods.ooi.ConversionItem;
import mods.ooi.ConversionFluid;
import mods.ooi.BlackList;

BlackList.addMatchItem("chisel");

static modid as string[] = [
    "minecraft",
    "thermalfoundation",
    "enderio",
    "tconstruct",
    "ic2",
    "mekanism",
    "taiga"
];

function getODItem(od as IOreDictEntry) as IItemStack {
    if (isNull(od.firstItem)) return <minecraft:stone>;

    var selected as IItemStack = null;
    for i in 0 to modid.length {
        for item in od.items {
            if (item.definition.owner == modid[i]) {
                selected = item;
                break;
            }
        }
        if (!isNull(selected)) break;
    }

    return isNull(selected) ? od.firstItem : selected;
}

if (!(<ore:itemSilicon>.empty)) {
    ConversionItem.create(getODItem(<ore:itemSilicon>))
        .addMatchItem(<ore:itemSilicon>)
        .register();
}

for od in oreDict.entries {
    var odName = od.name;
    if (odName.startsWith("ore")
        || odName.startsWith("dust")
        || odName.startsWith("ingot")
        || odName.startsWith("gem")
        || odName.startsWith("nugget")
        || odName.startsWith("plate")
        || odName.startsWith("gear")
        || odName.startsWith("stick")
    ) {
        ConversionItem.create(getODItem(od))
            .addMatchItem(od)
            .register();

        if (odName.startsWith("gem")) {
            val od0 = oreDict.get("block" + odName.substring("gem".length));
            if (!od0.empty) {
                ConversionItem.create(getODItem(od0))
                    .addMatchItem(od0)
                    .register();
            }
        } else if (odName.startsWith("ingot")) {
            val od0 = oreDict.get("block" + odName.substring("ingot".length));
            if (!od0.empty) {
                ConversionItem.create(getODItem(od0))
                    .addMatchItem(od0)
                    .register();
            }
        }
    }
}

复杂的批量规则可以使用同一套 API 编写循环或函数。替换某些模组物品可能改变其配方或机器行为,请在目标整合包中验证。

配方处理

唯一物品会分析工作台中的重复配方,并在满足条件时重建合并后的配方。它不是对所有物品和流体配方无条件直接合并。

如果检测到 UniDict 已加载,唯一物品会跳过自身的工作台重复配方处理,避免重复处理。