Introduce IContextSetter for events.

This will set the active mod container for events using the normal EventBus.
Fixes improper warnings from initializing mods using the new Registry events.
Modders, you should not use this as it has many performance implementations
and if abused will slow down the event bus A LOT. ActiveModContainer is not
thread safe.
This commit is contained in:
LexManos 2016-10-08 16:30:53 -07:00
parent c0db34796b
commit bc303074f6
6 changed files with 93 additions and 30 deletions

View File

@ -22,6 +22,7 @@ package net.minecraftforge.event;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.eventhandler.Event;
import net.minecraftforge.fml.common.eventhandler.GenericEvent;
import net.minecraftforge.fml.common.eventhandler.IContextSetter;
import net.minecraftforge.fml.common.registry.IForgeRegistry;
import net.minecraftforge.fml.common.registry.IForgeRegistryEntry;
import net.minecraftforge.fml.common.registry.PersistentRegistryManager;
@ -30,7 +31,7 @@ import net.minecraftforge.fml.common.registry.PersistentRegistryManager;
/**
* RegistryEvent supertype.
*/
public class RegistryEvent<T extends IForgeRegistryEntry<T>> extends GenericEvent<T>
public class RegistryEvent<T extends IForgeRegistryEntry<T>> extends GenericEvent<T> implements IContextSetter
{
RegistryEvent(Class<T> clazz) {
super(clazz);

View File

@ -22,6 +22,7 @@ package net.minecraftforge.fml.common;
import com.google.common.base.Strings;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.discovery.ASMDataTable;
import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData;
import net.minecraftforge.fml.common.discovery.asm.ModAnnotation;
import net.minecraftforge.fml.relauncher.Side;
import org.apache.logging.log4j.Level;
@ -50,6 +51,24 @@ public class AutomaticEventSubscriber
{
try
{
//Filter out handlers for things that arnt this mod.
//Perhaps find a way to make this more generic for multiple mods
//from the same source....
boolean register = true;
for (ASMData a : data.getAll(Mod.class.getName()))
{
if (a.getClassName().equals(targ.getClassName()))
{
if (!mod.getModId().equals(a.getAnnotationInfo().get("modid")))
{
register = false;
break;
}
}
}
if (!register)
continue;
//noinspection unchecked
List<ModAnnotation.EnumHolder> sidesEnum = (List<ModAnnotation.EnumHolder>)targ.getAnnotationInfo().get("value");
EnumSet<Side> sides = DEFAULT;

View File

@ -1144,4 +1144,9 @@ public class Loader
{
return modController != null ? modController.getState() : LoaderState.NOINIT;
}
public void setActiveModContainer(ModContainer container)
{
this.modController.forceActiveContainer(container);
}
}

View File

@ -122,15 +122,32 @@ public class EventBus implements IEventExceptionHandler
}
}
private void register(Class<?> eventType, Object target, Method method, ModContainer owner)
private void register(Class<?> eventType, Object target, Method method, final ModContainer owner)
{
try
{
Constructor<?> ctr = eventType.getConstructor();
ctr.setAccessible(true);
Event event = (Event)ctr.newInstance();
ASMEventHandler listener = new ASMEventHandler(target, method, owner, IGenericEvent.class.isAssignableFrom(eventType));
event.getListenerList().register(busID, listener.getPriority(), listener);
final ASMEventHandler asm = new ASMEventHandler(target, method, owner, IGenericEvent.class.isAssignableFrom(eventType));
IEventListener listener = asm;
if (IContextSetter.class.isAssignableFrom(eventType))
{
listener = new IEventListener()
{
@Override
public void invoke(Event event)
{
ModContainer old = Loader.instance().activeModContainer();
Loader.instance().setActiveModContainer(owner);
asm.invoke(event);
Loader.instance().setActiveModContainer(old);
}
};
}
event.getListenerList().register(busID, asm.getPriority(), listener);
ArrayList<IEventListener> others = listeners.get(target);
if (others == null)

View File

@ -0,0 +1,7 @@
package net.minecraftforge.fml.common.eventhandler;
//Instructs event handlers to set the active mod container.
//This has a major performance impact so use sparingly.
//Note: The context IS NOT thread aware as this would be ungodly slow.
//So This should ONLY be used for Forge mod lifecycle events.
public interface IContextSetter {}

View File

@ -5,25 +5,21 @@ import java.util.Map.Entry;
import net.minecraft.block.Block;
import net.minecraft.block.BlockWall;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.statemap.IStateMapper;
import net.minecraft.client.renderer.block.statemap.StateMap;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemMultiTexture;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IStringSerializable;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameData;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@ -31,21 +27,45 @@ import com.google.common.base.Function;
import com.google.common.collect.Maps;
@Mod(modid = ForgeBlockStatesLoaderDebug.MODID, name = "ForgeBlockStatesLoader", version = "1.0")
@Mod.EventBusSubscriber
public class ForgeBlockStatesLoaderDebug {
public static final String MODID = "forgeblockstatesloader";
public static final String ASSETS = "forgeblockstatesloader:";
//public static final Block blockCustom = new CustomMappedBlock();
public static final String nameCustomWall = "custom_wall";
public static final BlockWall blockCustomWall = new BlockWall(Blocks.COBBLESTONE);
public static final ItemMultiTexture itemCustomWall = (ItemMultiTexture)new ItemMultiTexture(blockCustomWall, blockCustomWall, new Function<ItemStack, String>()
@ObjectHolder(MODID)
public static class BLOCKS {
public static final BlockWall custom_wall = null;
}
@ObjectHolder(MODID)
public static class ITEMS {
public static final ItemMultiTexture custom_wall = null;
}
@SubscribeEvent
public static void registerBlocks(RegistryEvent.Register<Block> event)
{
@Override
public String apply(ItemStack stack)
{
return BlockWall.EnumType.byMetadata(stack.getMetadata()).getUnlocalizedName();
}
}).setRegistryName(nameCustomWall);
event.getRegistry().registerAll(
new BlockWall(Blocks.COBBLESTONE).setUnlocalizedName(MODID + ".customWall").setRegistryName(MODID, "custom_wall")
);
}
@SubscribeEvent
public static void registerItems(RegistryEvent.Register<Item> event)
{
event.getRegistry().registerAll(
new ItemMultiTexture(BLOCKS.custom_wall, BLOCKS.custom_wall, new Function<ItemStack, String>()
{
@Override
public String apply(ItemStack stack)
{
return BlockWall.EnumType.byMetadata(stack.getMetadata()).getUnlocalizedName();
}
}).setRegistryName(BLOCKS.custom_wall.getRegistryName())
);
}
//public static final Block blockCustom = new CustomMappedBlock();
@EventHandler
public void preInit(FMLPreInitializationEvent event)
@ -53,11 +73,6 @@ public class ForgeBlockStatesLoaderDebug {
//blockCustom.setUnlocalizedName(MODID + ".customBlock").setRegistryName("customBlock");
//GameRegistry.registerBlock(blockCustom);
blockCustomWall.setUnlocalizedName(MODID + ".customWall").setRegistryName(nameCustomWall);
GameRegistry.register(blockCustomWall);
GameRegistry.register(itemCustomWall);
GameData.getBlockItemMap().put(blockCustomWall, itemCustomWall);
if (event.getSide() == Side.CLIENT)
preInitClient(event);
}
@ -67,7 +82,7 @@ public class ForgeBlockStatesLoaderDebug {
{
//ModelLoader.setCustomStateMapper(blockCustom, new StateMap.Builder().withName(CustomMappedBlock.VARIANT).build());
ModelLoader.setCustomStateMapper(blockCustomWall, new IStateMapper()
ModelLoader.setCustomStateMapper(BLOCKS.custom_wall, new IStateMapper()
{
StateMap stateMap = new StateMap.Builder().withName(BlockWall.VARIANT).withSuffix("_wall").build();
@Override
@ -85,9 +100,8 @@ public class ForgeBlockStatesLoaderDebug {
return newMap;
}
});
Item customWallItem = Item.getItemFromBlock(blockCustomWall);
ModelLoader.setCustomModelResourceLocation(customWallItem, 0, new ModelResourceLocation(ASSETS + "cobblestone_wall", "inventory"));
ModelLoader.setCustomModelResourceLocation(customWallItem, 1, new ModelResourceLocation(ASSETS + "mossy_cobblestone_wall", "inventory"));
ModelLoader.setCustomModelResourceLocation(ITEMS.custom_wall, 0, new ModelResourceLocation(ASSETS + "cobblestone_wall", "inventory"));
ModelLoader.setCustomModelResourceLocation(ITEMS.custom_wall, 1, new ModelResourceLocation(ASSETS + "mossy_cobblestone_wall", "inventory"));
}
// this block is never actually used, it's only needed for the error message on load to see the variant it maps to