Merge remote-tracking branch 'origin/1.21.1' into 26.1
This commit is contained in:
commit
433a0e5b70
|
|
@ -0,0 +1,7 @@
|
||||||
|
package org.embeddedt.modernfix.chunk;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.chunk.Palette;
|
||||||
|
|
||||||
|
public interface ExtendedPalettedContainer<T> {
|
||||||
|
Palette<T> mfix$getPalette();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package org.embeddedt.modernfix.common.mixin.core;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.chunk.Palette;
|
||||||
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
|
import org.embeddedt.modernfix.chunk.ExtendedPalettedContainer;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
@Mixin(PalettedContainer.class)
|
||||||
|
public class PalettedContainerMixin<T> implements ExtendedPalettedContainer<T> {
|
||||||
|
@Shadow
|
||||||
|
private volatile PalettedContainer.Data<T> data;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Palette<T> mfix$getPalette() {
|
||||||
|
return this.data.palette();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package org.embeddedt.modernfix.common.mixin.perf.optimize_surface_rules;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||||
|
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.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Mixin(SurfaceRules.BiomeConditionSource.class)
|
||||||
|
public class BiomeConditionSourceMixin {
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
public List<ResourceKey<Biome>> biomes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mojang, embeddedt
|
||||||
|
* @reason Hoist evaluation of the biome conditions where possible, in cases where we know the chunk contains
|
||||||
|
* no matching biomes, or only matching biomes
|
||||||
|
*/
|
||||||
|
@Inject(method = "apply(Lnet/minecraft/world/level/levelgen/SurfaceRules$Context;)Lnet/minecraft/world/level/levelgen/SurfaceRules$Condition;", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void mfix$optimizeCondition(SurfaceRules.Context p_context, CallbackInfoReturnable<SurfaceRules.Condition> cir) {
|
||||||
|
var possibleBiomes = ((ExtendedSurfaceContext)(Object)p_context).mfix$getPossibleBiomes();
|
||||||
|
if (possibleBiomes != null) {
|
||||||
|
if (mfix$guaranteedNoMatch(possibleBiomes)) {
|
||||||
|
cir.setReturnValue(() -> false);
|
||||||
|
} else if (mfix$alwaysMatches(possibleBiomes)) {
|
||||||
|
cir.setReturnValue(() -> true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mfix$guaranteedNoMatch(Set<ResourceKey<Biome>> possibleBiomesInChunk) {
|
||||||
|
var testBiomes = this.biomes;
|
||||||
|
//noinspection ForLoopReplaceableByForEach
|
||||||
|
for (int i = 0; i < testBiomes.size(); i++) {
|
||||||
|
if (possibleBiomesInChunk.contains(testBiomes.get(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mfix$alwaysMatches(Set<ResourceKey<Biome>> possibleBiomesInChunk) {
|
||||||
|
var testBiomes = this.biomes;
|
||||||
|
// Check each of the biomes in the chunk and see if we'd always match it
|
||||||
|
for (var biome : possibleBiomesInChunk) {
|
||||||
|
if (!testBiomes.contains(biome)) {
|
||||||
|
// at least one biome would not match
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package org.embeddedt.modernfix.common.mixin.perf.optimize_surface_rules;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.StructureManager;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
|
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||||
|
import net.minecraft.world.level.levelgen.RandomState;
|
||||||
|
import org.embeddedt.modernfix.chunk.ExtendedPalettedContainer;
|
||||||
|
import org.embeddedt.modernfix.world.gen.ExtendedSurfaceContext;
|
||||||
|
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.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Mixin(NoiseBasedChunkGenerator.class)
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<ResourceKey<Biome>> mfix$obtainBiomes(WorldGenRegion region, int chunkRadius) {
|
||||||
|
Set<ResourceKey<Biome>> chunkBiomes = new ReferenceOpenHashSet<>();
|
||||||
|
ChunkPos center = region.getCenter();
|
||||||
|
for (int z = center.z() - chunkRadius; z <= center.z() + chunkRadius; z++) {
|
||||||
|
for (int x = center.x() - chunkRadius; x <= center.x() + chunkRadius; x++) {
|
||||||
|
var chunk = region.getChunk(x, z);
|
||||||
|
for (var section : chunk.getSections()) {
|
||||||
|
mfix$accumulate(chunkBiomes, section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chunkBiomes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author embeddedt
|
||||||
|
* @reason scan for all biomes in the chunk and its neighbors before building surface
|
||||||
|
*/
|
||||||
|
@Inject(method = "buildSurface(Lnet/minecraft/server/level/WorldGenRegion;Lnet/minecraft/world/level/StructureManager;Lnet/minecraft/world/level/levelgen/RandomState;Lnet/minecraft/world/level/chunk/ChunkAccess;)V",
|
||||||
|
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/NoiseBasedChunkGenerator;buildSurface(Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/world/level/levelgen/WorldGenerationContext;Lnet/minecraft/world/level/levelgen/RandomState;Lnet/minecraft/world/level/StructureManager;Lnet/minecraft/world/level/biome/BiomeManager;Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/blending/Blender;)V"))
|
||||||
|
private void mfix$findNearbyBiomes(WorldGenRegion level, StructureManager structureManager, RandomState random, ChunkAccess chunk, CallbackInfo ci) {
|
||||||
|
try {
|
||||||
|
ExtendedSurfaceContext.COMPUTED_POSSIBLE_BIOMES.set(mfix$obtainBiomes(level, 1));
|
||||||
|
} catch (NoSuchElementException ignored) {
|
||||||
|
// Catch in case a biome somehow does not have a key. In that case we just don't use the computed set
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.optimize_surface_rules;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.levelgen.SurfaceRules;
|
|
||||||
import org.embeddedt.modernfix.world.gen.SurfaceRuleOptimizer;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
@Mixin(targets = {"net/minecraft/world/level/levelgen/SurfaceRules$SequenceRuleSource"})
|
|
||||||
public class SequenceRuleSourceMixin {
|
|
||||||
@Unique
|
|
||||||
private transient SurfaceRules.RuleSource mfix$optimizedSource;
|
|
||||||
|
|
||||||
@Inject(method = "apply(Lnet/minecraft/world/level/levelgen/SurfaceRules$Context;)Lnet/minecraft/world/level/levelgen/SurfaceRules$SurfaceRule;", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void optimizeApply(SurfaceRules.Context context, CallbackInfoReturnable<SurfaceRules.SurfaceRule> cir) {
|
|
||||||
var optimizedSource = mfix$optimizedSource;
|
|
||||||
if (optimizedSource == null) {
|
|
||||||
mfix$optimizedSource = optimizedSource = SurfaceRuleOptimizer.optimizeSequenceRuleSource((SurfaceRules.SequenceRuleSource)(Object) this);
|
|
||||||
}
|
|
||||||
// Must check for it not being ourselves, to avoid infinite reentrance
|
|
||||||
if (optimizedSource != (Object)this) {
|
|
||||||
cir.setReturnValue(optimizedSource.apply(context));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.embeddedt.modernfix.common.mixin.perf.optimize_surface_rules;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||||
|
import org.embeddedt.modernfix.world.gen.ExtendedSurfaceContext;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Mixin(SurfaceRules.Context.class)
|
||||||
|
public class SurfaceRulesContextMixin implements ExtendedSurfaceContext {
|
||||||
|
@Nullable Set<ResourceKey<Biome>> mfix$possibleBiomes;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mfix$applyPossibleBiomes() {
|
||||||
|
// Copy into a field so we don't hit a thread local for each BiomeConditionSource instance
|
||||||
|
this.mfix$possibleBiomes = ExtendedSurfaceContext.COMPUTED_POSSIBLE_BIOMES.get();
|
||||||
|
ExtendedSurfaceContext.COMPUTED_POSSIBLE_BIOMES.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Set<ResourceKey<Biome>> mfix$getPossibleBiomes() {
|
||||||
|
return this.mfix$possibleBiomes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@ import net.minecraft.world.level.levelgen.SurfaceRules;
|
||||||
import net.minecraft.world.level.levelgen.SurfaceSystem;
|
import net.minecraft.world.level.levelgen.SurfaceSystem;
|
||||||
import net.minecraft.world.level.levelgen.WorldGenerationContext;
|
import net.minecraft.world.level.levelgen.WorldGenerationContext;
|
||||||
import org.embeddedt.modernfix.world.gen.ChunkBiomeLookup;
|
import org.embeddedt.modernfix.world.gen.ChunkBiomeLookup;
|
||||||
|
import org.embeddedt.modernfix.world.gen.ExtendedSurfaceContext;
|
||||||
import org.embeddedt.modernfix.world.gen.PrefetchingBlockColumn;
|
import org.embeddedt.modernfix.world.gen.PrefetchingBlockColumn;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
@ -43,6 +44,11 @@ public class SurfaceSystemMixin {
|
||||||
return lookup;
|
return lookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "buildSurface", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/SurfaceRules$RuleSource;apply(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 0))
|
||||||
|
private void injectBiomesOnContext(CallbackInfo ci, @Local(ordinal = 0) SurfaceRules.Context surfacerules$context) {
|
||||||
|
((ExtendedSurfaceContext)(Object) surfacerules$context).mfix$applyPossibleBiomes();
|
||||||
|
}
|
||||||
|
|
||||||
@Inject(method = "buildSurface", at = @At("TAIL"))
|
@Inject(method = "buildSurface", at = @At("TAIL"))
|
||||||
private void finishAndDisposeLookups(RandomState randomState, BiomeManager biomeManager, Registry<Biome> biomes, boolean p_224652_, WorldGenerationContext context, ChunkAccess chunk, NoiseChunk noiseChunk, SurfaceRules.RuleSource ruleSource, CallbackInfo ci) {
|
private void finishAndDisposeLookups(RandomState randomState, BiomeManager biomeManager, Registry<Biome> biomes, boolean p_224652_, WorldGenerationContext context, ChunkAccess chunk, NoiseChunk noiseChunk, SurfaceRules.RuleSource ruleSource, CallbackInfo ci) {
|
||||||
MFIX_LOOKUP_CACHE.get().dispose();
|
MFIX_LOOKUP_CACHE.get().dispose();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.embeddedt.modernfix.world.gen;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface ExtendedSurfaceContext {
|
||||||
|
ThreadLocal<Set<ResourceKey<Biome>>> COMPUTED_POSSIBLE_BIOMES = new ThreadLocal<>();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
Set<ResourceKey<Biome>> mfix$getPossibleBiomes();
|
||||||
|
|
||||||
|
void mfix$applyPossibleBiomes();
|
||||||
|
}
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
package org.embeddedt.modernfix.world.gen;
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.util.KeyDispatchDataCodec;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.levelgen.SurfaceRules;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class SurfaceRuleOptimizer {
|
|
||||||
public static SurfaceRules.RuleSource optimizeSequenceRuleSource(SurfaceRules.SequenceRuleSource source) {
|
|
||||||
// First pass: collect which biomes appear and count biome-gated branches
|
|
||||||
Reference2ObjectOpenHashMap<ResourceKey<Biome>, List<SurfaceRules.RuleSource>> perBiomeSources = null;
|
|
||||||
int biomeGatedBranches = 0;
|
|
||||||
var sequence = source.sequence();
|
|
||||||
//noinspection ForLoopReplaceableByForEach
|
|
||||||
for (int i = 0; i < sequence.size(); i++) {
|
|
||||||
if (sequence.get(i) instanceof SurfaceRules.TestRuleSource testRuleSource
|
|
||||||
&& testRuleSource.ifTrue() instanceof SurfaceRules.BiomeConditionSource biomeConditionSource) {
|
|
||||||
biomeGatedBranches++;
|
|
||||||
if (perBiomeSources == null) {
|
|
||||||
perBiomeSources = new Reference2ObjectOpenHashMap<>();
|
|
||||||
}
|
|
||||||
for (var biome : biomeConditionSource.biomes) {
|
|
||||||
perBiomeSources.putIfAbsent(biome, new ArrayList<>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (biomeGatedBranches < 3) {
|
|
||||||
// Just use the source as-is, not worth optimizing
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
// Second pass: build per-biome source lists preserving original interleaving order
|
|
||||||
List<SurfaceRules.RuleSource> noMatchSources = new ArrayList<>();
|
|
||||||
//noinspection ForLoopReplaceableByForEach
|
|
||||||
for (int i = 0; i < sequence.size(); i++) {
|
|
||||||
var innerSource = sequence.get(i);
|
|
||||||
if (innerSource instanceof SurfaceRules.TestRuleSource testRuleSource
|
|
||||||
&& testRuleSource.ifTrue() instanceof SurfaceRules.BiomeConditionSource biomeConditionSource) {
|
|
||||||
// Add the inner rule (condition stripped) only to the matching biomes' lists
|
|
||||||
for (var biome : biomeConditionSource.biomes) {
|
|
||||||
perBiomeSources.get(biome).add(testRuleSource.thenRun());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Non-biome-gated rule: add to every biome list and the no-match list
|
|
||||||
for (var list : perBiomeSources.values()) {
|
|
||||||
list.add(innerSource);
|
|
||||||
}
|
|
||||||
noMatchSources.add(innerSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
ResourceKey<Biome>[] biomeKeys = new ResourceKey[perBiomeSources.size()];
|
|
||||||
SurfaceRules.RuleSource[][] sourcesPerBiome = new SurfaceRules.RuleSource[perBiomeSources.size()][];
|
|
||||||
int i = 0;
|
|
||||||
for (var entry : Reference2ObjectMaps.fastIterable(perBiomeSources)) {
|
|
||||||
biomeKeys[i] = entry.getKey();
|
|
||||||
sourcesPerBiome[i] = entry.getValue().toArray(new SurfaceRules.RuleSource[0]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return new OptimizedBiomeLookupSequenceRule(biomeKeys, sourcesPerBiome, noMatchSources.toArray(new SurfaceRules.RuleSource[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public record OptimizedBiomeLookupSequenceRule(
|
|
||||||
ResourceKey<Biome>[] biomeKeys,
|
|
||||||
SurfaceRules.RuleSource[][] sourcesPerBiome,
|
|
||||||
SurfaceRules.RuleSource[] sourcesForNoBiomeMatch
|
|
||||||
) implements SurfaceRules.RuleSource {
|
|
||||||
@Override
|
|
||||||
public SurfaceRules.SurfaceRule apply(SurfaceRules.Context context) {
|
|
||||||
var biomeKeys = this.biomeKeys;
|
|
||||||
var sourcesPerBiome = this.sourcesPerBiome;
|
|
||||||
Reference2ObjectOpenHashMap<ResourceKey<Biome>, List<SurfaceRules.SurfaceRule>> compiledBiomeMatch =
|
|
||||||
new Reference2ObjectOpenHashMap<>(biomeKeys.length);
|
|
||||||
for (int i = 0; i < biomeKeys.length; i++) {
|
|
||||||
var uncompiled = sourcesPerBiome[i];
|
|
||||||
SurfaceRules.SurfaceRule[] compiled = new SurfaceRules.SurfaceRule[uncompiled.length];
|
|
||||||
for (int j = 0; j < uncompiled.length; j++) {
|
|
||||||
compiled[j] = uncompiled[j].apply(context);
|
|
||||||
}
|
|
||||||
compiledBiomeMatch.put(biomeKeys[i], List.of(compiled));
|
|
||||||
}
|
|
||||||
var sourcesForNoBiomeMatch = this.sourcesForNoBiomeMatch;
|
|
||||||
List<SurfaceRules.SurfaceRule> compiledNoMatchList;
|
|
||||||
if (sourcesForNoBiomeMatch.length > 0) {
|
|
||||||
SurfaceRules.SurfaceRule[] compiledNoMatch = new SurfaceRules.SurfaceRule[sourcesForNoBiomeMatch.length];
|
|
||||||
for (int i = 0; i < sourcesForNoBiomeMatch.length; i++) {
|
|
||||||
compiledNoMatch[i] = sourcesForNoBiomeMatch[i].apply(context);
|
|
||||||
}
|
|
||||||
compiledNoMatchList = List.of(compiledNoMatch);
|
|
||||||
} else {
|
|
||||||
compiledNoMatchList = List.of();
|
|
||||||
}
|
|
||||||
return new CompiledOptimizedBiomeLookupRule(compiledBiomeMatch, compiledNoMatchList, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeyDispatchDataCodec<? extends SurfaceRules.RuleSource> codec() {
|
|
||||||
throw new UnsupportedOperationException("Do not try to serialize OptimizedBiomeLookupSequenceRule");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private record CompiledOptimizedBiomeLookupRule(
|
|
||||||
Map<ResourceKey<Biome>, List<SurfaceRules.SurfaceRule>> rulesForBiomeMatch,
|
|
||||||
List<SurfaceRules.SurfaceRule> rulesForNoBiomeMatch,
|
|
||||||
SurfaceRules.Context context
|
|
||||||
) implements SurfaceRules.SurfaceRule {
|
|
||||||
@Override
|
|
||||||
public @Nullable BlockState tryApply(int x, int y, int z) {
|
|
||||||
var biome = context.biome.get();
|
|
||||||
var key = (biome instanceof Holder.Reference<Biome> ref) ? ref.key() : biome.unwrapKey().orElseThrow();
|
|
||||||
var ruleList = rulesForBiomeMatch.getOrDefault(key, rulesForNoBiomeMatch);
|
|
||||||
//noinspection ForLoopReplaceableByForEach
|
|
||||||
for (int i = 0; i < ruleList.size(); i++) {
|
|
||||||
var rule = ruleList.get(i);
|
|
||||||
var state = rule.tryApply(x, y, z);
|
|
||||||
if (state != null) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
CompiledOptimizedBiomeLookupRule that = (CompiledOptimizedBiomeLookupRule) o;
|
|
||||||
return rulesForBiomeMatch.equals(that.rulesForBiomeMatch) && rulesForNoBiomeMatch.equals(that.rulesForNoBiomeMatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(rulesForBiomeMatch, rulesForNoBiomeMatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user