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