This commit is contained in:
Brian Neumann-Fopiano committed 2026-06-03 01:21:14 -04:00
1 parent 1a6fff35e8
commit 11efae428f
56 files changed
+2052 -2694

No files matched your search

@@ -42,6 +42,7 @@ public class CustomBiomeSource extends BiomeSource {
private final KMap<String, Holder<Biome>> customBiomes;
private final Holder<Biome> fallbackBiome;
private final ConcurrentHashMap<Long, Holder<Biome>> noiseBiomeCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Long, Holder<Biome>> structureBiomeCache = new ConcurrentHashMap<>();
public CustomBiomeSource(long seed, Engine engine, World world) {
this.engine = engine;
@@ -173,13 +174,33 @@ public class CustomBiomeSource extends BiomeSource {
@Override
public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
long cacheKey = packNoiseKey(x, y, z);
Holder<Biome> cachedHolder = structureBiomeCache.get(cacheKey);
if (cachedHolder != null) {
return cachedHolder;
}
Holder<Biome> resolvedHolder = resolveStructureBiomeHolder(x, y, z);
Holder<Biome> existingHolder = structureBiomeCache.putIfAbsent(cacheKey, resolvedHolder);
if (existingHolder != null) {
return existingHolder;
}
if (structureBiomeCache.size() > NOISE_BIOME_CACHE_MAX) {
structureBiomeCache.clear();
}
return resolvedHolder;
}
public Holder<Biome> getVisibleNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
long cacheKey = packNoiseKey(x, y, z);
Holder<Biome> cachedHolder = noiseBiomeCache.get(cacheKey);
if (cachedHolder != null) {
return cachedHolder;
}
Holder<Biome> resolvedHolder = resolveNoiseBiomeHolder(x, y, z);
Holder<Biome> resolvedHolder = resolveVisibleBiomeHolder(x, y, z);
Holder<Biome> existingHolder = noiseBiomeCache.putIfAbsent(cacheKey, resolvedHolder);
if (existingHolder != null) {
return existingHolder;
@@ -192,15 +213,66 @@ public class CustomBiomeSource extends BiomeSource {
return resolvedHolder;
}
private Holder<Biome> resolveNoiseBiomeHolder(int x, int y, int z) {
if (engine == null || engine.isClosed()) {
private Holder<Biome> resolveStructureBiomeHolder(int x, int y, int z) {
BiomeResolution resolution = resolveBiomeResolution(x, y, z);
if (resolution == null) {
return getFallbackBiome();
}
if (engine.getComplex() == null) {
if (resolution.irisBiome.isCustom()) {
return resolveCustomHolder(resolution);
}
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, resolution.irisBiome.getVanillaDerivative());
if (holder != null) {
return holder;
}
return getFallbackBiome();
}
private Holder<Biome> resolveVisibleBiomeHolder(int x, int y, int z) {
BiomeResolution resolution = resolveBiomeResolution(x, y, z);
if (resolution == null) {
return getFallbackBiome();
}
if (resolution.irisBiome.isCustom()) {
return resolveCustomHolder(resolution);
}
org.bukkit.block.Biome vanillaBiome = resolution.underground
? resolution.irisBiome.getGroundBiome(resolution.rng, resolution.blockX, resolution.blockY, resolution.blockZ)
: resolution.irisBiome.getSkyBiome(resolution.rng, resolution.blockX, resolution.blockY, resolution.blockZ);
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, vanillaBiome);
if (holder != null) {
return holder;
}
return getFallbackBiome();
}
private Holder<Biome> resolveCustomHolder(BiomeResolution resolution) {
IrisBiomeCustom customBiome = resolution.irisBiome.getCustomBiome(resolution.rng, resolution.blockX, resolution.blockY, resolution.blockZ);
if (customBiome != null) {
Holder<Biome> holder = customBiomes.get(customBiome.getId());
if (holder != null) {
return holder;
}
}
return getFallbackBiome();
}
private BiomeResolution resolveBiomeResolution(int x, int y, int z) {
if (engine == null || engine.isClosed()) {
return null;
}
if (engine.getComplex() == null) {
return null;
}
int blockX = x << 2;
int blockZ = z << 2;
int blockY = y << 2;
@@ -218,7 +290,7 @@ public class CustomBiomeSource extends BiomeSource {
irisBiome = engine.getComplex().getTrueBiomeStream().get(blockX, blockZ);
}
if (irisBiome == null) {
return getFallbackBiome();
return null;
}
RNG noiseRng = new RNG(seed
@@ -226,27 +298,7 @@ public class CustomBiomeSource extends BiomeSource {
^ (((long) blockY) * 132897987541L)
^ (((long) blockZ) * 42317861L));
if (irisBiome.isCustom()) {
IrisBiomeCustom customBiome = irisBiome.getCustomBiome(noiseRng, blockX, blockY, blockZ);
if (customBiome != null) {
Holder<Biome> holder = customBiomes.get(customBiome.getId());
if (holder != null) {
return holder;
}
}
return getFallbackBiome();
}
org.bukkit.block.Biome vanillaBiome = underground
? irisBiome.getGroundBiome(noiseRng, blockX, blockY, blockZ)
: irisBiome.getSkyBiome(noiseRng, blockX, blockY, blockZ);
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, vanillaBiome);
if (holder != null) {
return holder;
}
return getFallbackBiome();
return new BiomeResolution(irisBiome, underground, blockX, blockY, blockZ, noiseRng);
}
private Holder<Biome> getFallbackBiome() {
@@ -328,4 +380,22 @@ public class CustomBiomeSource extends BiomeSource {
return null;
}
private static final class BiomeResolution {
private final IrisBiome irisBiome;
private final boolean underground;
private final int blockX;
private final int blockY;
private final int blockZ;
private final RNG rng;
private BiomeResolution(IrisBiome irisBiome, boolean underground, int blockX, int blockY, int blockZ, RNG rng) {
this.irisBiome = irisBiome;
this.underground = underground;
this.blockX = blockX;
this.blockY = blockY;
this.blockZ = blockZ;
this.rng = rng;
}
}
}
@@ -50,11 +50,18 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
private final ChunkGenerator delegate;
private final Engine engine;
private final CustomBiomeSource customBiomeSource;
private volatile Set<String> reachableStructureKeysCache;
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
this(delegate, engine, world, new CustomBiomeSource(seed, engine, world));
}
private IrisChunkGenerator(ChunkGenerator delegate, Engine engine, World world, CustomBiomeSource customBiomeSource) {
super(((CraftWorld) world).getHandle(), edit(delegate, customBiomeSource), null);
this.delegate = delegate;
this.engine = engine;
this.customBiomeSource = customBiomeSource;
}
@Override
@@ -91,13 +98,40 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
if (!importedControl().active()) {
return null;
}
HolderSet<Structure> reachable = filterReachableStructures(level, holders);
if (reachable == null || reachable.size() == 0) {
return null;
}
try {
return delegate.findNearestMapStructure(level, holders, pos, radius, findUnexplored);
return delegate.findNearestMapStructure(level, reachable, pos, radius, findUnexplored);
} catch (Throwable e) {
return null;
}
}
private HolderSet<Structure> filterReachableStructures(ServerLevel level, HolderSet<Structure> holders) {
Set<String> reachable = reachableStructureKeysCache;
if (reachable == null) {
reachable = VanillaStructureBiomes.reachableStructureKeys(level, delegate.getBiomeSource());
reachableStructureKeysCache = reachable;
}
if (reachable.isEmpty()) {
return holders;
}
Registry<Structure> registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
List<Holder<Structure>> kept = new ArrayList<>();
for (Holder<Structure> holder : holders) {
Object id = registry.getKey(holder.value());
if (id != null && reachable.contains(id.toString())) {
kept.add(holder);
}
}
if (kept.size() == holders.size()) {
return holders;
}
return HolderSet.direct(kept);
}
@Override
protected MapCodec<? extends ChunkGenerator> codec() {
return MapCodec.unit(null);
@@ -144,7 +178,8 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
@Override
public CompletableFuture<ChunkAccess> createBiomes(RandomState randomstate, Blender blender, StructureManager structuremanager, ChunkAccess ichunkaccess) {
return delegate.createBiomes(randomstate, blender, structuremanager, ichunkaccess);
ichunkaccess.fillBiomesFromNoise(customBiomeSource::getVisibleNoiseBiome, randomstate.sampler());
return CompletableFuture.completedFuture(ichunkaccess);
}
@Override
@@ -44,6 +44,7 @@ import net.minecraft.tags.TagKey;
import net.minecraft.world.attribute.EnvironmentAttributes;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
@@ -89,9 +90,12 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
public class NMSBinding implements INMSBinding {
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
@@ -412,6 +416,43 @@ public class NMSBinding implements INMSBinding {
return keys;
}
@Override
public KList<String> getReachableStructureKeys(World world) {
KList<String> keys = new KList<>();
try {
ServerLevel level = ((CraftWorld) world).getHandle();
BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource();
keys.addAll(VanillaStructureBiomes.reachableStructureKeys(level, source));
} catch (Throwable e) {
Iris.reportError(e);
}
return keys;
}
@Override
public KList<String> getStructureBiomeKeys(String structureKey) {
KList<String> keys = new KList<>();
try {
keys.addAll(VanillaStructureBiomes.structureBiomeKeys(registry(), structureKey));
} catch (Throwable e) {
Iris.reportError(e);
}
return keys;
}
@Override
public KList<String> getPossibleBiomeKeys(World world) {
KList<String> keys = new KList<>();
try {
ServerLevel level = ((CraftWorld) world).getHandle();
BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource();
keys.addAll(VanillaStructureBiomes.possibleBiomeKeys(source));
} catch (Throwable e) {
Iris.reportError(e);
}
return keys;
}
@Override
public boolean isBukkit() {
return true;
@@ -555,6 +596,42 @@ public class NMSBinding implements INMSBinding {
});
}
@Override
public boolean purgeChunk(World world, int x, int z) {
ServerLevel level = ((CraftWorld) world).getHandle();
try {
CountDownLatch latch = new CountDownLatch(1);
Runnable unload = () -> {
try {
if (world.isChunkLoaded(x, z)) {
world.unloadChunk(x, z, false);
}
} finally {
latch.countDown();
}
};
if (!J.runRegion(world, x, z, unload)) {
return false;
}
if (!latch.await(15, TimeUnit.SECONDS)) {
Iris.warn("Chunk purge timed out waiting to unload " + x + "," + z + " in " + world.getName() + ".");
return false;
}
for (MoonriseRegionFileIO.RegionFileType type : MoonriseRegionFileIO.RegionFileType.values()) {
MoonriseRegionFileIO.scheduleSave(level, x, z, null, type);
}
MoonriseRegionFileIO.flush(level);
return true;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
} catch (Throwable e) {
Iris.reportError(e);
return false;
}
}
public ItemStack applyCustomNbt(ItemStack itemStack, KMap<String, Object> customNbt) throws IllegalArgumentException {
if (customNbt != null && !customNbt.isEmpty()) {
net.minecraft.world.item.ItemStack s = CraftItemStack.asNMSCopy(itemStack);
@@ -0,0 +1,77 @@
package art.arcane.iris.core.nms.v1_21_R7;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.levelgen.structure.Structure;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
final class VanillaStructureBiomes {
private VanillaStructureBiomes() {
}
static Set<String> possibleBiomeKeys(BiomeSource source) {
Set<String> keys = new LinkedHashSet<>();
if (source == null) {
return keys;
}
for (Holder<Biome> holder : source.possibleBiomes()) {
Optional<ResourceKey<Biome>> key = holder.unwrapKey();
if (key.isPresent()) {
keys.add(key.get().identifier().toString());
}
}
return keys;
}
static Set<String> structureBiomeKeys(RegistryAccess access, String structureKey) {
Set<String> keys = new LinkedHashSet<>();
if (access == null || structureKey == null || structureKey.isEmpty()) {
return keys;
}
Registry<Structure> registry = access.lookupOrThrow(Registries.STRUCTURE);
Structure structure = registry.getValue(Identifier.parse(structureKey));
if (structure == null) {
return keys;
}
for (Holder<Biome> holder : structure.biomes()) {
Optional<ResourceKey<Biome>> key = holder.unwrapKey();
if (key.isPresent()) {
keys.add(key.get().identifier().toString());
}
}
return keys;
}
static Set<String> reachableStructureKeys(ServerLevel level, BiomeSource source) {
Set<String> reachable = new LinkedHashSet<>();
if (level == null || source == null) {
return reachable;
}
Set<String> possible = possibleBiomeKeys(source);
if (possible.isEmpty()) {
return reachable;
}
Registry<Structure> registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
for (Map.Entry<ResourceKey<Structure>, Structure> entry : registry.entrySet()) {
for (Holder<Biome> holder : entry.getValue().biomes()) {
Optional<ResourceKey<Biome>> key = holder.unwrapKey();
if (key.isPresent() && possible.contains(key.get().identifier().toString())) {
reachable.add(entry.getKey().identifier().toString());
break;
}
}
}
return reachable;
}
}
@@ -42,6 +42,7 @@ public class CustomBiomeSource extends BiomeSource {
private final KMap<String, Holder<Biome>> customBiomes;
private final Holder<Biome> fallbackBiome;
private final ConcurrentHashMap<Long, Holder<Biome>> noiseBiomeCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Long, Holder<Biome>> structureBiomeCache = new ConcurrentHashMap<>();
public CustomBiomeSource(long seed, Engine engine, World world) {
this.engine = engine;
@@ -173,13 +174,33 @@ public class CustomBiomeSource extends BiomeSource {
@Override
public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
long cacheKey = packNoiseKey(x, y, z);
Holder<Biome> cachedHolder = structureBiomeCache.get(cacheKey);
if (cachedHolder != null) {
return cachedHolder;
}
Holder<Biome> resolvedHolder = resolveStructureBiomeHolder(x, y, z);
Holder<Biome> existingHolder = structureBiomeCache.putIfAbsent(cacheKey, resolvedHolder);
if (existingHolder != null) {
return existingHolder;
}
if (structureBiomeCache.size() > NOISE_BIOME_CACHE_MAX) {
structureBiomeCache.clear();
}
return resolvedHolder;
}
public Holder<Biome> getVisibleNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
long cacheKey = packNoiseKey(x, y, z);
Holder<Biome> cachedHolder = noiseBiomeCache.get(cacheKey);
if (cachedHolder != null) {
return cachedHolder;
}
Holder<Biome> resolvedHolder = resolveNoiseBiomeHolder(x, y, z);
Holder<Biome> resolvedHolder = resolveVisibleBiomeHolder(x, y, z);
Holder<Biome> existingHolder = noiseBiomeCache.putIfAbsent(cacheKey, resolvedHolder);
if (existingHolder != null) {
return existingHolder;
@@ -192,15 +213,66 @@ public class CustomBiomeSource extends BiomeSource {
return resolvedHolder;
}
private Holder<Biome> resolveNoiseBiomeHolder(int x, int y, int z) {
if (engine == null || engine.isClosed()) {
private Holder<Biome> resolveStructureBiomeHolder(int x, int y, int z) {
BiomeResolution resolution = resolveBiomeResolution(x, y, z);
if (resolution == null) {
return getFallbackBiome();
}
if (engine.getComplex() == null) {
if (resolution.irisBiome.isCustom()) {
return resolveCustomHolder(resolution);
}
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, resolution.irisBiome.getVanillaDerivative());
if (holder != null) {
return holder;
}
return getFallbackBiome();
}
private Holder<Biome> resolveVisibleBiomeHolder(int x, int y, int z) {
BiomeResolution resolution = resolveBiomeResolution(x, y, z);
if (resolution == null) {
return getFallbackBiome();
}
if (resolution.irisBiome.isCustom()) {
return resolveCustomHolder(resolution);
}
org.bukkit.block.Biome vanillaBiome = resolution.underground
? resolution.irisBiome.getGroundBiome(resolution.rng, resolution.blockX, resolution.blockY, resolution.blockZ)
: resolution.irisBiome.getSkyBiome(resolution.rng, resolution.blockX, resolution.blockY, resolution.blockZ);
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, vanillaBiome);
if (holder != null) {
return holder;
}
return getFallbackBiome();
}
private Holder<Biome> resolveCustomHolder(BiomeResolution resolution) {
IrisBiomeCustom customBiome = resolution.irisBiome.getCustomBiome(resolution.rng, resolution.blockX, resolution.blockY, resolution.blockZ);
if (customBiome != null) {
Holder<Biome> holder = customBiomes.get(customBiome.getId());
if (holder != null) {
return holder;
}
}
return getFallbackBiome();
}
private BiomeResolution resolveBiomeResolution(int x, int y, int z) {
if (engine == null || engine.isClosed()) {
return null;
}
if (engine.getComplex() == null) {
return null;
}
int blockX = x << 2;
int blockZ = z << 2;
int blockY = y << 2;
@@ -218,7 +290,7 @@ public class CustomBiomeSource extends BiomeSource {
irisBiome = engine.getComplex().getTrueBiomeStream().get(blockX, blockZ);
}
if (irisBiome == null) {
return getFallbackBiome();
return null;
}
RNG noiseRng = new RNG(seed
@@ -226,27 +298,7 @@ public class CustomBiomeSource extends BiomeSource {
^ (((long) blockY) * 132897987541L)
^ (((long) blockZ) * 42317861L));
if (irisBiome.isCustom()) {
IrisBiomeCustom customBiome = irisBiome.getCustomBiome(noiseRng, blockX, blockY, blockZ);
if (customBiome != null) {
Holder<Biome> holder = customBiomes.get(customBiome.getId());
if (holder != null) {
return holder;
}
}
return getFallbackBiome();
}
org.bukkit.block.Biome vanillaBiome = underground
? irisBiome.getGroundBiome(noiseRng, blockX, blockY, blockZ)
: irisBiome.getSkyBiome(noiseRng, blockX, blockY, blockZ);
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, vanillaBiome);
if (holder != null) {
return holder;
}
return getFallbackBiome();
return new BiomeResolution(irisBiome, underground, blockX, blockY, blockZ, noiseRng);
}
private Holder<Biome> getFallbackBiome() {
@@ -328,4 +380,22 @@ public class CustomBiomeSource extends BiomeSource {
return null;
}
private static final class BiomeResolution {
private final IrisBiome irisBiome;
private final boolean underground;
private final int blockX;
private final int blockY;
private final int blockZ;
private final RNG rng;
private BiomeResolution(IrisBiome irisBiome, boolean underground, int blockX, int blockY, int blockZ, RNG rng) {
this.irisBiome = irisBiome;
this.underground = underground;
this.blockX = blockX;
this.blockY = blockY;
this.blockZ = blockZ;
this.rng = rng;
}
}
}
@@ -50,11 +50,18 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
private final ChunkGenerator delegate;
private final Engine engine;
private final CustomBiomeSource customBiomeSource;
private volatile Set<String> reachableStructureKeysCache;
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
this(delegate, engine, world, new CustomBiomeSource(seed, engine, world));
}
private IrisChunkGenerator(ChunkGenerator delegate, Engine engine, World world, CustomBiomeSource customBiomeSource) {
super(((CraftWorld) world).getHandle(), edit(delegate, customBiomeSource), null);
this.delegate = delegate;
this.engine = engine;
this.customBiomeSource = customBiomeSource;
}
@Override
@@ -91,13 +98,40 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
if (!importedControl().active()) {
return null;
}
HolderSet<Structure> reachable = filterReachableStructures(level, holders);
if (reachable == null || reachable.size() == 0) {
return null;
}
try {
return delegate.findNearestMapStructure(level, holders, pos, radius, findUnexplored);
return delegate.findNearestMapStructure(level, reachable, pos, radius, findUnexplored);
} catch (Throwable e) {
return null;
}
}
private HolderSet<Structure> filterReachableStructures(ServerLevel level, HolderSet<Structure> holders) {
Set<String> reachable = reachableStructureKeysCache;
if (reachable == null) {
reachable = VanillaStructureBiomes.reachableStructureKeys(level, delegate.getBiomeSource());
reachableStructureKeysCache = reachable;
}
if (reachable.isEmpty()) {
return holders;
}
Registry<Structure> registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
List<Holder<Structure>> kept = new ArrayList<>();
for (Holder<Structure> holder : holders) {
Object id = registry.getKey(holder.value());
if (id != null && reachable.contains(id.toString())) {
kept.add(holder);
}
}
if (kept.size() == holders.size()) {
return holders;
}
return HolderSet.direct(kept);
}
@Override
protected MapCodec<? extends ChunkGenerator> codec() {
return MapCodec.unit(null);
@@ -144,7 +178,8 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
@Override
public CompletableFuture<ChunkAccess> createBiomes(RandomState randomstate, Blender blender, StructureManager structuremanager, ChunkAccess ichunkaccess) {
return delegate.createBiomes(randomstate, blender, structuremanager, ichunkaccess);
ichunkaccess.fillBiomesFromNoise(customBiomeSource::getVisibleNoiseBiome, randomstate.sampler());
return CompletableFuture.completedFuture(ichunkaccess);
}
@Override
@@ -44,6 +44,7 @@ import net.minecraft.tags.TagKey;
import net.minecraft.world.attribute.EnvironmentAttributes;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
@@ -89,9 +90,12 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
public class NMSBinding implements INMSBinding {
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
@@ -412,6 +416,43 @@ public class NMSBinding implements INMSBinding {
return keys;
}
@Override
public KList<String> getReachableStructureKeys(World world) {
KList<String> keys = new KList<>();
try {
ServerLevel level = ((CraftWorld) world).getHandle();
BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource();
keys.addAll(VanillaStructureBiomes.reachableStructureKeys(level, source));
} catch (Throwable e) {
Iris.reportError(e);
}
return keys;
}
@Override
public KList<String> getStructureBiomeKeys(String structureKey) {
KList<String> keys = new KList<>();
try {
keys.addAll(VanillaStructureBiomes.structureBiomeKeys(registry(), structureKey));
} catch (Throwable e) {
Iris.reportError(e);
}
return keys;
}
@Override
public KList<String> getPossibleBiomeKeys(World world) {
KList<String> keys = new KList<>();
try {
ServerLevel level = ((CraftWorld) world).getHandle();
BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource();
keys.addAll(VanillaStructureBiomes.possibleBiomeKeys(source));
} catch (Throwable e) {
Iris.reportError(e);
}
return keys;
}
@Override
public boolean isBukkit() {
return true;
@@ -555,6 +596,42 @@ public class NMSBinding implements INMSBinding {
});
}
@Override
public boolean purgeChunk(World world, int x, int z) {
ServerLevel level = ((CraftWorld) world).getHandle();
try {
CountDownLatch latch = new CountDownLatch(1);
Runnable unload = () -> {
try {
if (world.isChunkLoaded(x, z)) {
world.unloadChunk(x, z, false);
}
} finally {
latch.countDown();
}
};
if (!J.runRegion(world, x, z, unload)) {
return false;
}
if (!latch.await(15, TimeUnit.SECONDS)) {
Iris.warn("Chunk purge timed out waiting to unload " + x + "," + z + " in " + world.getName() + ".");
return false;
}
for (MoonriseRegionFileIO.RegionFileType type : MoonriseRegionFileIO.RegionFileType.values()) {
MoonriseRegionFileIO.scheduleSave(level, x, z, null, type);
}
MoonriseRegionFileIO.flush(level);
return true;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
} catch (Throwable e) {
Iris.reportError(e);
return false;
}
}
public ItemStack applyCustomNbt(ItemStack itemStack, KMap<String, Object> customNbt) throws IllegalArgumentException {
if (customNbt != null && !customNbt.isEmpty()) {
net.minecraft.world.item.ItemStack s = CraftItemStack.asNMSCopy(itemStack);
@@ -0,0 +1,77 @@
package art.arcane.iris.core.nms.v26_1_R1;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.levelgen.structure.Structure;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
final class VanillaStructureBiomes {
private VanillaStructureBiomes() {
}
static Set<String> possibleBiomeKeys(BiomeSource source) {
Set<String> keys = new LinkedHashSet<>();
if (source == null) {
return keys;
}
for (Holder<Biome> holder : source.possibleBiomes()) {
Optional<ResourceKey<Biome>> key = holder.unwrapKey();
if (key.isPresent()) {
keys.add(key.get().identifier().toString());
}
}
return keys;
}
static Set<String> structureBiomeKeys(RegistryAccess access, String structureKey) {
Set<String> keys = new LinkedHashSet<>();
if (access == null || structureKey == null || structureKey.isEmpty()) {
return keys;
}
Registry<Structure> registry = access.lookupOrThrow(Registries.STRUCTURE);
Structure structure = registry.getValue(Identifier.parse(structureKey));
if (structure == null) {
return keys;
}
for (Holder<Biome> holder : structure.biomes()) {
Optional<ResourceKey<Biome>> key = holder.unwrapKey();
if (key.isPresent()) {
keys.add(key.get().identifier().toString());
}
}
return keys;
}
static Set<String> reachableStructureKeys(ServerLevel level, BiomeSource source) {
Set<String> reachable = new LinkedHashSet<>();
if (level == null || source == null) {
return reachable;
}
Set<String> possible = possibleBiomeKeys(source);
if (possible.isEmpty()) {
return reachable;
}
Registry<Structure> registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
for (Map.Entry<ResourceKey<Structure>, Structure> entry : registry.entrySet()) {
for (Holder<Biome> holder : entry.getValue().biomes()) {
Optional<ResourceKey<Biome>> key = holder.unwrapKey();
if (key.isPresent() && possible.contains(key.get().identifier().toString())) {
reachable.add(entry.getKey().identifier().toString());
break;
}
}
}
return reachable;
}
}