1. 跨 Mod 通信(Inter-Mod Communication,IMC)

FML 提供了一套基于“发信和收信”的跨 Mod 间的通信系统(Inter-Mod Communication),通称 IMC。使用这套系统可以在不硬依赖某个 Mod 的代码的情况下,和其他 Mod 通过这种不与具体代码耦合的形式来实现互相“兼容”。

1.1. 五种类型的消息

  • String
  • ItemStack
  • NBTTagCompound
  • ResourceLocation
  • java.util.function.Function<?, ?>
    • 发送的信息是实现了 Function<?, ?> 的类的 Canonical Name。
    • 因为各种原因,FML 没有办法保存下来这个 Function<?, ?> 的真正类型信息,使用时也是使用的 unchecked cast,一切全靠 Modder 之间的约定。

1.2. 发送消息

一般来说消息是在 FML 加载的生命周期中进行的。只要是在 FMLInterModComms.IMCEvent 发布之前发送 IMC 消息即可。一般情况下,通常会选择 FMLPreInitializationEventFMLInitializationEvent 完成。
发送消息并不需要额外的 Loader.isModLoaded 的检查——因为 IMC 系统自己就会在存储消息前执行这个检查,收信的 Mod 不存在时就不会继续存储消息。所以直接发送消息即可,无用的数据自然会被回收掉的。

// Sending a String message
FMLInterModComms.sendMessage(modid, key, stringPayload);
// Sending an ItemStack message
FMLInterModComms.sendMessage(modid, key, itemStackPayload);
// Sending a NBTTagCompound message
FMLInterModComms.sendMessage(modid, key, tagPayload);
// Sending a ResourceLocation message
FMLInterModComms.sendMessage(modid, key, resourceLocationPayload);
// Sending a function message
FMLInterModComms.sendFunctionMessage(modid, key, functionClassCanonicalName);

虽然不常见,但在 FMLInterModComms.IMCEvent 发布之后仍然可以发送所谓的“运行时消息”:

// Sending a String message
FMLInterModComms.sendRuntimeMessage(modid, key, stringPayload);
// Sending an ItemStack message
FMLInterModComms.sendRuntimeMessage(modid, key, itemStackPayload);
// Sending a NBTTagCompound message
FMLInterModComms.sendRuntimeMessage(modid, key, tagPayload);
// Sending a ResourceLocation message
FMLInterModComms.sendRuntimeMessage(modid, key, resourceLocationPayload);
// Sending a function message
FMLInterModComms.sendRuntimeFunctionMessage(modid, key, functionClassCanonicalName);

1.3. 接收消息

@Mod.EventHandler
public void onIMCMessageDistributed(FMLInterModComms.IMCEvent event) {
    List<FMLInterModComms.IMCMessage> messages = event.getMessages();
    for (FMLInterModComms.IMCMessage message : messages) {
        if (message.isStringMessage()) {
            String stringData = message.getStringValue();
            // Do further process
        }
        if (message.isItemStackMessage()) {
            ItemStack itemStackData = message.getItemStackValue();
            // Do further process
        }
        if (message.isNBTMessage()) {
            NBTTagCompound nbtData = message.getNBTValue();
            // Do further process
        }
        if (message.isResourceLocationMessage()) {
            ResourceLocation resourceLocation = message.getResourceLocationValue();
            // Do further process
        }
        if (message.isFunctionMessage()) {
            Optional<Function<Foo, Bar>> function = message.getFunctionValue(Foo.class, Bar.class);
            if (function.isPresent()) {
                // Do further process after presence check
            }
        }
    }
}