001    package cpw.mods.fml.common.event;
002    
003    import java.util.List;
004    
005    import net.minecraft.item.ItemStack;
006    import net.minecraft.nbt.NBTTagCompound;
007    
008    import com.google.common.base.Function;
009    import com.google.common.base.Functions;
010    import com.google.common.base.Predicate;
011    import com.google.common.base.Predicates;
012    import com.google.common.collect.ArrayListMultimap;
013    import com.google.common.collect.FluentIterable;
014    import com.google.common.collect.ImmutableList;
015    import com.google.common.collect.ImmutableListMultimap;
016    import com.google.common.collect.Maps;
017    import com.google.common.collect.Multimaps;
018    
019    import cpw.mods.fml.common.FMLCommonHandler;
020    import cpw.mods.fml.common.FMLLog;
021    import cpw.mods.fml.common.Loader;
022    import cpw.mods.fml.common.LoaderState;
023    import cpw.mods.fml.common.Mod.Instance;
024    import cpw.mods.fml.common.ModContainer;
025    import cpw.mods.fml.common.Mod.Init;
026    import 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     */
035    public 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    }