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 }