Merge branch '1.20' into 1.21.1
This commit is contained in:
commit
5d862d0de3
|
|
@ -0,0 +1,9 @@
|
|||
package org.embeddedt.modernfix.annotation;
|
||||
|
||||
public enum FeatureLevel {
|
||||
GA, BETA;
|
||||
|
||||
public boolean isAtLeast(FeatureLevel required) {
|
||||
return this.ordinal() >= required.ordinal();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package org.embeddedt.modernfix.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface RequiresFeatureLevel {
|
||||
FeatureLevel value() default FeatureLevel.GA;
|
||||
}
|
||||
|
|
@ -116,6 +116,7 @@ dependencies {
|
|||
compileOnly("curse.maven:cofhcore-69162:5374122")
|
||||
compileOnly("curse.maven:resourcefullib-570073:5659871")
|
||||
compileOnly("curse.maven:kubejs-238086:5853326")
|
||||
compileOnly("curse.maven:terrablender-neoforge-940057:6054947")
|
||||
}
|
||||
|
||||
tasks.named<Jar>("jar") {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.optimize_surface_rules;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.llamalad7.mixinextras.sugar.Share;
|
||||
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||
import org.embeddedt.modernfix.annotation.FeatureLevel;
|
||||
import org.embeddedt.modernfix.annotation.RequiresFeatureLevel;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.embeddedt.modernfix.world.gen.ExtendedSurfaceContext;
|
||||
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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import terrablender.worldgen.surface.NamespacedSurfaceRuleSource;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(NamespacedSurfaceRuleSource.class)
|
||||
@RequiresMod("terrablender")
|
||||
@RequiresFeatureLevel(FeatureLevel.BETA)
|
||||
public class NamespacedSurfaceRuleSourceMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private Map<String, SurfaceRules.RuleSource> sources;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private SurfaceRules.RuleSource base;
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason Avoid doing an expensive biome lookup per block in cases where we can prove all biomes will be from a
|
||||
* single namespace. This achieves much of the benefit of TerraBlenderFix without the compatibility issues.
|
||||
*/
|
||||
@Inject(method = "apply(Lnet/minecraft/world/level/levelgen/SurfaceRules$Context;)Lnet/minecraft/world/level/levelgen/SurfaceRules$SurfaceRule;", at = @At("HEAD"), cancellable = true, remap = false)
|
||||
private void modernfix$fastApply(SurfaceRules.Context context, CallbackInfoReturnable<SurfaceRules.SurfaceRule> cir,
|
||||
@Share("possibleNamespaces") LocalRef<Set<String>> possibleNamespacesRef) {
|
||||
var possibleBiomes = ((ExtendedSurfaceContext)(Object)context).mfix$getPossibleBiomes();
|
||||
if (possibleBiomes == null) {
|
||||
return;
|
||||
}
|
||||
Set<String> namespaces = mfix$findNamespaces(possibleBiomes);
|
||||
possibleNamespacesRef.set(namespaces);
|
||||
if (namespaces.size() != 1) {
|
||||
return;
|
||||
}
|
||||
String singleNamespace = namespaces.iterator().next();
|
||||
// In a single namespace scenario, we can bypass the biome lookup and directly construct a sequence rule
|
||||
SurfaceRules.RuleSource namespacedSource = this.sources.get(singleNamespace);
|
||||
if (namespacedSource == null) {
|
||||
// Sequence rule wrapper not required
|
||||
cir.setReturnValue(this.base.apply(context));
|
||||
} else {
|
||||
cir.setReturnValue(new SurfaceRules.SequenceRule(ImmutableList.of(namespacedSource.apply(context), this.base.apply(context))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason Even if we have to fall back to the namespaced source, avoid compiling surface rules for namespaces that
|
||||
* will never be hit in the given chunk.
|
||||
*/
|
||||
@ModifyArg(method = "apply(Lnet/minecraft/world/level/levelgen/SurfaceRules$Context;)Lnet/minecraft/world/level/levelgen/SurfaceRules$SurfaceRule;", at = @At(value = "INVOKE", target = "Ljava/util/Set;forEach(Ljava/util/function/Consumer;)V"), remap = false)
|
||||
private Consumer<Map.Entry<String, SurfaceRules.RuleSource>> mfix$filterConsumer(Consumer<Map.Entry<String, SurfaceRules.RuleSource>> originalConsumer,
|
||||
@Share("possibleNamespaces") LocalRef<Set<String>> possibleNamespacesRef) {
|
||||
var possibleNamespaces = possibleNamespacesRef.get();
|
||||
if (possibleNamespaces == null) {
|
||||
return originalConsumer;
|
||||
}
|
||||
return entry -> {
|
||||
if(possibleNamespaces.contains(entry.getKey())) {
|
||||
originalConsumer.accept(entry);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Set<String> mfix$findNamespaces(Set<ResourceKey<Biome>> possibleBiomes) {
|
||||
if (possibleBiomes.size() == 1) {
|
||||
return Set.of(possibleBiomes.iterator().next().location().getNamespace());
|
||||
} else {
|
||||
var namespaces = new ObjectArraySet<String>(4);
|
||||
for (var key : possibleBiomes) {
|
||||
namespaces.add(key.location().getNamespace());
|
||||
}
|
||||
return Set.copyOf(namespaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,8 +26,15 @@ public class NoiseBasedChunkGeneratorMixin {
|
|||
@SuppressWarnings("unchecked")
|
||||
private static void mfix$accumulate(Set<ResourceKey<Biome>> chunkBiomes, LevelChunkSection section) {
|
||||
var palette = ((ExtendedPalettedContainer<Holder<Biome>>)section.getBiomes()).mfix$getPalette();
|
||||
for (int i = 0; i < palette.getSize(); i++) {
|
||||
chunkBiomes.add(palette.valueFor(i).unwrapKey().orElseThrow());
|
||||
if (palette.getSize() == 1) {
|
||||
// No need to iterate the storage itself, as there can only be one value
|
||||
chunkBiomes.add(palette.valueFor(0).unwrapKey().orElseThrow());
|
||||
} else {
|
||||
// Use getAll() rather than raw palette iteration. PalettedContainer.recreate() seeds the new
|
||||
// palette with Biomes.PLAINS (the initial default), leaving a stale palette entry even after
|
||||
// fillBiomesFromNoise replaces all cells with real biomes. getAll() only visits entries that
|
||||
// are actually referenced in the backing storage, so stale entries are correctly excluded.
|
||||
section.getBiomes().getAll(holder -> chunkBiomes.add(holder.unwrapKey().orElseThrow()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.embeddedt.modernfix.core;
|
|||
import com.google.common.collect.ImmutableSet;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.embeddedt.modernfix.annotation.FeatureLevel;
|
||||
import org.embeddedt.modernfix.core.config.ModernFixEarlyConfig;
|
||||
import org.embeddedt.modernfix.core.config.Option;
|
||||
import org.embeddedt.modernfix.core.launchplugin.CoreLaunchPluginService;
|
||||
|
|
@ -40,6 +41,11 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
|||
this.logger.info("Loaded configuration file for ModernFix {}: {} options available, {} override(s) found",
|
||||
ModernFixPlatformHooks.INSTANCE.getVersionString(), config.getOptionCount(), config.getOptionOverrideCount());
|
||||
|
||||
if(ModernFixEarlyConfig.ACTIVE_FEATURE_LEVEL != FeatureLevel.GA) {
|
||||
this.logger.warn("ModernFix stability level is set to {}. Features at this level may be unstable or cause crashes.",
|
||||
ModernFixEarlyConfig.ACTIVE_FEATURE_LEVEL);
|
||||
}
|
||||
|
||||
config.getOptionMap().values().forEach(option -> {
|
||||
if (option.isOverridden()) {
|
||||
String source = "[unknown]";
|
||||
|
|
@ -129,10 +135,17 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
|||
}
|
||||
|
||||
String mixin = mixinClassName.substring(MIXIN_PACKAGE_ROOT.length());
|
||||
if(!instance.isOptionEnabled(mixin))
|
||||
if(!instance.isOptionEnabled(mixin)) {
|
||||
this.logger.debug("Skipping mixin {}: disabled by configuration", mixin);
|
||||
return false;
|
||||
}
|
||||
String disabledBecauseMod = instance.config.getPermanentlyDisabledMixins().get(mixin);
|
||||
return disabledBecauseMod == null;
|
||||
if(disabledBecauseMod != null) {
|
||||
this.logger.debug("Skipping mixin {}: disabled for mod compat ({})", mixin, disabledBecauseMod);
|
||||
return false;
|
||||
}
|
||||
this.logger.debug("Applying mixin {}", mixin);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isOptionEnabled(String mixin) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ import org.apache.commons.lang3.SystemUtils;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.annotation.FeatureLevel;
|
||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
||||
import org.embeddedt.modernfix.annotation.RequiresFeatureLevel;
|
||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
||||
|
|
@ -65,6 +67,18 @@ public class ModernFixEarlyConfig {
|
|||
private static final String MIXIN_CLIENT_ONLY_DESC = Type.getDescriptor(ClientOnlyMixin.class);
|
||||
private static final String MIXIN_REQUIRES_MOD_DESC = Type.getDescriptor(RequiresMod.class);
|
||||
private static final String MIXIN_DEV_ONLY_DESC = Type.getDescriptor(IgnoreOutsideDev.class);
|
||||
private static final String FEATURE_LEVEL_ANNOTATION_DESC = Type.getDescriptor(RequiresFeatureLevel.class);
|
||||
|
||||
public static final FeatureLevel ACTIVE_FEATURE_LEVEL = resolveFeatureLevel();
|
||||
|
||||
private static FeatureLevel resolveFeatureLevel() {
|
||||
String prop = System.getProperty("modernfix.stabilityLevel", "ga").toUpperCase(Locale.ROOT);
|
||||
try {
|
||||
return FeatureLevel.valueOf(prop);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return FeatureLevel.GA;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern PLATFORM_PREFIX = Pattern.compile("(neoforge|fabric|common)\\.");
|
||||
|
||||
|
|
@ -112,6 +126,7 @@ public class ModernFixEarlyConfig {
|
|||
return;
|
||||
boolean isMixin = false, isClientOnly = false, requiredModPresent = true, isDevOnly = false;
|
||||
String requiredModId = "";
|
||||
FeatureLevel requiredLevel = FeatureLevel.GA;
|
||||
for(AnnotationNode annotation : node.invisibleAnnotations) {
|
||||
if(Objects.equals(annotation.desc, MIXIN_DESC)) {
|
||||
isMixin = true;
|
||||
|
|
@ -130,6 +145,15 @@ public class ModernFixEarlyConfig {
|
|||
}
|
||||
} else if(Objects.equals(annotation.desc, MIXIN_DEV_ONLY_DESC)) {
|
||||
isDevOnly = true;
|
||||
} else if(Objects.equals(annotation.desc, FEATURE_LEVEL_ANNOTATION_DESC)) {
|
||||
for(int i = 0; i < annotation.values.size(); i += 2) {
|
||||
if(annotation.values.get(i).equals("value")) {
|
||||
// ASM stores enum annotation values as String[]{typeDescriptor, constantName}
|
||||
String[] enumVal = (String[]) annotation.values.get(i + 1);
|
||||
requiredLevel = FeatureLevel.valueOf(enumVal[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isMixin && (!isDevOnly || ModernFixPlatformHooks.INSTANCE.isDevEnv())) {
|
||||
|
|
@ -138,6 +162,8 @@ public class ModernFixEarlyConfig {
|
|||
mixinsMissingMods.put(mixinClassName, requiredModId);
|
||||
else if(isClientOnly && !ModernFixPlatformHooks.INSTANCE.isClient())
|
||||
mixinsMissingMods.put(mixinClassName, "[not client]");
|
||||
else if(!ACTIVE_FEATURE_LEVEL.isAtLeast(requiredLevel))
|
||||
mixinsMissingMods.put(mixinClassName, "[feature level: requires " + requiredLevel + "]");
|
||||
String mixinCategoryName = "mixin." + mixinClassName.substring(0, mixinClassName.lastIndexOf('.'));
|
||||
mixinOptions.add(mixinCategoryName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ public net.minecraft.client.renderer.block.model.multipart.MultiPart definition
|
|||
public net.minecraft.client.resources.model.ModelBakery$ModelBakerImpl
|
||||
public net.minecraft.client.resources.model.ModelBakery$ModelBakerImpl <init>(Lnet/minecraft/client/resources/model/ModelBakery;Lnet/minecraft/client/resources/model/ModelBakery$TextureGetter;Lnet/minecraft/client/resources/model/ModelResourceLocation;)V
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$SequenceRule
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$SequenceRule <init>(Ljava/util/List;)V
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$SequenceRuleSource
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$SequenceRuleSource <init>(Ljava/util/List;)V
|
||||
public net.minecraft.world.level.levelgen.SurfaceRules$TestRuleSource
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user