diff --git a/src/main/java/net/minecraftforge/client/event/ModelRegistryEvent.java b/src/main/java/net/minecraftforge/client/event/ModelRegistryEvent.java new file mode 100644 index 0000000000..b14025cebe --- /dev/null +++ b/src/main/java/net/minecraftforge/client/event/ModelRegistryEvent.java @@ -0,0 +1,29 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * 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.client.event; + +import net.minecraftforge.fml.common.eventhandler.Event; + +/** + * Fired when the {@link net.minecraftforge.client.model.ModelLoader} is ready to receive registrations + */ +public class ModelRegistryEvent extends Event +{ +} diff --git a/src/main/java/net/minecraftforge/event/RegistryEvent.java b/src/main/java/net/minecraftforge/event/RegistryEvent.java new file mode 100644 index 0000000000..a1967e5b7d --- /dev/null +++ b/src/main/java/net/minecraftforge/event/RegistryEvent.java @@ -0,0 +1,77 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * 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.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.registry.IForgeRegistry; +import net.minecraftforge.fml.common.registry.IForgeRegistryEntry; +import net.minecraftforge.fml.common.registry.PersistentRegistryManager; + + +/** + * RegistryEvent supertype. + */ +public class RegistryEvent> extends GenericEvent +{ + RegistryEvent(Class clazz) { + super(clazz); + } + /** + * Register new registries when you receive this event, through the {@link PersistentRegistryManager} + */ + public static class NewRegistry extends Event { + } + + /** + * Register your objects for the appropriate registry type when you receive this event. + * + * event.getRegistry().register(...) + * + * The registries will be visited in alphabetic order of their name, except blocks and items, + * which will be visited FIRST and SECOND respectively. + * + * ObjectHolders will reload between Blocks and Items, and after all registries have been visited. + * @param The registry top level type + */ + public static class Register> extends RegistryEvent { + private final IForgeRegistry registry; + private final ResourceLocation location; + + public Register(ResourceLocation location, IForgeRegistry registry) + { + super(registry.getRegistrySuperType()); + this.location = location; + this.registry = registry; + } + + public IForgeRegistry getRegistry() + { + return registry; + } + + public ResourceLocation getLocation() + { + return location; + } + + } +} diff --git a/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java b/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java index b468546d3a..9bb217cfb8 100644 --- a/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java +++ b/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java @@ -76,7 +76,9 @@ import net.minecraft.util.StringUtils; import net.minecraft.world.WorldSettings; import net.minecraft.world.storage.WorldSummary; import net.minecraft.world.storage.SaveFormatOld; +import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.common.ForgeModContainer; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.DummyModContainer; import net.minecraftforge.fml.common.DuplicateModsFoundException; @@ -1038,4 +1040,10 @@ public class FMLClientHandler implements IFMLSidedHandler { this.client.renderGlobal.loadRenderers(); } + + @Override + public void fireSidedRegistryEvents() + { + MinecraftForge.EVENT_BUS.post(new ModelRegistryEvent()); + } } diff --git a/src/main/java/net/minecraftforge/fml/common/AutomaticEventSubscriber.java b/src/main/java/net/minecraftforge/fml/common/AutomaticEventSubscriber.java new file mode 100644 index 0000000000..81df043008 --- /dev/null +++ b/src/main/java/net/minecraftforge/fml/common/AutomaticEventSubscriber.java @@ -0,0 +1,77 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * 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; + +import com.google.common.base.Strings; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.discovery.ASMDataTable; +import net.minecraftforge.fml.common.discovery.asm.ModAnnotation; +import net.minecraftforge.fml.relauncher.Side; +import org.apache.logging.log4j.Level; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +/** + * Automatic eventbus subscriber - reads {@link net.minecraftforge.fml.common.Mod.EventBusSubscriber} + * annotations and passes the class instances to the {@link net.minecraftforge.common.MinecraftForge.EVENT_BUS} + */ +public class AutomaticEventSubscriber +{ + private static final EnumSet DEFAULT = EnumSet.allOf(Side.class); + public static void inject(ModContainer mod, ASMDataTable data, Side side) + { + FMLLog.fine("Attempting to inject @EventBusSubscriber classes into the eventbus for %s", mod.getModId()); + Set targets = data.getAnnotationsFor(mod).get(Mod.EventBusSubscriber.class.getName()); + ClassLoader mcl = Loader.instance().getModClassLoader(); + + for (ASMDataTable.ASMData targ : targets) + { + try + { + //noinspection unchecked + List sidesEnum = (List)targ.getAnnotationInfo().get("value"); + EnumSet sides = DEFAULT; + if (sidesEnum != null) { + sides = EnumSet.noneOf(Side.class); + for (ModAnnotation.EnumHolder h: sidesEnum) { + sides.add(Side.valueOf(h.getValue())); + } + } + if (sides == DEFAULT || sides.contains(side)) { + FMLLog.fine("Found @EventBusSubscriber class %s", targ.getClassName()); + Class subscriptionTarget = Class.forName(targ.getClassName(), true, mcl); + MinecraftForge.EVENT_BUS.register(subscriptionTarget); + FMLLog.fine("Injected @EventBusSubscriber class %s", targ.getClassName()); + } + } + catch (Exception e) + { + FMLLog.log(Level.ERROR, e, "An error occurred trying to load an EventBusSubscriber %s for modid %s", targ.getClassName(), mod.getModId()); + throw new LoaderException(e); + } + } + } + +} diff --git a/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java b/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java index 085a619cbc..e16cd3709a 100644 --- a/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java +++ b/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java @@ -746,4 +746,9 @@ public class FMLCommonHandler public void reloadRenderers() { sidedDelegate.reloadRenderers(); } + + public void fireSidedRegistryEvents() + { + sidedDelegate.fireSidedRegistryEvents(); + } } diff --git a/src/main/java/net/minecraftforge/fml/common/FMLModContainer.java b/src/main/java/net/minecraftforge/fml/common/FMLModContainer.java index 6dac654db1..ac424bfc97 100644 --- a/src/main/java/net/minecraftforge/fml/common/FMLModContainer.java +++ b/src/main/java/net/minecraftforge/fml/common/FMLModContainer.java @@ -573,6 +573,8 @@ public class FMLModContainer implements ModContainer eventBus.post(new FMLFingerprintViolationEvent(source.isDirectory(), source, ImmutableSet.copyOf(this.sourceFingerprints), expectedFingerprint)); } ProxyInjector.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide(), getLanguageAdapter()); + AutomaticEventSubscriber.inject(this, event.getASMHarvestedData(), FMLCommonHandler.instance().getSide()); + processFieldAnnotations(event.getASMHarvestedData()); } catch (Throwable e) diff --git a/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java b/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java index 4c49ed11de..aea07ffcda 100644 --- a/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java +++ b/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java @@ -75,4 +75,6 @@ public interface IFMLSidedHandler String stripSpecialChars(String message); void reloadRenderers(); + + void fireSidedRegistryEvents(); } diff --git a/src/main/java/net/minecraftforge/fml/common/Loader.java b/src/main/java/net/minecraftforge/fml/common/Loader.java index 82bcd17dce..3f43f781d7 100644 --- a/src/main/java/net/minecraftforge/fml/common/Loader.java +++ b/src/main/java/net/minecraftforge/fml/common/Loader.java @@ -604,6 +604,8 @@ public class Loader ObjectHolderRegistry.INSTANCE.findObjectHolders(discoverer.getASMTable()); ItemStackHolderInjector.INSTANCE.findHolders(discoverer.getASMTable()); CapabilityManager.INSTANCE.injectCapabilities(discoverer.getASMTable()); + PersistentRegistryManager.fireRegistryEvents(); + FMLCommonHandler.instance().fireSidedRegistryEvents(); modController.distributeStateMessage(LoaderState.PREINITIALIZATION, discoverer.getASMTable(), canonicalConfigDir); ObjectHolderRegistry.INSTANCE.applyObjectHolders(); ItemStackHolderInjector.INSTANCE.inject(); diff --git a/src/main/java/net/minecraftforge/fml/common/Mod.java b/src/main/java/net/minecraftforge/fml/common/Mod.java index 47ba5e57eb..24afe9d334 100644 --- a/src/main/java/net/minecraftforge/fml/common/Mod.java +++ b/src/main/java/net/minecraftforge/fml/common/Mod.java @@ -39,6 +39,7 @@ import net.minecraftforge.fml.common.event.FMLServerStoppingEvent; import net.minecraftforge.fml.common.event.FMLInterModComms.IMCEvent; import net.minecraftforge.fml.common.network.NetworkCheckHandler; import net.minecraftforge.fml.common.registry.GameRegistry; +import net.minecraftforge.fml.relauncher.Side; /** * This defines a Mod to FML. @@ -305,4 +306,13 @@ public @interface Mod @Target(ElementType.METHOD) public @interface InstanceFactory { } + + /** + * A class which will be subscribed to {@link net.minecraftforge.common.MinecraftForge.EVENT_BUS} at mod construction time. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface EventBusSubscriber { + Side[] value() default { Side.CLIENT, Side.SERVER }; + } } diff --git a/src/main/java/net/minecraftforge/fml/common/eventhandler/ASMEventHandler.java b/src/main/java/net/minecraftforge/fml/common/eventhandler/ASMEventHandler.java index 9394b4191e..412aab6f88 100644 --- a/src/main/java/net/minecraftforge/fml/common/eventhandler/ASMEventHandler.java +++ b/src/main/java/net/minecraftforge/fml/common/eventhandler/ASMEventHandler.java @@ -68,11 +68,9 @@ public class ASMEventHandler implements IEventListener if (isGeneric) { java.lang.reflect.Type type = method.getGenericParameterTypes()[0]; - System.currentTimeMillis(); if (type instanceof ParameterizedType) { filter = ((ParameterizedType)type).getActualTypeArguments()[0]; - System.currentTimeMillis(); } } } diff --git a/src/main/java/net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry.java b/src/main/java/net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry.java index e63b5bbad3..d9d621b5be 100644 --- a/src/main/java/net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry.java +++ b/src/main/java/net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry.java @@ -36,6 +36,7 @@ import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import net.minecraftforge.event.RegistryEvent; import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.Level; @@ -830,6 +831,13 @@ public class FMLControlledNamespacedRegistry> e add(-1, key, value); } + public void registerAll(I... values) + { + for (I value: values) + { + register(value); + } + } @Override public boolean containsValue(I value) { @@ -908,4 +916,10 @@ public class FMLControlledNamespacedRegistry> e { return (T)slaves.get(slaveMapName); } + + RegistryEvent.Register buildRegistryRegisterEvent(ResourceLocation location) + { + return new RegistryEvent.Register(location, this); + } + } diff --git a/src/main/java/net/minecraftforge/fml/common/registry/IForgeRegistry.java b/src/main/java/net/minecraftforge/fml/common/registry/IForgeRegistry.java index 54863649bb..3d52bb2a26 100644 --- a/src/main/java/net/minecraftforge/fml/common/registry/IForgeRegistry.java +++ b/src/main/java/net/minecraftforge/fml/common/registry/IForgeRegistry.java @@ -39,6 +39,8 @@ public interface IForgeRegistry> extends Iterab void register(V value); + void registerAll(V... values); + boolean containsKey(ResourceLocation key); boolean containsValue(V value); diff --git a/src/main/java/net/minecraftforge/fml/common/registry/IForgeRegistryEntry.java b/src/main/java/net/minecraftforge/fml/common/registry/IForgeRegistryEntry.java index 87f043aa38..919f803a21 100644 --- a/src/main/java/net/minecraftforge/fml/common/registry/IForgeRegistryEntry.java +++ b/src/main/java/net/minecraftforge/fml/common/registry/IForgeRegistryEntry.java @@ -89,7 +89,6 @@ public interface IForgeRegistryEntry //Helper functions public final T setRegistryName(ResourceLocation name){ return setRegistryName(name.toString()); } public final T setRegistryName(String modID, String name){ return setRegistryName(modID + ":" + name); } - public final ResourceLocation getRegistryName() { if (delegate.name() != null) return delegate.name(); diff --git a/src/main/java/net/minecraftforge/fml/common/registry/PersistentRegistryManager.java b/src/main/java/net/minecraftforge/fml/common/registry/PersistentRegistryManager.java index 9c7a8aabd8..71010a3480 100644 --- a/src/main/java/net/minecraftforge/fml/common/registry/PersistentRegistryManager.java +++ b/src/main/java/net/minecraftforge/fml/common/registry/PersistentRegistryManager.java @@ -20,8 +20,9 @@ package net.minecraftforge.fml.common.registry; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -33,6 +34,8 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockAir; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.EnhancedRuntimeException; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.FMLLog; @@ -64,6 +67,35 @@ import com.google.common.collect.Sets.SetView; @SuppressWarnings("WeakerAccess") public class PersistentRegistryManager { + public static void fireRegistryEvents() + { + MinecraftForge.EVENT_BUS.post(new RegistryEvent.NewRegistry()); + + List registryKeys = Lists.newArrayList(PersistentRegistry.ACTIVE.registries.keySet()); + Collections.sort(registryKeys, new Comparator() + { + @Override + public int compare(ResourceLocation o1, ResourceLocation o2) + { + return o1.toString().compareToIgnoreCase(o2.toString()); + } + }); + fireRegistryEvent(PersistentRegistry.ACTIVE.registries, BLOCKS); + ObjectHolderRegistry.INSTANCE.applyObjectHolders(); // inject any blocks + fireRegistryEvent(PersistentRegistry.ACTIVE.registries, ITEMS); + ObjectHolderRegistry.INSTANCE.applyObjectHolders(); // inject any items + for (ResourceLocation rl : registryKeys) { + if (rl == BLOCKS || rl == ITEMS) continue; + fireRegistryEvent(PersistentRegistry.ACTIVE.registries, rl); + } + ObjectHolderRegistry.INSTANCE.applyObjectHolders(); // inject everything else + } + private static void fireRegistryEvent(BiMap> registries, ResourceLocation name) + { + final RegistryEvent.Register event = registries.get(name).buildRegistryRegisterEvent(name); + MinecraftForge.EVENT_BUS.post(event); + } + enum PersistentRegistry { ACTIVE, VANILLA, FROZEN, STAGING; diff --git a/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java b/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java index cb1b4c6330..54c25b1f45 100644 --- a/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java +++ b/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java @@ -332,6 +332,11 @@ public class FMLServerHandler implements IFMLSidedHandler @Override public void reloadRenderers() { // NOOP + } + @Override + public void fireSidedRegistryEvents() + { + // NOOP } }