Deduplicate capability provider lists
This commit is contained in:
parent
ad6425f7e9
commit
6eb82e1325
|
|
@ -0,0 +1,91 @@
|
|||
package org.embeddedt.modernfix.neoforge.caps;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.neoforged.neoforge.capabilities.BaseCapability;
|
||||
import net.neoforged.neoforge.capabilities.BlockCapability;
|
||||
import net.neoforged.neoforge.capabilities.EntityCapability;
|
||||
import net.neoforged.neoforge.capabilities.ICapabilityProvider;
|
||||
import net.neoforged.neoforge.capabilities.ItemCapability;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CapProviderGetter {
|
||||
private static final MethodHandle BLOCK_CAP_PROVIDERS, ITEM_CAP_PROVIDERS, ENTITY_CAP_PROVIDERS;
|
||||
private static final boolean FOUND_PROVIDERS;
|
||||
|
||||
static {
|
||||
MethodHandle bProvider, iProvider, eProvider;
|
||||
boolean found;
|
||||
try {
|
||||
bProvider = obtainForClass(BlockCapability.class);
|
||||
iProvider = obtainForClass(ItemCapability.class);
|
||||
eProvider = obtainForClass(EntityCapability.class);
|
||||
found = true;
|
||||
} catch(ReflectiveOperationException e) {
|
||||
e.printStackTrace();
|
||||
bProvider = null;
|
||||
iProvider = null;
|
||||
eProvider = null;
|
||||
found = false;
|
||||
}
|
||||
BLOCK_CAP_PROVIDERS = bProvider;
|
||||
ITEM_CAP_PROVIDERS = iProvider;
|
||||
ENTITY_CAP_PROVIDERS = eProvider;
|
||||
FOUND_PROVIDERS = found;
|
||||
}
|
||||
|
||||
private static MethodHandle obtainForClass(Class<? extends BaseCapability> clz) throws ReflectiveOperationException{
|
||||
Field field = clz.getDeclaredField("providers");
|
||||
field.setAccessible(true);
|
||||
return MethodHandles.publicLookup().unreflectGetter(field);
|
||||
}
|
||||
|
||||
private static final Map<?, List<ICapabilityProvider<?, ?, ?>>> DUMMY_MAP = new HashMap<>();
|
||||
|
||||
public static <T extends BaseCapability> Map<?, List<ICapabilityProvider<?, ?, ?>>> getProviderMap(T cap) {
|
||||
if(!FOUND_PROVIDERS) {
|
||||
return DUMMY_MAP;
|
||||
}
|
||||
|
||||
try {
|
||||
if(cap instanceof BlockCapability<?,?> blockCap) {
|
||||
return (Map<?, List<ICapabilityProvider<?, ?, ?>>>)BLOCK_CAP_PROVIDERS.invokeExact(blockCap);
|
||||
} else if(cap instanceof ItemCapability<?,?> itemCap) {
|
||||
return (Map<?, List<ICapabilityProvider<?, ?, ?>>>)ITEM_CAP_PROVIDERS.invokeExact(itemCap);
|
||||
} else if(cap instanceof EntityCapability<?,?> entityCap) {
|
||||
return (Map<?, List<ICapabilityProvider<?, ?, ?>>>)ENTITY_CAP_PROVIDERS.invokeExact(entityCap);
|
||||
} else {
|
||||
return DUMMY_MAP;
|
||||
}
|
||||
} catch(Throwable e) {
|
||||
throw new RuntimeException("Couldn't get map", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deduplicateCap(BaseCapability<?, ?> cap) {
|
||||
var map = getProviderMap(cap);
|
||||
if(map.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ObjectOpenHashSet<List<ICapabilityProvider<?, ?, ?>>> capLists = new ObjectOpenHashSet<>();
|
||||
int hits = 0;
|
||||
for(Map.Entry<?, List<ICapabilityProvider<?, ?, ?>>> entry : map.entrySet()) {
|
||||
var v = entry.getValue();
|
||||
var canonicalList = capLists.get(v);
|
||||
if(canonicalList == null) {
|
||||
canonicalList = List.copyOf(v);
|
||||
// This works because List.equals/hashCode is well-defined across any List implementation
|
||||
capLists.add(canonicalList);
|
||||
} else {
|
||||
hits++;
|
||||
}
|
||||
entry.setValue(canonicalList);
|
||||
}
|
||||
//ModernFix.LOGGER.info("Deduplicated {}/{} lists", hits, map.size());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package org.embeddedt.modernfix.neoforge.caps;
|
||||
|
||||
import net.neoforged.neoforge.capabilities.BaseCapability;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface ITrackingCapEvent {
|
||||
Set<BaseCapability<?, ?>> mfix$getTrackedCaps();
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.perf.capability_list_compaction;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.neoforge.capabilities.BaseCapability;
|
||||
import net.neoforged.neoforge.capabilities.CapabilityHooks;
|
||||
import org.embeddedt.modernfix.neoforge.caps.CapProviderGetter;
|
||||
import org.embeddedt.modernfix.neoforge.caps.ITrackingCapEvent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(value = CapabilityHooks.class, remap = false)
|
||||
public class CapabilityHooksMixin {
|
||||
@WrapOperation(method = "init", at = @At(value = "INVOKE", target = "Lnet/neoforged/fml/ModLoader;postEventWrapContainerInModOrder(Lnet/neoforged/bus/api/Event;)V"))
|
||||
private static void deduplicateCaps(Event event, Operation<Void> original) {
|
||||
original.call(event);
|
||||
if(event instanceof ITrackingCapEvent) {
|
||||
//var stopwatch = Stopwatch.createStarted();
|
||||
for(BaseCapability<?, ?> cap : ((ITrackingCapEvent)event).mfix$getTrackedCaps()) {
|
||||
CapProviderGetter.deduplicateCap(cap);
|
||||
}
|
||||
//stopwatch.stop();
|
||||
//ModernFix.LOGGER.info("Deduplicated capability lists in {}", stopwatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package org.embeddedt.modernfix.neoforge.mixin.perf.capability_list_compaction;
|
||||
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.neoforged.neoforge.capabilities.BaseCapability;
|
||||
import net.neoforged.neoforge.capabilities.BlockCapability;
|
||||
import net.neoforged.neoforge.capabilities.EntityCapability;
|
||||
import net.neoforged.neoforge.capabilities.IBlockCapabilityProvider;
|
||||
import net.neoforged.neoforge.capabilities.ICapabilityProvider;
|
||||
import net.neoforged.neoforge.capabilities.ItemCapability;
|
||||
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
|
||||
import org.embeddedt.modernfix.neoforge.caps.ITrackingCapEvent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(value = RegisterCapabilitiesEvent.class, remap = false)
|
||||
public class RegisterCapabilitiesEventMixin implements ITrackingCapEvent {
|
||||
private final Set<BaseCapability<?, ?>> mfix$trackedCapabilities = new HashSet<>();
|
||||
|
||||
@Inject(method = "registerBlock", at = @At("HEAD"))
|
||||
private void trackBlockCap(BlockCapability<?, ?> capability, IBlockCapabilityProvider<?, ?> provider, Block[] blocks, CallbackInfo ci) {
|
||||
mfix$trackedCapabilities.add(capability);
|
||||
}
|
||||
|
||||
@Inject(method = "registerBlockEntity", at = @At("HEAD"))
|
||||
private void trackBlockEntityCap(BlockCapability<?, ?> capability, BlockEntityType<?> type, ICapabilityProvider<?, ?, ?> provider, CallbackInfo ci) {
|
||||
mfix$trackedCapabilities.add(capability);
|
||||
}
|
||||
|
||||
@Inject(method = "registerItem", at = @At("HEAD"))
|
||||
private void trackItemCap(ItemCapability<?, ?> capability, ICapabilityProvider<?, ?, ?> provider, ItemLike[] items, CallbackInfo ci) {
|
||||
mfix$trackedCapabilities.add(capability);
|
||||
}
|
||||
|
||||
@Inject(method = "registerEntity", at = @At("HEAD"))
|
||||
private void trackEntityCap(EntityCapability<?, ?> capability, EntityType<?> type, ICapabilityProvider<?, ?, ?> provider, CallbackInfo ci) {
|
||||
mfix$trackedCapabilities.add(capability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<BaseCapability<?, ?>> mfix$getTrackedCaps() {
|
||||
return mfix$trackedCapabilities;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user