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 }