415 lines
14 KiB
Java
415 lines
14 KiB
Java
/*
|
|
* Minecraft Forge
|
|
* Copyright (c) 2016-2018.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
package net.minecraftforge.fml.common.event;
|
|
|
|
import java.util.function.Function;
|
|
import java.util.Optional;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.util.ResourceLocation;
|
|
import net.minecraftforge.fml.ModList;
|
|
import net.minecraftforge.fml.ModThreadContext;
|
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
|
import net.minecraftforge.fml.common.FMLLog;
|
|
import net.minecraftforge.fml.ModContainer;
|
|
import net.minecraftforge.fml.common.Mod.Instance;
|
|
|
|
import com.google.common.collect.ArrayListMultimap;
|
|
import com.google.common.collect.ImmutableList;
|
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
/**
|
|
* Simple intermod communications to receive simple messages directed at you
|
|
* from other mods
|
|
*
|
|
* @author cpw
|
|
*
|
|
*/
|
|
public class FMLInterModComms {
|
|
private static final ImmutableList<IMCMessage> emptyIMCList = ImmutableList.of();
|
|
private static ArrayListMultimap<String, IMCMessage> modMessages = ArrayListMultimap.create();
|
|
|
|
/**
|
|
* Subscribe to this event to receive your messages (they are sent between
|
|
* {@link FMLInitializationEvent} and {@link FMLPostInitializationEvent})
|
|
*
|
|
* @see net.minecraftforge.fml.common.Mod.EventHandler for how to subscribe to this event
|
|
* @author cpw
|
|
*/
|
|
public static class IMCEvent extends ModLifecycleEvent
|
|
{
|
|
private ModContainer activeContainer;
|
|
|
|
public IMCEvent()
|
|
{
|
|
super(activeContainer);
|
|
}
|
|
|
|
@Override
|
|
public void applyModContainer(ModContainer activeContainer)
|
|
{
|
|
this.activeContainer = activeContainer;
|
|
this.currentList = null;
|
|
FMLLog.log.trace("Attempting to deliver {} IMC messages to mod {}", modMessages.get(activeContainer.getModId()).size(), activeContainer.getModId());
|
|
}
|
|
|
|
private ImmutableList<IMCMessage> currentList;
|
|
|
|
public ImmutableList<IMCMessage> getMessages()
|
|
{
|
|
if (currentList == null)
|
|
{
|
|
currentList = ImmutableList.copyOf(modMessages.removeAll(activeContainer.getModId()));
|
|
}
|
|
return currentList;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* You will receive an instance of this for each message sent
|
|
*
|
|
* @author cpw
|
|
*
|
|
*/
|
|
public static final class IMCMessage {
|
|
private final boolean isFunction;
|
|
/**
|
|
* This is the modid of the mod that sent you the message
|
|
*/
|
|
private String sender;
|
|
/**
|
|
* This field, and {@link #value} are both at the mod's discretion
|
|
*/
|
|
@Nonnull
|
|
public final String key;
|
|
/**
|
|
* This field, and {@link #key} are both at the mod's discretion
|
|
*/
|
|
@Nonnull
|
|
private final Object value;
|
|
|
|
private IMCMessage(@Nonnull String key, @Nonnull Object value)
|
|
{
|
|
this.key = key;
|
|
this.value = value;
|
|
this.isFunction = false;
|
|
}
|
|
|
|
private IMCMessage(@Nonnull String key, @Nonnull String value, boolean isFunction) {
|
|
this.key = key;
|
|
this.value = value;
|
|
this.isFunction = isFunction;
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return sender;
|
|
}
|
|
|
|
/**
|
|
* Get the sending modId of this message.
|
|
* @return The modId of the mod that originated the message
|
|
*/
|
|
public String getSender()
|
|
{
|
|
return this.sender;
|
|
}
|
|
|
|
void setSender(ModContainer activeModContainer)
|
|
{
|
|
this.sender = activeModContainer.getModId();
|
|
}
|
|
|
|
/**
|
|
* Get the string value from this message.
|
|
* @throws ClassCastException if this message doesn't contain a String value
|
|
* @return The string value
|
|
*/
|
|
public String getStringValue()
|
|
{
|
|
return (String) value;
|
|
}
|
|
/**
|
|
* Get the ResourceLocation value from this message.
|
|
* @throws ClassCastException if this message doesn't contain a ResourceLocation value
|
|
* @return The string value
|
|
*/
|
|
public ResourceLocation getResourceLocationValue()
|
|
{
|
|
return (ResourceLocation) value;
|
|
}
|
|
|
|
/**
|
|
* Get the {@link NBTTagCompound} value from this message
|
|
* @throws ClassCastException if this message doesn't contain an NBT value
|
|
* @return The NBT value
|
|
*/
|
|
public NBTTagCompound getNBTValue()
|
|
{
|
|
return (NBTTagCompound) value;
|
|
}
|
|
|
|
/**
|
|
* Get the {@link ItemStack} value from this message
|
|
* @throws ClassCastException if this message doesn't contain an Itemstack value
|
|
* @return The Itemstack value
|
|
*/
|
|
@Nonnull
|
|
public ItemStack getItemStackValue()
|
|
{
|
|
return (ItemStack) value;
|
|
}
|
|
|
|
/**
|
|
* Get the {@link Function} value from this message. This will attempt to classload the function
|
|
* supplied by the caller. The parameter classes are strictly to give a concrete generic function return value.
|
|
* @param functionFrom The type of the argument to the function
|
|
* @param functionTo The type of the result of the function
|
|
* @param <T> The argument type
|
|
* @param <V> The result type
|
|
* @return The function value or Optional.absent if it wasn't readable or isn't a function call
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public <T,V> Optional<Function<T,V>> getFunctionValue(Class<T> functionFrom, Class<V> functionTo) {
|
|
if (!isFunction) {
|
|
return Optional.empty();
|
|
}
|
|
try {
|
|
Function<T,V> f = Class.forName((String) value).asSubclass(Function.class).newInstance();
|
|
return Optional.of(f);
|
|
} catch (Exception e) {
|
|
FMLLog.log.info("An error occurred instantiating the IMC function. key: {} value: {}, caller: {}", key,value,sender);
|
|
return Optional.empty();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the actual message class type
|
|
* @return The type of the message
|
|
*/
|
|
public Class<?> getMessageType()
|
|
{
|
|
return value.getClass();
|
|
}
|
|
|
|
/**
|
|
* Is this a string type message
|
|
* @return if this is a string type message
|
|
*/
|
|
public boolean isStringMessage()
|
|
{
|
|
return String.class.isAssignableFrom(getMessageType());
|
|
}
|
|
|
|
/**
|
|
* Is this an {@link ItemStack} type message
|
|
* @return if this is an itemstack type message
|
|
*/
|
|
public boolean isItemStackMessage()
|
|
{
|
|
return ItemStack.class.isAssignableFrom(getMessageType());
|
|
}
|
|
|
|
/**
|
|
* Is this an {@link NBTTagCompound} type message
|
|
* @return if this is an NBT type message
|
|
*/
|
|
public boolean isNBTMessage()
|
|
{
|
|
return NBTTagCompound.class.isAssignableFrom(getMessageType());
|
|
}
|
|
|
|
/**
|
|
* Is this an {@link ResourceLocation} type message
|
|
* @return if this is an NBT type message
|
|
*/
|
|
public boolean isResourceLocationMessage()
|
|
{
|
|
return ResourceLocation.class.isAssignableFrom(getMessageType());
|
|
}
|
|
|
|
/**
|
|
* Is this a {@link Function} type message
|
|
* @return if this is a function type message
|
|
*/
|
|
public boolean isFunctionMessage() { return Function.class.isAssignableFrom(getMessageType()); }
|
|
}
|
|
|
|
/**
|
|
* Send a startup time message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param value An NBT type value
|
|
* @return if the message was enqueued successfully and will be processed during startup
|
|
*/
|
|
public static boolean sendMessage(String modId, String key, NBTTagCompound value)
|
|
{
|
|
return enqueueStartupMessage(modId, new IMCMessage(key, value));
|
|
}
|
|
|
|
/**
|
|
* Send a startup time message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param value An Itemstack value
|
|
* @return if the message was enqueued successfully and will be processed during startup
|
|
*/
|
|
public static boolean sendMessage(String modId, String key, ItemStack value)
|
|
{
|
|
return enqueueStartupMessage(modId, new IMCMessage(key, value));
|
|
}
|
|
|
|
/**
|
|
* Send a startup time message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param value A ResourceLocation value
|
|
* @return if the message was enqueued successfully and will be processed during startup
|
|
*/
|
|
public static boolean sendMessage(String modId, String key, ResourceLocation value)
|
|
{
|
|
return enqueueStartupMessage(modId, new IMCMessage(key, value));
|
|
}
|
|
|
|
/**
|
|
* Send a startup time message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param value A String value
|
|
* @return if the message was enqueued successfully and will be processed during startup
|
|
*/
|
|
public static boolean sendMessage(String modId, String key, String value)
|
|
{
|
|
return enqueueStartupMessage(modId, new IMCMessage(key, value));
|
|
}
|
|
/**
|
|
* Send a startup time function message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param functionClassName The class name of a function that will be instantiated when the
|
|
* message is read. It must implement {@link Function}
|
|
* @return if the message was enqueued successfully and will be processed during startup
|
|
*/
|
|
public static boolean sendFunctionMessage(String modId, String key, String functionClassName)
|
|
{
|
|
return enqueueStartupMessage(modId, new IMCMessage(key, functionClassName, true));
|
|
}
|
|
|
|
/**
|
|
* Send a post-startup message
|
|
* @param sourceMod The mod sending the message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param value An NBT type value
|
|
*/
|
|
public static void sendRuntimeMessage(Object sourceMod, String modId, String key, NBTTagCompound value)
|
|
{
|
|
enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
|
|
}
|
|
|
|
/**
|
|
* Send a post-startup message
|
|
* @param sourceMod The mod sending the message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param value An Itemstack value
|
|
*/
|
|
public static void sendRuntimeMessage(Object sourceMod, String modId, String key, ItemStack value)
|
|
{
|
|
enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
|
|
}
|
|
|
|
/**
|
|
* Send a post-startup message
|
|
* @param sourceMod The mod sending the message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param value A string value
|
|
*/
|
|
public static void sendRuntimeMessage(Object sourceMod, String modId, String key, String value)
|
|
{
|
|
enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
|
|
}
|
|
|
|
/**
|
|
* Send a post-startup message
|
|
* @param sourceMod The mod sending the message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param value A string value
|
|
*/
|
|
public static void sendRuntimeMessage(Object sourceMod, String modId, String key, ResourceLocation value)
|
|
{
|
|
enqueueMessage(sourceMod, modId, new IMCMessage(key, value));
|
|
}
|
|
/**
|
|
* Send a post-startup function message.
|
|
*
|
|
* @param sourceMod The mod originating this message
|
|
* @param modId The modid to send it to
|
|
* @param key The mod specific key
|
|
* @param functionClassName The name of a class to be loaded when the caller processes this message.
|
|
* The named class must extend {@link Function}
|
|
*/
|
|
public static void sendRuntimeFunctionMessage(Object sourceMod, String modId, String key, String functionClassName)
|
|
{
|
|
enqueueMessage(sourceMod, modId, new IMCMessage(key, functionClassName, true));
|
|
}
|
|
|
|
private static boolean enqueueStartupMessage(String modTarget, IMCMessage message)
|
|
{
|
|
if (ModThreadContext.get().getActiveContainer() == null)
|
|
{
|
|
return false;
|
|
}
|
|
enqueueMessage(ModThreadContext.get().getActiveContainer(), modTarget, message);
|
|
return ModList.get().isLoaded(modTarget);
|
|
|
|
}
|
|
private static void enqueueMessage(ModContainer sourceMod, String modTarget, IMCMessage message)
|
|
{
|
|
if (ModList.get().isLoaded(modTarget))
|
|
{
|
|
message.setSender(sourceMod);
|
|
modMessages.put(modTarget, message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve any pending runtime messages for the mod
|
|
* @param forMod The {@link Instance} of the Mod to fetch messages for
|
|
* @return any messages - the collection will never be null
|
|
*/
|
|
public static ImmutableList<IMCMessage> fetchRuntimeMessages(Object forMod)
|
|
{
|
|
ModContainer mc = FMLCommonHandler.instance().findContainerFor(forMod);
|
|
if (mc != null)
|
|
{
|
|
return ImmutableList.copyOf(modMessages.removeAll(mc.getModId()));
|
|
}
|
|
else
|
|
{
|
|
return emptyIMCList;
|
|
}
|
|
}
|
|
}
|