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