    001package cpw.mods.fml.common.event;
    002
    003import java.util.List;
    004
    005import net.minecraft.item.ItemStack;
    006import net.minecraft.nbt.NBTTagCompound;
    007
    008import com.google.common.base.Function;
    009import com.google.common.base.Functions;
    010import com.google.common.base.Predicate;
    011import com.google.common.base.Predicates;
    012import com.google.common.collect.ArrayListMultimap;
    013import com.google.common.collect.FluentIterable;
    014import com.google.common.collect.ImmutableList;
    015import com.google.common.collect.ImmutableListMultimap;
    016import com.google.common.collect.Maps;
    017import com.google.common.collect.Multimaps;
    018
    019import cpw.mods.fml.common.FMLCommonHandler;
    020import cpw.mods.fml.common.FMLLog;
    021import cpw.mods.fml.common.Loader;
    022import cpw.mods.fml.common.LoaderState;
    023import cpw.mods.fml.common.Mod.Instance;
    024import cpw.mods.fml.common.ModContainer;
    025import cpw.mods.fml.common.Mod.Init;
    026import cpw.mods.fml.common.Mod.PostInit;
    027
    028/**
    029 * Simple intermod communications to receive simple messages directed at you
    030 * from other mods
    031 *
    032 * @author cpw
    033 *
    034 */
    035public class FMLInterModComms {
    036    private static final ImmutableList<IMCMessage> emptyIMCList = ImmutableList.<IMCMessage>of();
    037    private static ArrayListMultimap<String, IMCMessage> modMessages = ArrayListMultimap.create();
    038
    039    /**
    040     * Subscribe to this event to receive your messages (they are sent between
    041     * {@link Init} and {@link PostInit})
    042     *
    043     * @author cpw
    044     *
    045     */
    046    public static class IMCEvent extends FMLEvent {
    047        private ModContainer activeContainer;
    048
    049        @Override
    050        public void applyModContainer(ModContainer activeContainer)
    051        {
    052            this.activeContainer = activeContainer;
    053            FMLLog.finest("Attempting to deliver %d IMC messages to mod %s", modMessages.get(activeContainer.getModId()).size(), activeContainer.getModId());
    054        }
    055
    056        private ImmutableList<IMCMessage> currentList;
    057
    058        public ImmutableList<IMCMessage> getMessages()
    059        {
    060            if (currentList == null)
    061            {
    062                currentList = ImmutableList.copyOf(modMessages.removeAll(activeContainer.getModId()));
    063            }
    064            return currentList;
    065        }
    066    }
    067
    068    /**
    069     * You will receive an instance of this for each message sent
    070     *
    071     * @author cpw
    072     *
    073     */
    074    public static final class IMCMessage {
    075        /**
    076         * This is the modid of the mod that sent you the message
    077         */
    078        private String sender;
    079        /**
    080         * This field, and {@link #value} are both at the mod's discretion
    081         */
    082        public final String key;
    083        /**
    084         * This field, and {@link #key} are both at the mod's discretion
    085         */
    086        private Object value;
    087
    088        private IMCMessage(String key, Object value)
    089        {
    090            this.key = key;
    091            this.value = value;
    092        }
    093
    094        @Override
    095        public String toString()
    096        {
    097            return sender;
    098        }
    099
    100        public String getSender()
    101        {
    102            return this.sender;
    103        }
    104
    105        void setSender(ModContainer activeModContainer)
    106        {
    107            this.sender = activeModContainer.getModId();
    108        }
    109
    110        public String getStringValue()
    111        {
    112            return (String) value;
    113        }
    114
    115        public NBTTagCompound getNBTValue()
    116        {
    117            return (NBTTagCompound) value;
    118        }
    119
    120        public ItemStack getItemStackValue()
    121        {
    122            return (ItemStack) value;
    123        }
    124
    125        public Class<?> getMessageType()
    126        {
    127            return value.getClass();
    128        }
    129
    130        public boolean isStringMessage()
    131        {
    132            return String.class.isAssignableFrom(getMessageType());
    133        }
    134
    135        public boolean isItemStackMessage()
    136        {
    137            return ItemStack.class.isAssignableFrom(getMessageType());
    138        }
    139
    140        public boolean isNBTMessage()
    141        {
    142            return NBTTagCompound.class.isAssignableFrom(getMessageType());
    143        }
    144    }
    145
    146    public static boolean sendMessage(String modId, String key, NBTTagCompound value)
    147    {
    148        return enqueueStartupMessage(modId, new IMCMessage(key, value));
    149    }
    150    public static boolean sendMessage(String modId, String key, ItemStack value)
    151    {
    152        return enqueueStartupMessage(modId, new IMCMessage(key, value));
    153    }
    154    public static boolean sendMessage(String modId, String key, String value)
    155    {
    156        return enqueueStartupMessage(modId, new IMCMessage(key, value));
    157    }
    158
    159    public static void sendRuntimeMessage(Object sourceMod, String modId, String key, NBTTagCompound value)
    160    {
    161        enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
    162    }
    163
    164    public static void sendRuntimeMessage(Object sourceMod, String modId, String key, ItemStack value)
    165    {
    166        enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
    167    }
    168
    169    public static void sendRuntimeMessage(Object sourceMod, String modId, String key, String value)
    170    {
    171        enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
    172    }
    173
    174    private static boolean enqueueStartupMessage(String modTarget, IMCMessage message)
    175    {
    176        if (Loader.instance().activeModContainer() == null)
    177        {
    178            return false;
    179        }
    180        enqueueMessage(Loader.instance().activeModContainer(), modTarget, message);
    181        return Loader.isModLoaded(modTarget) && !Loader.instance().hasReachedState(LoaderState.POSTINITIALIZATION);
    182
    183    }
    184    private static void enqueueMessage(Object sourceMod, String modTarget, IMCMessage message)
    185    {
    186        ModContainer mc;
    187        if (sourceMod instanceof ModContainer) {
    188            mc = (ModContainer) sourceMod;
    189        }
    190        else
    191        {
    192            mc = FMLCommonHandler.instance().findContainerFor(sourceMod);
    193        }
    194        if (mc != null && Loader.isModLoaded(modTarget))
    195        {
    196            message.setSender(mc);
    197            modMessages.put(modTarget, message);
    198        }
    199    }
    200
    201    /**
    202     * Retrieve any pending runtime messages for the mod
    203     * @param forMod The {@link Instance} of the Mod to fetch messages for
    204     * @return any messages - the collection will never be null
    205     */
    206    public static ImmutableList<IMCMessage> fetchRuntimeMessages(Object forMod)
    207    {
    208        ModContainer mc = FMLCommonHandler.instance().findContainerFor(forMod);
    209        if (mc != null)
    210        {
    211            return ImmutableList.copyOf(modMessages.removeAll(mc.getModId()));
    212        }
    213        else
    214        {
    215            return emptyIMCList;
    216        }
    217    }
    218}