Add RegisterCapabilitiesEvent (#8021)

This commit is contained in:
Take Weiland authored and GitHub committed 2021-08-20 12:38:43 -07:00
1 parent d612dc3a6d
commit aa97ddad8b
7 files changed
+112 -31

No files matched your search

@@ -33,6 +33,7 @@ import net.minecraft.world.level.storage.WorldData;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.common.data.ForgeFluidTagsProvider;
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
@@ -150,6 +151,7 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
WorldPersistenceHooks.addHook(this);
WorldPersistenceHooks.addHook(new FMLWorldPersistenceHook());
final IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(this::registerCapabilities);
modEventBus.addListener(this::preInit);
modEventBus.addListener(this::gatherData);
modEventBus.addListener(this::loadComplete);
@@ -171,13 +173,16 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
BiomeDictionary.init();
}
public void registerCapabilities(RegisterCapabilitiesEvent event)
{
CapabilityItemHandler.register(event);
CapabilityFluidHandler.register(event);
CapabilityAnimation.register(event);
CapabilityEnergy.register(event);
}
public void preInit(FMLCommonSetupEvent evt)
{
CapabilityItemHandler.register();
CapabilityFluidHandler.register();
CapabilityAnimation.register();
CapabilityEnergy.register();
VersionChecker.startVersionCheck();
registerArgumentTypes();
@@ -24,12 +24,12 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.forgespi.language.ModFileScanData;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -43,7 +43,7 @@ import static net.minecraftforge.fml.Logging.CAPABILITIES;
public enum CapabilityManager
{
INSTANCE;
private static final Logger LOGGER = LogManager.getLogger();
static final Logger LOGGER = LogManager.getLogger();
private static final Type CAP_INJECT = Type.getType(CapabilityInject.class);
/**
@@ -53,7 +53,9 @@ public enum CapabilityManager
* This method is safe to call during parallel mod loading.
*
* @param type The class type to be registered
* @deprecated use {@link RegisterCapabilitiesEvent}
*/
@Deprecated(forRemoval = true)
public <T> void register(Class<T> type)
{
Objects.requireNonNull(type,"Attempted to register a capability with invalid type");
@@ -71,7 +73,7 @@ public enum CapabilityManager
providers.put(realName, cap);
}
callbacks.getOrDefault(realName, Collections.emptyList()).forEach(func -> func.apply(cap));
fireCallbacks(this.callbacks, List.of(cap));
}
// INTERNAL
@@ -79,21 +81,36 @@ public enum CapabilityManager
private volatile IdentityHashMap<String, List<Function<Capability<?>, Object>>> callbacks;
public void injectCapabilities(List<ModFileScanData> data)
{
final List<ModFileScanData.AnnotationData> capabilities = data.stream()
final List<ModFileScanData.AnnotationData> elementsToInject = data.stream()
.map(ModFileScanData::getAnnotations)
.flatMap(Collection::stream)
.filter(a -> CAP_INJECT.equals(a.annotationType()))
.collect(Collectors.toList());
final IdentityHashMap<String, List<Function<Capability<?>, Object>>> m = new IdentityHashMap<>();
capabilities.forEach(entry -> attachCapabilityToMethod(m, entry));
callbacks = m;
final IdentityHashMap<String, List<Function<Capability<?>, Object>>> callbacks = new IdentityHashMap<>();
elementsToInject.forEach(entry -> gatherCallbacks(callbacks, entry));
var event = new RegisterCapabilitiesEvent();
ModLoader.get().postEvent(event);
fireCallbacks(callbacks, event.getCapabilities().values());
// TODO 1.18: remove these fields
this.providers.putAll(event.getCapabilities());
this.callbacks = callbacks;
}
private static void attachCapabilityToMethod(Map<String, List<Function<Capability<?>, Object>>> cbs, ModFileScanData.AnnotationData entry)
private static void fireCallbacks(Map<String, List<Function<Capability<?>, Object>>> callbacks, Iterable<Capability<?>> caps)
{
final String targetClass = entry.clazz().getClassName();
final String targetName = entry.memberName();
Type type = (Type)entry.annotationData().get("value");
for (var cap : caps)
{
callbacks.getOrDefault(cap.getName(), List.of()).forEach(f -> f.apply(cap));
}
}
private static void gatherCallbacks(Map<String, List<Function<Capability<?>, Object>>> callbacks, ModFileScanData.AnnotationData annotationData)
{
final String targetClass = annotationData.clazz().getClassName();
final String targetName = annotationData.memberName();
Type type = (Type)annotationData.annotationData().get("value");
if (type == null)
{
LOGGER.warn(CAPABILITIES,"Unable to inject capability at {}.{} (Invalid Annotation)", targetClass, targetName);
@@ -101,9 +118,9 @@ public enum CapabilityManager
}
final String capabilityName = type.getInternalName().replace('/', '.').intern();
List<Function<Capability<?>, Object>> list = cbs.computeIfAbsent(capabilityName, k -> new ArrayList<>());
List<Function<Capability<?>, Object>> list = callbacks.computeIfAbsent(capabilityName, k -> new ArrayList<>());
if (entry.memberName().indexOf('(') > 0)
if (annotationData.memberName().indexOf('(') > 0)
{
list.add(input -> {
try
@@ -0,0 +1,60 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2021.
*
* 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.common.capabilities;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import java.util.*;
import static net.minecraftforge.fml.Logging.CAPABILITIES;
/**
* This event fires when it is time to register your capabilities.
* @see Capability
*/
public final class RegisterCapabilitiesEvent extends Event implements IModBusEvent
{
private final IdentityHashMap<String, Capability<?>> capabilities = new IdentityHashMap<>();
/**
* Registers a capability to be consumed by others.
* APIs who define the capability should call this.
* To retrieve the Capability instance, use the @CapabilityInject annotation.
*
* @param type The type to be registered
*/
public <T> void register(Class<T> type)
{
Objects.requireNonNull(type,"Attempted to register a capability with invalid type");
String realName = type.getName().intern();
if (capabilities.putIfAbsent(realName, new Capability<>(realName)) != null) {
CapabilityManager.LOGGER.error(CAPABILITIES, "Cannot register capability implementation multiple times : {}", realName);
throw new IllegalArgumentException("Cannot register a capability implementation multiple times : "+ realName);
}
}
IdentityHashMap<String, Capability<?>> getCapabilities()
{
return this.capabilities;
}
}
@@ -19,11 +19,10 @@
package net.minecraftforge.common.model.animation;
import net.minecraft.nbt.Tag;
import net.minecraft.core.Direction;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
@@ -35,9 +34,9 @@ public class CapabilityAnimation
@CapabilityInject(IAnimationStateMachine.class)
public static Capability<IAnimationStateMachine> ANIMATION_CAPABILITY = null;
public static void register()
public static void register(RegisterCapabilitiesEvent event)
{
CapabilityManager.INSTANCE.register(IAnimationStateMachine.class);
event.register(IAnimationStateMachine.class);
}
public static class DefaultItemAnimationCapabilityProvider implements ICapabilityProvider
@@ -26,8 +26,8 @@ public class CapabilityEnergy
@CapabilityInject(IEnergyStorage.class)
public static Capability<IEnergyStorage> ENERGY = null;
public static void register()
public static void register(RegisterCapabilitiesEvent event)
{
CapabilityManager.INSTANCE.register(IEnergyStorage.class);
event.register(IEnergyStorage.class);
}
}
@@ -21,7 +21,7 @@ package net.minecraftforge.fluids.capability;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
public class CapabilityFluidHandler
{
@@ -30,10 +30,10 @@ public class CapabilityFluidHandler
@CapabilityInject(IFluidHandlerItem.class)
public static Capability<IFluidHandlerItem> FLUID_HANDLER_ITEM_CAPABILITY = null;
public static void register()
public static void register(RegisterCapabilitiesEvent event)
{
CapabilityManager.INSTANCE.register(IFluidHandler.class);
event.register(IFluidHandler.class);
CapabilityManager.INSTANCE.register(IFluidHandlerItem.class);
event.register(IFluidHandlerItem.class);
}
}
@@ -21,16 +21,16 @@ package net.minecraftforge.items;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
public class CapabilityItemHandler
{
@CapabilityInject(IItemHandler.class)
public static Capability<IItemHandler> ITEM_HANDLER_CAPABILITY = null;
public static void register()
public static void register(RegisterCapabilitiesEvent event)
{
CapabilityManager.INSTANCE.register(IItemHandler.class);
event.register(IItemHandler.class);
}
}