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:cofhcore-69162:5374122")
|
||||||
compileOnly("curse.maven:resourcefullib-570073:5659871")
|
compileOnly("curse.maven:resourcefullib-570073:5659871")
|
||||||
compileOnly("curse.maven:kubejs-238086:5853326")
|
compileOnly("curse.maven:kubejs-238086:5853326")
|
||||||
|
compileOnly("curse.maven:terrablender-neoforge-940057:6054947")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named<Jar>("jar") {
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
private static void mfix$accumulate(Set<ResourceKey<Biome>> chunkBiomes, LevelChunkSection section) {
|
private static void mfix$accumulate(Set<ResourceKey<Biome>> chunkBiomes, LevelChunkSection section) {
|
||||||
var palette = ((ExtendedPalettedContainer<Holder<Biome>>)section.getBiomes()).mfix$getPalette();
|
var palette = ((ExtendedPalettedContainer<Holder<Biome>>)section.getBiomes()).mfix$getPalette();
|
||||||
for (int i = 0; i < palette.getSize(); i++) {
|
if (palette.getSize() == 1) {
|
||||||
chunkBiomes.add(palette.valueFor(i).unwrapKey().orElseThrow());
|
// 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 com.google.common.collect.ImmutableSet;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
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.ModernFixEarlyConfig;
|
||||||
import org.embeddedt.modernfix.core.config.Option;
|
import org.embeddedt.modernfix.core.config.Option;
|
||||||
import org.embeddedt.modernfix.core.launchplugin.CoreLaunchPluginService;
|
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",
|
this.logger.info("Loaded configuration file for ModernFix {}: {} options available, {} override(s) found",
|
||||||
ModernFixPlatformHooks.INSTANCE.getVersionString(), config.getOptionCount(), config.getOptionOverrideCount());
|
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 -> {
|
config.getOptionMap().values().forEach(option -> {
|
||||||
if (option.isOverridden()) {
|
if (option.isOverridden()) {
|
||||||
String source = "[unknown]";
|
String source = "[unknown]";
|
||||||
|
|
@ -129,10 +135,17 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
String mixin = mixinClassName.substring(MIXIN_PACKAGE_ROOT.length());
|
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;
|
return false;
|
||||||
|
}
|
||||||
String disabledBecauseMod = instance.config.getPermanentlyDisabledMixins().get(mixin);
|
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) {
|
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.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||||
|
import org.embeddedt.modernfix.annotation.FeatureLevel;
|
||||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
||||||
|
import org.embeddedt.modernfix.annotation.RequiresFeatureLevel;
|
||||||
import org.embeddedt.modernfix.annotation.RequiresMod;
|
import org.embeddedt.modernfix.annotation.RequiresMod;
|
||||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
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_CLIENT_ONLY_DESC = Type.getDescriptor(ClientOnlyMixin.class);
|
||||||
private static final String MIXIN_REQUIRES_MOD_DESC = Type.getDescriptor(RequiresMod.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 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)\\.");
|
private static final Pattern PLATFORM_PREFIX = Pattern.compile("(neoforge|fabric|common)\\.");
|
||||||
|
|
||||||
|
|
@ -112,6 +126,7 @@ public class ModernFixEarlyConfig {
|
||||||
return;
|
return;
|
||||||
boolean isMixin = false, isClientOnly = false, requiredModPresent = true, isDevOnly = false;
|
boolean isMixin = false, isClientOnly = false, requiredModPresent = true, isDevOnly = false;
|
||||||
String requiredModId = "";
|
String requiredModId = "";
|
||||||
|
FeatureLevel requiredLevel = FeatureLevel.GA;
|
||||||
for(AnnotationNode annotation : node.invisibleAnnotations) {
|
for(AnnotationNode annotation : node.invisibleAnnotations) {
|
||||||
if(Objects.equals(annotation.desc, MIXIN_DESC)) {
|
if(Objects.equals(annotation.desc, MIXIN_DESC)) {
|
||||||
isMixin = true;
|
isMixin = true;
|
||||||
|
|
@ -130,6 +145,15 @@ public class ModernFixEarlyConfig {
|
||||||
}
|
}
|
||||||
} else if(Objects.equals(annotation.desc, MIXIN_DEV_ONLY_DESC)) {
|
} else if(Objects.equals(annotation.desc, MIXIN_DEV_ONLY_DESC)) {
|
||||||
isDevOnly = true;
|
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())) {
|
if(isMixin && (!isDevOnly || ModernFixPlatformHooks.INSTANCE.isDevEnv())) {
|
||||||
|
|
@ -138,6 +162,8 @@ public class ModernFixEarlyConfig {
|
||||||
mixinsMissingMods.put(mixinClassName, requiredModId);
|
mixinsMissingMods.put(mixinClassName, requiredModId);
|
||||||
else if(isClientOnly && !ModernFixPlatformHooks.INSTANCE.isClient())
|
else if(isClientOnly && !ModernFixPlatformHooks.INSTANCE.isClient())
|
||||||
mixinsMissingMods.put(mixinClassName, "[not client]");
|
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('.'));
|
String mixinCategoryName = "mixin." + mixinClassName.substring(0, mixinClassName.lastIndexOf('.'));
|
||||||
mixinOptions.add(mixinCategoryName);
|
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
|
||||||
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.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
|
||||||
|
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
|
||||||
public net.minecraft.world.level.levelgen.SurfaceRules$SequenceRuleSource <init>(Ljava/util/List;)V
|
public net.minecraft.world.level.levelgen.SurfaceRules$SequenceRuleSource <init>(Ljava/util/List;)V
|
||||||
public net.minecraft.world.level.levelgen.SurfaceRules$TestRuleSource
|
public net.minecraft.world.level.levelgen.SurfaceRules$TestRuleSource
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user