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}