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        @Override
048        public void applyModContainer(ModContainer activeContainer)
049        {
050            currentList = ImmutableList.copyOf(modMessages.removeAll(activeContainer.getModId()));
051            FMLLog.finest("Attempting to deliver %d IMC messages to mod %s", currentList.size(), activeContainer.getModId());
052        }
053
054        private ImmutableList<IMCMessage> currentList;
055
056        public ImmutableList<IMCMessage> getMessages()
057        {
058            return currentList;
059        }
060    }
061
062    /**
063     * You will receive an instance of this for each message sent
064     *
065     * @author cpw
066     *
067     */
068    public static final class IMCMessage {
069        /**
070         * This is the modid of the mod that sent you the message
071         */
072        private String sender;
073        /**
074         * This field, and {@link #value} are both at the mod's discretion
075         */
076        public final String key;
077        /**
078         * This field, and {@link #key} are both at the mod's discretion
079         */
080        private Object value;
081
082        private IMCMessage(String key, Object value)
083        {
084            this.key = key;
085            this.value = value;
086        }
087
088        @Override
089        public String toString()
090        {
091            return sender;
092        }
093
094        public String getSender()
095        {
096            return this.sender;
097        }
098
099        void setSender(ModContainer activeModContainer)
100        {
101            this.sender = activeModContainer.getModId();
102        }
103
104        public String getStringValue()
105        {
106            return (String) value;
107        }
108
109        public NBTTagCompound getNBTValue()
110        {
111            return (NBTTagCompound) value;
112        }
113
114        public ItemStack getItemStackValue()
115        {
116            return (ItemStack) value;
117        }
118
119        public Class<?> getMessageType()
120        {
121            return value.getClass();
122        }
123
124        public boolean isStringMessage()
125        {
126            return String.class.isAssignableFrom(getMessageType());
127        }
128
129        public boolean isItemStackMessage()
130        {
131            return ItemStack.class.isAssignableFrom(getMessageType());
132        }
133
134        public boolean isNBTMessage()
135        {
136            return NBTTagCompound.class.isAssignableFrom(getMessageType());
137        }
138    }
139
140    public static boolean sendMessage(String modId, String key, NBTTagCompound value)
141    {
142        return enqueueStartupMessage(modId, new IMCMessage(key, value));
143    }
144    public static boolean sendMessage(String modId, String key, ItemStack value)
145    {
146        return enqueueStartupMessage(modId, new IMCMessage(key, value));
147    }
148    public static boolean sendMessage(String modId, String key, String value)
149    {
150        return enqueueStartupMessage(modId, new IMCMessage(key, value));
151    }
152
153    public static void sendRuntimeMessage(Object sourceMod, String modId, String key, NBTTagCompound value)
154    {
155        enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
156    }
157
158    public static void sendRuntimeMessage(Object sourceMod, String modId, String key, ItemStack value)
159    {
160        enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
161    }
162
163    public static void sendRuntimeMessage(Object sourceMod, String modId, String key, String value)
164    {
165        enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
166    }
167
168    private static boolean enqueueStartupMessage(String modTarget, IMCMessage message)
169    {
170        if (Loader.instance().activeModContainer() == null)
171        {
172            return false;
173        }
174        enqueueMessage(Loader.instance().activeModContainer(), modTarget, message);
175        return Loader.isModLoaded(modTarget) && !Loader.instance().hasReachedState(LoaderState.POSTINITIALIZATION);
176
177    }
178    private static void enqueueMessage(Object sourceMod, String modTarget, IMCMessage message)
179    {
180        ModContainer mc;
181        if (sourceMod instanceof ModContainer) {
182            mc = (ModContainer) sourceMod;
183        }
184        else
185        {
186            mc = FMLCommonHandler.instance().findContainerFor(sourceMod);
187        }
188        if (mc != null && Loader.isModLoaded(modTarget))
189        {
190            message.setSender(mc);
191            modMessages.put(modTarget, message);
192        }
193    }
194
195    /**
196     * Retrieve any pending runtime messages for the mod
197     * @param forMod The {@link Instance} of the Mod to fetch messages for
198     * @return any messages - the collection will never be null
199     */
200    public static ImmutableList<IMCMessage> fetchRuntimeMessages(Object forMod)
201    {
202        ModContainer mc = FMLCommonHandler.instance().findContainerFor(forMod);
203        if (mc != null)
204        {
205            return ImmutableList.copyOf(modMessages.removeAll(mc));
206        }
207        else
208        {
209            return emptyIMCList;
210        }
211    }
212}