diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index a04dd51fd..d0652fde7 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -10,7 +10,7 @@ object Versions { const val tectonic = "4.3.1" const val paralithic = "2.0.1" const val strata = "1.3.2" - const val seismic = "2.5.0" + const val seismic = "2.5.1" const val cloud = "2.0.0" diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BaseBiomeColumn.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BaseBiomeColumn.java index 4af6cc838..dd97af0ff 100644 --- a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BaseBiomeColumn.java +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BaseBiomeColumn.java @@ -46,6 +46,6 @@ class BaseBiomeColumn implements Column { @Override public Biome get(int y) { - return biomeProvider.extrude(base, x, y, z, seed); + return biomeProvider.pipeline.extrude(base, x, y, z, seed); } } diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionProvider.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionProvider.java index aca41216f..df9bc1a94 100644 --- a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionProvider.java +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/BiomeExtrusionProvider.java @@ -6,15 +6,17 @@ import java.util.Set; import java.util.stream.Collectors; import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; +import com.dfsek.terra.addons.biome.extrusion.utils.ExtrusionPipeline; +import com.dfsek.terra.addons.biome.extrusion.utils.ExtrusionPipelineFactory; import com.dfsek.terra.api.util.Column; import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; public class BiomeExtrusionProvider implements BiomeProvider { + public final ExtrusionPipeline pipeline; private final BiomeProvider delegate; private final Set biomes; - private final ExtrusionPipeline pipeline; private final int resolution; public BiomeExtrusionProvider(BiomeProvider delegate, List extrusions, int resolution) { @@ -30,11 +32,7 @@ public class BiomeExtrusionProvider implements BiomeProvider { @Override public Biome getBiome(int x, int y, int z, long seed) { Biome delegated = delegate.getBiome(x, y, z, seed); - return extrude(delegated, x, y, z, seed); - } - - public Biome extrude(Biome original, int x, int y, int z, long seed) { - return pipeline.extrude(original, x, y, z, seed); + return pipeline.extrude(delegated, x, y, z, seed); } @Override diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/ReplaceExtrusion.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/ReplaceExtrusion.java index 0e062977d..a03e3528e 100644 --- a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/ReplaceExtrusion.java +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/extrusions/ReplaceExtrusion.java @@ -1,43 +1,64 @@ package com.dfsek.terra.addons.biome.extrusion.extrusions; import com.dfsek.seismic.type.sampler.Sampler; - -import java.util.Collection; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; import com.dfsek.terra.addons.biome.query.api.BiomeQueries; import com.dfsek.terra.api.util.collection.ProbabilityCollection; +import com.dfsek.terra.api.util.collection.TriStateIntCache; import com.dfsek.terra.api.util.range.Range; import com.dfsek.terra.api.world.biome.Biome; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicLongArray; +import java.util.function.IntPredicate; +import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Sets biomes at locations based on a sampler. */ public class ReplaceExtrusion implements Extrusion { private final Sampler sampler; - private final Range range; - private final ProbabilityCollection biomes; - private final Predicate hasTag; + // Replaced ThreadLocal with a specialized primitive cache. + // Shared across all threads safely. + private final TriStateIntCache cache; + public ReplaceExtrusion(Sampler sampler, Range range, ProbabilityCollection biomes, String tag) { this.sampler = sampler; this.range = range; this.biomes = biomes; this.hasTag = BiomeQueries.has(tag); + + this.cache = new TriStateIntCache(65536); } @Override public Biome extrude(Biome original, int x, int y, int z, long seed) { - if(hasTag.test(original)) { - return range.ifInRange(y, () -> biomes.get(sampler, x, y, z, seed).get(original), original); + int id = original.getIntID(); + + long state = cache.get(id); + boolean passes; + + if (state == TriStateIntCache.STATE_UNSET) { + // Only run the test if unset in cache + passes = hasTag.test(original); + cache.set(id, passes); + } else { + // Read the primitive long directly + passes = (state == TriStateIntCache.STATE_TRUE); } + + if (passes) { + if (range.isInRange(y)) { + return biomes.get(sampler, x, y, z, seed).get(original); + } + } + return original; } diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/ExtrusionPipeline.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/utils/ExtrusionPipeline.java similarity index 74% rename from common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/ExtrusionPipeline.java rename to common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/utils/ExtrusionPipeline.java index ff6e0d19c..a9548763f 100644 --- a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/ExtrusionPipeline.java +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/utils/ExtrusionPipeline.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.addons.biome.extrusion; +package com.dfsek.terra.addons.biome.extrusion.utils; import com.dfsek.terra.api.world.biome.Biome; diff --git a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/ExtrusionPipelineFactory.java b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/utils/ExtrusionPipelineFactory.java similarity index 99% rename from common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/ExtrusionPipelineFactory.java rename to common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/utils/ExtrusionPipelineFactory.java index 934d7fe56..d1a976dde 100644 --- a/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/ExtrusionPipelineFactory.java +++ b/common/addons/biome-provider-extrusion/src/main/java/com/dfsek/terra/addons/biome/extrusion/utils/ExtrusionPipelineFactory.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.addons.biome.extrusion; +package com.dfsek.terra.addons.biome.extrusion.utils; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; diff --git a/common/addons/config-biome/src/main/java/com/dfsek/terra/addons/biome/UserDefinedBiome.java b/common/addons/config-biome/src/main/java/com/dfsek/terra/addons/biome/UserDefinedBiome.java index 24f5c64cb..86b878f08 100644 --- a/common/addons/config-biome/src/main/java/com/dfsek/terra/addons/biome/UserDefinedBiome.java +++ b/common/addons/config-biome/src/main/java/com/dfsek/terra/addons/biome/UserDefinedBiome.java @@ -8,6 +8,7 @@ package com.dfsek.terra.addons.biome; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import com.dfsek.terra.api.properties.Context; import com.dfsek.terra.api.world.biome.Biome; @@ -18,6 +19,7 @@ import com.dfsek.terra.api.world.biome.PlatformBiome; * Class representing a config-defined biome */ public class UserDefinedBiome implements Biome { + private final static AtomicInteger INT_ID_COUNTER = new AtomicInteger(0); private final PlatformBiome vanilla; private final String id; private final BiomeTemplate config; @@ -25,6 +27,7 @@ public class UserDefinedBiome implements Biome { private final Set tags; private final Context context = new Context(); + private final int intID; public UserDefinedBiome(PlatformBiome vanilla, BiomeTemplate config) { this.vanilla = vanilla; @@ -32,6 +35,7 @@ public class UserDefinedBiome implements Biome { this.config = config; this.color = config.getColor(); this.tags = config.getTags(); + this.intID = INT_ID_COUNTER.getAndIncrement(); tags.add("BIOME:" + id); tags.add("ALL"); } @@ -61,6 +65,11 @@ public class UserDefinedBiome implements Biome { return tags; } + @Override + public int getIntID() { + return intID; + } + @Override public String getID() { return id; diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/collection/TriStateIntCache.java b/common/api/src/main/java/com/dfsek/terra/api/util/collection/TriStateIntCache.java new file mode 100644 index 000000000..9aec70eb0 --- /dev/null +++ b/common/api/src/main/java/com/dfsek/terra/api/util/collection/TriStateIntCache.java @@ -0,0 +1,51 @@ +package com.dfsek.terra.api.util.collection; + +import java.util.concurrent.atomic.AtomicLongArray; + +public class TriStateIntCache { + public static final long STATE_UNSET = 0L; + public static final long STATE_FALSE = 1L; + public static final long STATE_TRUE = 2L; + + private static final long BIT_MASK = 3L; + private final AtomicLongArray data; + + public TriStateIntCache(int maxKeySize) { + this.data = new AtomicLongArray((maxKeySize + 31) >>> 5); + } + + /** + * Checks the cache state without any allocation. + * @return STATE_UNSET (0), STATE_FALSE (1), or STATE_TRUE (2) + */ + public long get(int key) { + int arrayIndex = key >>> 5; + int bitShift = (key & 31) << 1; + long currentWord = data.get(arrayIndex); + return (currentWord >>> bitShift) & BIT_MASK; + } + + /** + * Sets the value safely. Handles race conditions internally. + */ + public void set(int key, boolean value) { + int arrayIndex = key >>> 5; + int bitShift = (key & 31) << 1; + long targetState = value ? STATE_TRUE : STATE_FALSE; + + long currentWord, newWord; + do { + currentWord = data.get(arrayIndex); + + // Race condition check: + long existingState = (currentWord >>> bitShift) & BIT_MASK; + if (existingState != STATE_UNSET) { + return; // Already set, abort our update + } + + // Create new word with our bit set + newWord = (currentWord & ~(BIT_MASK << bitShift)) | (targetState << bitShift); + + } while (!data.compareAndSet(arrayIndex, currentWord, newWord)); + } +} \ No newline at end of file diff --git a/common/api/src/main/java/com/dfsek/terra/api/world/biome/Biome.java b/common/api/src/main/java/com/dfsek/terra/api/world/biome/Biome.java index 907058466..009b71a68 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/world/biome/Biome.java +++ b/common/api/src/main/java/com/dfsek/terra/api/world/biome/Biome.java @@ -39,4 +39,12 @@ public interface Biome extends PropertyHolder, StringIdentifiable { * @return A {@link Set} of String tags this biome holds. */ Set getTags(); + + + /** + * Get the numeric ID of this biome, generated at registration time + * + * @return The numeric ID. + */ + int getIntID(); }