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}