Merge remote-tracking branch 'origin/1.20' into 1.21

This commit is contained in:
embeddedt 2024-08-10 19:14:41 -04:00
commit 512a7e237c
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
7 changed files with 104 additions and 106 deletions

View File

@ -1,5 +1,6 @@
package org.embeddedt.modernfix.blockstate;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.world.level.block.state.properties.Property;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -14,6 +15,7 @@ import java.util.*;
*/
public class FakeStateMap<S> implements Map<Map<Property<?>, Comparable<?>>, S> {
private final Map<Property<?>, Comparable<?>>[] keys;
private Map<Map<Property<?>, Comparable<?>>, S> fastLookup;
private final Object[] values;
private int usedSlots;
public FakeStateMap(int numStates) {
@ -34,22 +36,39 @@ public class FakeStateMap<S> implements Map<Map<Property<?>, Comparable<?>>, S>
@Override
public boolean containsKey(Object o) {
throw new UnsupportedOperationException();
return getFastLookup().containsKey(o);
}
@Override
public boolean containsValue(Object o) {
throw new UnsupportedOperationException();
return getFastLookup().containsValue(o);
}
@SuppressWarnings("unchecked")
private Map<Map<Property<?>, Comparable<?>>, S> getFastLookup() {
if(fastLookup == null) {
var map = new Object2ObjectOpenHashMap<Map<Property<?>, Comparable<?>>, S>(usedSlots);
Map<Property<?>, Comparable<?>>[] keys = this.keys;
Object[] values = this.values;
for(int i = 0; i < usedSlots; i++) {
map.put(keys[i], (S)values[i]);
}
fastLookup = map;
}
return fastLookup;
}
@Override
public S get(Object o) {
throw new UnsupportedOperationException();
return getFastLookup().get(o);
}
@Nullable
@Override
public S put(Map<Property<?>, Comparable<?>> propertyComparableMap, S s) {
if(fastLookup != null) {
throw new IllegalStateException("Cannot populate map after fast lookup is built");
}
keys[usedSlots] = propertyComparableMap;
values[usedSlots] = s;
usedSlots++;
@ -70,7 +89,7 @@ public class FakeStateMap<S> implements Map<Map<Property<?>, Comparable<?>>, S>
@Override
public void clear() {
for(int i = 0; i < this.keys.length; i++) {
for(int i = 0; i < usedSlots; i++) {
this.keys[i] = null;
this.values[i] = null;
}

View File

@ -0,0 +1,22 @@
package org.embeddedt.modernfix.common.mixin.perf.chunk_meshing;
import net.minecraft.client.renderer.chunk.SectionCompiler;
import net.minecraft.core.BlockPos;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.util.blockpos.SectionBlockPosIterator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = SectionCompiler.class, priority = 2000)
@ClientOnlyMixin
public class RebuildTaskMixin {
/**
* @author embeddedt
* @reason Use a much faster iterator implementation than vanilla's Guava-based one.
*/
@Redirect(method = "compile", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;betweenClosed(Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/BlockPos;)Ljava/lang/Iterable;"))
private Iterable<BlockPos> fastBetweenClosed(BlockPos firstPos, BlockPos secondPos) {
return () -> new SectionBlockPosIterator(firstPos);
}
}

View File

@ -6,23 +6,25 @@ import net.minecraft.world.level.block.state.StateHolder;
import net.minecraft.world.level.block.state.properties.Property;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.embeddedt.modernfix.blockstate.FakeStateMap;
import org.embeddedt.modernfix.blockstate.FerriteCorePostProcess;
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
// This optimization requires FerriteCore to be worthwhile, otherwise the FakeStateMap degrades to hash internally
@Mixin(StateDefinition.class)
@RequiresMod("ferritecore")
public class StateDefinitionMixin<O, S extends StateHolder<O, S>> {
@Shadow @Final private ImmutableSortedMap<String, Property<?>> propertiesByName;
/**
* @author embeddedt
* @reason write states into a custom array map for fast iteration by FerriteCore, no need to waste time hashing
* and growing
*/
@ModifyVariable(method = "<init>", at = @At(value = "STORE", ordinal = 0), ordinal = 1, index = 8)
private Map<Map<Property<?>, Comparable<?>>, S> useArrayMap(Map<Map<Property<?>, Comparable<?>>, S> in) {
int numStates = 1;
@ -31,11 +33,4 @@ public class StateDefinitionMixin<O, S extends StateHolder<O, S>> {
}
return new FakeStateMap<>(numStates);
}
@Inject(method = "<init>", at = @At("TAIL"))
private void postProcess(CallbackInfo ci) {
// keep in dev only until upstream FC releases
if(ModernFixPlatformHooks.INSTANCE.isDevEnv())
FerriteCorePostProcess.postProcess((StateDefinition<O, S>)(Object)this);
}
}

View File

@ -0,0 +1,39 @@
package org.embeddedt.modernfix.util.blockpos;
import net.minecraft.core.BlockPos;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class SectionBlockPosIterator implements Iterator<BlockPos> {
private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
private int index = 0;
private final int baseX, baseY, baseZ;
public SectionBlockPosIterator(int baseX, int baseY, int baseZ) {
this.baseX = baseX;
this.baseY = baseY;
this.baseZ = baseZ;
}
public SectionBlockPosIterator(BlockPos pos) {
this(pos.getX(), pos.getY(), pos.getZ());
}
@Override
public boolean hasNext() {
return index < 4096;
}
@Override
public BlockPos next() {
int i = index;
if (i >= 4096) {
throw new NoSuchElementException();
}
index = i + 1;
var pos = this.pos;
pos.set(this.baseX + (i & 15), this.baseY + ((i >> 8) & 15), this.baseZ + ((i >> 4) & 15));
return pos;
}
}

View File

@ -1,12 +1,17 @@
package org.embeddedt.modernfix.testing.util;
import net.minecraft.SharedConstants;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.server.Bootstrap;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.Extension;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.lang.reflect.Field;
import java.util.IdentityHashMap;
/**
* Simple extension to run vanilla bootstrap, inspired by AE2.
*/
@ -15,6 +20,15 @@ public class BootstrapMinecraftExtension implements Extension, BeforeAllCallback
public void beforeAll(ExtensionContext context) throws Exception {
SharedConstants.tryDetectVersion();
Bootstrap.bootStrap();
// Allow blocks to be created in tests
Field field = MappedRegistry.class.getDeclaredField("unregisteredIntrusiveHolders");
field.setAccessible(true);
if(field.get(BuiltInRegistries.BLOCK) == null) {
field.set(BuiltInRegistries.BLOCK, new IdentityHashMap<>());
field = MappedRegistry.class.getDeclaredField("frozen");
field.setAccessible(true);
field.setBoolean(BuiltInRegistries.BLOCK, false);
}
}
@Override

View File

@ -1,89 +0,0 @@
package org.embeddedt.modernfix.neoforge.classloading;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import net.neoforged.fml.ModList;
import net.neoforged.neoforgespi.language.ModFileScanData;
import net.neoforged.neoforgespi.locating.IModFile;
import org.objectweb.asm.Type;
import java.lang.reflect.Field;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ModFileScanDataDeduplicator {
private final Interner<Type> typeInterner = Interners.newStrongInterner();
private final Function<Type, Type> internerFn = type -> type != null ? typeInterner.intern(type) : null;
private static Field classClazzField, parentField, interfacesField, annotationClazzField, annotationTypeField;
private static final boolean reflectionSuccessful;
static {
boolean success = false;
try {
classClazzField = ModFileScanData.ClassData.class.getDeclaredField("clazz");
classClazzField.setAccessible(true);
parentField = ModFileScanData.ClassData.class.getDeclaredField("parent");
parentField.setAccessible(true);
interfacesField = ModFileScanData.ClassData.class.getDeclaredField("interfaces");
interfacesField.setAccessible(true);
annotationClazzField = ModFileScanData.AnnotationData.class.getDeclaredField("clazz");
annotationClazzField.setAccessible(true);
annotationTypeField = ModFileScanData.AnnotationData.class.getDeclaredField("annotationType");
annotationTypeField.setAccessible(true);
success = true;
} catch(ReflectiveOperationException | RuntimeException e) {
}
reflectionSuccessful = success;
}
ModFileScanDataDeduplicator() {
}
private void runDeduplication() {
ModList.get().forEachModFile(this::deduplicateFile);
}
private void deduplicateFile(IModFile file) {
ModFileScanData data = file.getScanResult();
if(data != null) {
data.getClasses().forEach(this::deduplicateClass);
data.getAnnotations().forEach(this::deduplicateAnnotation);
}
}
private void deduplicateClass(ModFileScanData.ClassData data) {
try {
Type type = (Type)classClazzField.get(data);
type = internerFn.apply(type);
classClazzField.set(data, type);
type = (Type)parentField.get(data);
type = internerFn.apply(type);
parentField.set(data, type);
Set<Type> types = (Set<Type>)interfacesField.get(data);
types = types.stream().map(internerFn).collect(Collectors.toSet());
interfacesField.set(data, types);
} catch(ReflectiveOperationException e) {
}
}
private void deduplicateAnnotation(ModFileScanData.AnnotationData data) {
try {
Type type = (Type)annotationClazzField.get(data);
type = internerFn.apply(type);
annotationClazzField.set(data, type);
type = (Type)annotationTypeField.get(data);
type = internerFn.apply(type);
annotationTypeField.set(data, type);
} catch(ReflectiveOperationException e) {
}
}
public static void deduplicate() {
if(!reflectionSuccessful)
return;
new ModFileScanDataDeduplicator().runDeduplication();
}
}

View File

@ -22,7 +22,6 @@ import org.apache.commons.lang3.tuple.Pair;
import org.embeddedt.modernfix.ModernFix;
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
import org.embeddedt.modernfix.neoforge.ModernFixConfig;
import org.embeddedt.modernfix.neoforge.classloading.ModFileScanDataDeduplicator;
import java.util.List;
@ -41,7 +40,6 @@ public class ModernFixForge {
NeoForge.EVENT_BUS.register(new ModernFixClientForge(modContainer, modBus));
}
modContainer.registerConfig(ModConfig.Type.COMMON, ModernFixConfig.COMMON_CONFIG);
ModFileScanDataDeduplicator.deduplicate();
}
private void registerItems(RegisterEvent event) {