More Extrusion Opts

This commit is contained in:
Zoe Gidiere
2025-12-10 18:49:03 -07:00
parent ddc8cc7db5
commit dd2f0365b0
9 changed files with 107 additions and 20 deletions

View File

@@ -10,7 +10,7 @@ object Versions {
const val tectonic = "4.3.1" const val tectonic = "4.3.1"
const val paralithic = "2.0.1" const val paralithic = "2.0.1"
const val strata = "1.3.2" const val strata = "1.3.2"
const val seismic = "2.5.0" const val seismic = "2.5.1"
const val cloud = "2.0.0" const val cloud = "2.0.0"

View File

@@ -46,6 +46,6 @@ class BaseBiomeColumn implements Column<Biome> {
@Override @Override
public Biome get(int y) { public Biome get(int y) {
return biomeProvider.extrude(base, x, y, z, seed); return biomeProvider.pipeline.extrude(base, x, y, z, seed);
} }
} }

View File

@@ -6,15 +6,17 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.dfsek.terra.addons.biome.extrusion.api.Extrusion; 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.util.Column;
import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomeExtrusionProvider implements BiomeProvider { public class BiomeExtrusionProvider implements BiomeProvider {
public final ExtrusionPipeline pipeline;
private final BiomeProvider delegate; private final BiomeProvider delegate;
private final Set<Biome> biomes; private final Set<Biome> biomes;
private final ExtrusionPipeline pipeline;
private final int resolution; private final int resolution;
public BiomeExtrusionProvider(BiomeProvider delegate, List<Extrusion> extrusions, int resolution) { public BiomeExtrusionProvider(BiomeProvider delegate, List<Extrusion> extrusions, int resolution) {
@@ -30,11 +32,7 @@ public class BiomeExtrusionProvider implements BiomeProvider {
@Override @Override
public Biome getBiome(int x, int y, int z, long seed) { public Biome getBiome(int x, int y, int z, long seed) {
Biome delegated = delegate.getBiome(x, y, z, seed); Biome delegated = delegate.getBiome(x, y, z, seed);
return extrude(delegated, x, y, z, seed); return pipeline.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);
} }
@Override @Override

View File

@@ -1,43 +1,64 @@
package com.dfsek.terra.addons.biome.extrusion.extrusions; package com.dfsek.terra.addons.biome.extrusion.extrusions;
import com.dfsek.seismic.type.sampler.Sampler; 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.Extrusion;
import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome; import com.dfsek.terra.addons.biome.extrusion.api.ReplaceableBiome;
import com.dfsek.terra.addons.biome.query.api.BiomeQueries; import com.dfsek.terra.addons.biome.query.api.BiomeQueries;
import com.dfsek.terra.api.util.collection.ProbabilityCollection; 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.util.range.Range;
import com.dfsek.terra.api.world.biome.Biome; 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. * Sets biomes at locations based on a sampler.
*/ */
public class ReplaceExtrusion implements Extrusion { public class ReplaceExtrusion implements Extrusion {
private final Sampler sampler; private final Sampler sampler;
private final Range range; private final Range range;
private final ProbabilityCollection<ReplaceableBiome> biomes; private final ProbabilityCollection<ReplaceableBiome> biomes;
private final Predicate<Biome> hasTag; private final Predicate<Biome> hasTag;
// Replaced ThreadLocal<HashMap> with a specialized primitive cache.
// Shared across all threads safely.
private final TriStateIntCache cache;
public ReplaceExtrusion(Sampler sampler, Range range, ProbabilityCollection<ReplaceableBiome> biomes, String tag) { public ReplaceExtrusion(Sampler sampler, Range range, ProbabilityCollection<ReplaceableBiome> biomes, String tag) {
this.sampler = sampler; this.sampler = sampler;
this.range = range; this.range = range;
this.biomes = biomes; this.biomes = biomes;
this.hasTag = BiomeQueries.has(tag); this.hasTag = BiomeQueries.has(tag);
this.cache = new TriStateIntCache(65536);
} }
@Override @Override
public Biome extrude(Biome original, int x, int y, int z, long seed) { public Biome extrude(Biome original, int x, int y, int z, long seed) {
if(hasTag.test(original)) { int id = original.getIntID();
return range.ifInRange(y, () -> biomes.get(sampler, x, y, z, seed).get(original), original);
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; return original;
} }

View File

@@ -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; import com.dfsek.terra.api.world.biome.Biome;

View File

@@ -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.ClassWriter;
import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.FieldVisitor;

View File

@@ -8,6 +8,7 @@
package com.dfsek.terra.addons.biome; package com.dfsek.terra.addons.biome;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import com.dfsek.terra.api.properties.Context; import com.dfsek.terra.api.properties.Context;
import com.dfsek.terra.api.world.biome.Biome; 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 * Class representing a config-defined biome
*/ */
public class UserDefinedBiome implements Biome { public class UserDefinedBiome implements Biome {
private final static AtomicInteger INT_ID_COUNTER = new AtomicInteger(0);
private final PlatformBiome vanilla; private final PlatformBiome vanilla;
private final String id; private final String id;
private final BiomeTemplate config; private final BiomeTemplate config;
@@ -25,6 +27,7 @@ public class UserDefinedBiome implements Biome {
private final Set<String> tags; private final Set<String> tags;
private final Context context = new Context(); private final Context context = new Context();
private final int intID;
public UserDefinedBiome(PlatformBiome vanilla, BiomeTemplate config) { public UserDefinedBiome(PlatformBiome vanilla, BiomeTemplate config) {
this.vanilla = vanilla; this.vanilla = vanilla;
@@ -32,6 +35,7 @@ public class UserDefinedBiome implements Biome {
this.config = config; this.config = config;
this.color = config.getColor(); this.color = config.getColor();
this.tags = config.getTags(); this.tags = config.getTags();
this.intID = INT_ID_COUNTER.getAndIncrement();
tags.add("BIOME:" + id); tags.add("BIOME:" + id);
tags.add("ALL"); tags.add("ALL");
} }
@@ -61,6 +65,11 @@ public class UserDefinedBiome implements Biome {
return tags; return tags;
} }
@Override
public int getIntID() {
return intID;
}
@Override @Override
public String getID() { public String getID() {
return id; return id;

View File

@@ -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));
}
}

View File

@@ -39,4 +39,12 @@ public interface Biome extends PropertyHolder, StringIdentifiable {
* @return A {@link Set} of String tags this biome holds. * @return A {@link Set} of String tags this biome holds.
*/ */
Set<String> getTags(); Set<String> getTags();
/**
* Get the numeric ID of this biome, generated at registration time
*
* @return The numeric ID.
*/
int getIntID();
} }