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

This commit is contained in:
embeddedt 2024-03-21 13:53:42 -04:00
commit 9d7ef772a0
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
7 changed files with 221 additions and 4 deletions

View File

@ -0,0 +1,28 @@
package org.embeddedt.modernfix.common.mixin.perf.ticking_chunk_alloc;
import net.minecraft.world.entity.ambient.Bat;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.time.LocalDate;
@Mixin(value = Bat.class, priority = 1200)
public class BatMixin {
private static long mfix$lastQueriedTime = -1L;
private static LocalDate mfix$lastQueriedDate = null;
/**
* @author embeddedt
* @reason avoid excessive allocations from continuously querying the date, only get a new date once every 30 seconds
*/
@Redirect(method = "isHalloween", at = @At(value = "INVOKE", target = "Ljava/time/LocalDate;now()Ljava/time/LocalDate;"), require = 0)
private static LocalDate useCachedLocalDate() {
LocalDate date = mfix$lastQueriedDate;
if(date == null || Math.abs(System.currentTimeMillis() - mfix$lastQueriedTime) > 30000) {
mfix$lastQueriedDate = date = LocalDate.now();
mfix$lastQueriedTime = System.currentTimeMillis();
}
return date;
}
}

View File

@ -0,0 +1,26 @@
package org.embeddedt.modernfix.common.mixin.perf.ticking_chunk_alloc;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@Mixin(ChunkGenerator.class)
public class ChunkGeneratorMixin {
/**
* @author embeddedt
* @reason Avoid allocation if the chunk contains no structures
*/
@Redirect(method = "getMobsAt", at = @At(value = "INVOKE", target = "Ljava/util/Map;entrySet()Ljava/util/Set;"), require = 0)
private Set<?> avoidSetAllocation(Map<?, ?> instance) {
if(instance.isEmpty()) {
return Collections.emptySet();
} else {
return instance.entrySet();
}
}
}

View File

@ -0,0 +1,40 @@
package org.embeddedt.modernfix.common.mixin.perf.ticking_chunk_alloc;
import com.mojang.datafixers.util.Either;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.world.level.chunk.LevelChunk;
import org.embeddedt.modernfix.util.EitherUtil;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import java.util.concurrent.CompletableFuture;
@Mixin(value = ChunkHolder.class, priority = 500)
public abstract class ChunkHolderMixin {
@Shadow public abstract CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> getTickingChunkFuture();
@Shadow public abstract CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> getFullChunkFuture();
/**
* @author embeddedt
* @reason avoid Optional allocation
*/
@Overwrite
public LevelChunk getTickingChunk() {
CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> completableFuture = this.getTickingChunkFuture();
Either<LevelChunk, ChunkHolder.ChunkLoadingFailure> either = completableFuture.getNow(null);
return either == null ? null : EitherUtil.leftOrNull(either);
}
/**
* @author embeddedt
* @reason avoid Optional allocation
*/
@Overwrite
public LevelChunk getFullChunk() {
CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> completableFuture = this.getFullChunkFuture();
Either<LevelChunk, ChunkHolder.ChunkLoadingFailure> either = completableFuture.getNow(null);
return either == null ? null : EitherUtil.leftOrNull(either);
}
}

View File

@ -0,0 +1,52 @@
package org.embeddedt.modernfix.util;
import com.mojang.datafixers.util.Either;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
public class EitherUtil {
private static final Class<?> LEFT, RIGHT;
private static final MethodHandle LEFT_VAL, RIGHT_VAL;
static {
try {
LEFT = Class.forName("com.mojang.datafixers.util.Either$Left");
RIGHT = Class.forName("com.mojang.datafixers.util.Either$Right");
Field lvalue = LEFT.getDeclaredField("value");
lvalue.setAccessible(true);
Field rvalue = RIGHT.getDeclaredField("value");
rvalue.setAccessible(true);
LEFT_VAL = MethodHandles.publicLookup().unreflectGetter(lvalue).asType(MethodType.methodType(Object.class, Either.class));
RIGHT_VAL = MethodHandles.publicLookup().unreflectGetter(rvalue).asType(MethodType.methodType(Object.class, Either.class));
} catch(ReflectiveOperationException e) {
throw new AssertionError("Failed to hook DFU Either", e);
}
}
@SuppressWarnings("unchecked")
public static <L, R> L leftOrNull(Either<L, R> either) {
if(either.getClass() == LEFT) {
try {
return (L)LEFT_VAL.invokeExact(either);
} catch(Throwable e) {
throw new RuntimeException(e);
}
}
return null;
}
@SuppressWarnings("unchecked")
public static <L, R> R rightOrNull(Either<L, R> either) {
if(either.getClass() == RIGHT) {
try {
return (R)RIGHT_VAL.invokeExact(either);
} catch(Throwable e) {
throw new RuntimeException(e);
}
}
return null;
}
}

View File

@ -1,5 +1,6 @@
package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources;
import com.google.common.collect.ImmutableList;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.fabricmc.loader.api.FabricLoader;
@ -75,9 +76,19 @@ public abstract class ModelBakerImplMixin implements IExtendedModelBaker {
synchronized (this.field_40571) {
/* to emulate vanilla model loading, treat as top-level */
Optional<Block> blockOpt = Objects.equals(((ModelResourceLocation)arg).getVariant(), "inventory") ? Optional.empty() : BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(arg.getNamespace(), arg.getPath()));
boolean invalidMRL = false;
if(blockOpt.isPresent()) {
/* load via lambda for mods that expect blockstate to get loaded */
for(BlockState state : extendedBakery.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), (ModelResourceLocation)arg)) {
ImmutableList<BlockState> states;
try {
states = extendedBakery.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), (ModelResourceLocation)arg);
} catch(RuntimeException e) {
states = ImmutableList.of();
invalidMRL = true;
// Fall back to getModel
cir.setReturnValue(this.field_40571.getModel(arg));
}
for(BlockState state : states) {
try {
blockStateLoaderHandle.invokeExact(this.field_40571, state);
} catch(Throwable e) {
@ -87,9 +98,11 @@ public abstract class ModelBakerImplMixin implements IExtendedModelBaker {
} else {
this.field_40571.loadTopLevel((ModelResourceLocation)arg);
}
cir.setReturnValue(this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel()));
// avoid leaks
this.field_40571.topLevelModels.clear();
if(!invalidMRL) {
cir.setReturnValue(this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel()));
// avoid leaks
this.field_40571.topLevelModels.clear();
}
}
} else
cir.setReturnValue(this.field_40571.getModel(arg));

View File

@ -0,0 +1,56 @@
package org.embeddedt.modernfix.neoforge.config;
import com.electronwill.nightconfig.core.file.FileWatcher;
import com.google.common.collect.ForwardingCollection;
import com.google.common.collect.ForwardingMap;
import net.neoforged.fml.util.ObfuscationReflectionHelper;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
/**
* Throttle NightConfig's file watching. There are reports of this consuming excessive CPU time
* (<a href="https://github.com/TheElectronWill/night-config/pull/144">example</a>) and the spammed iterator calls
* end up being 10% of allocations when testing in a dev environment.
*/
public class NightConfigWatchThrottler {
private static final long DELAY = TimeUnit.MILLISECONDS.toNanos(1000);
@SuppressWarnings("rawtypes")
public static void throttle() {
Map watchedDirs = ObfuscationReflectionHelper.getPrivateValue(FileWatcher.class, FileWatcher.defaultInstance(), "watchedDirs");
ObfuscationReflectionHelper.setPrivateValue(FileWatcher.class, FileWatcher.defaultInstance(), new ForwardingMap() {
@Override
protected Map delegate() {
return watchedDirs;
}
private Collection cachedValues;
@Override
public Collection values() {
if(cachedValues == null) {
Collection values = super.values();
cachedValues = new ForwardingCollection() {
@Override
protected Collection delegate() {
return values;
}
@Override
public Iterator iterator() {
// iterator() is called at the beginning of each iteration of the watch loop,
// so it is a good spot to inject the delay.
LockSupport.parkNanos(DELAY);
return super.iterator();
}
};
}
return cachedValues;
}
}, "watchedDirs");
}
}

View File

@ -24,6 +24,7 @@ import net.neoforged.neoforge.server.ServerLifecycleHooks;
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
import org.embeddedt.modernfix.neoforge.config.NightConfigFixer;
import org.embeddedt.modernfix.neoforge.config.NightConfigWatchThrottler;
import org.embeddedt.modernfix.neoforge.init.ModernFixForge;
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
import org.embeddedt.modernfix.spark.SparkLaunchProfiler;
@ -106,6 +107,7 @@ public class ModernFixPlatformHooksImpl implements ModernFixPlatformHooks {
}
NightConfigFixer.monitorFileWatcher();
NightConfigWatchThrottler.throttle();
}
public void applyASMTransformers(String mixinClassName, ClassNode targetClass) {