mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-24 07:40:56 +00:00
Amending / removing all structures will redesign later im over this
This commit is contained in:
+7
-428
@@ -2,19 +2,11 @@ package art.arcane.iris.core.nms.v1_21_R7;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.ExternalDataPackPipeline;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.util.common.reflect.WrappedField;
|
||||
import art.arcane.iris.util.common.reflect.WrappedReturningMethod;
|
||||
import net.minecraft.CrashReport;
|
||||
import net.minecraft.CrashReportCategory;
|
||||
import net.minecraft.ReportedException;
|
||||
import net.minecraft.core.*;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.util.random.WeightedList;
|
||||
@@ -29,12 +21,9 @@ import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.levelgen.*;
|
||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
|
||||
@@ -45,18 +34,12 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||
private static final int EXTERNAL_FOUNDATION_MAX_DEPTH = 96;
|
||||
private static final Set<String> loggedExternalStructureFingerprintKeys = ConcurrentHashMap.newKeySet();
|
||||
private final ChunkGenerator delegate;
|
||||
private final Engine engine;
|
||||
private volatile Registry<Structure> cachedStructureRegistry;
|
||||
private volatile Map<Structure, Integer> cachedStructureOrder;
|
||||
|
||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||
@@ -66,10 +49,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
|
||||
@Override
|
||||
public @Nullable Pair<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||
if (holders.size() == 0) return null;
|
||||
if (engine.getDimension().isDisableExplorerMaps())
|
||||
return null;
|
||||
return delegate.findNearestMapStructure(level, holders, pos, radius, findUnexplored);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,12 +76,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
|
||||
@Override
|
||||
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager, ResourceKey<Level> levelKey) {
|
||||
if (!structureManager.shouldGenerateStructures())
|
||||
return;
|
||||
if (!IrisSettings.get().getGeneral().isAutoGenerateIntrinsicStructures()) {
|
||||
return;
|
||||
}
|
||||
delegate.createStructures(registryAccess, structureState, structureManager, access, templateManager, levelKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,18 +131,8 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
|
||||
@Override
|
||||
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||
if (!structureManager.shouldGenerateStructures())
|
||||
return;
|
||||
if (!IrisSettings.get().getGeneral().isAutoGenerateIntrinsicStructures()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSectionY());
|
||||
BlockPos blockPos = sectionPos.origin();
|
||||
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||
Registry<Structure> structureRegistry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
Map<Structure, Integer> structureOrder = getStructureOrder(structureRegistry);
|
||||
|
||||
Heightmap surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||
Heightmap ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||
@@ -180,403 +144,18 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
int wX = x + blockPos.getX();
|
||||
int wZ = z + blockPos.getZ();
|
||||
|
||||
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||
int oceanHeight = ocean.getFirstAvailable(x, z);
|
||||
int surfaceHeight = surface.getFirstAvailable(x, z);
|
||||
int motionHeight = motion.getFirstAvailable(x, z);
|
||||
int motionNoLeavesHeight = motionNoLeaves.getFirstAvailable(x, z);
|
||||
if (noFluid > oceanHeight) {
|
||||
SET_HEIGHT.invoke(ocean, x, z, noFluid);
|
||||
}
|
||||
if (noAir > surfaceHeight) {
|
||||
SET_HEIGHT.invoke(surface, x, z, noAir);
|
||||
}
|
||||
if (noAir > motionHeight) {
|
||||
SET_HEIGHT.invoke(motion, x, z, noAir);
|
||||
}
|
||||
if (noAir > motionNoLeavesHeight) {
|
||||
SET_HEIGHT.invoke(motionNoLeaves, x, z, noAir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<StructureStart> starts = new ArrayList<>(structureManager.startsForStructure(chunkAccess.getPos(), structure -> true));
|
||||
starts.sort(Comparator.comparingInt(start -> structureOrder.getOrDefault(start.getStructure(), Integer.MAX_VALUE)));
|
||||
Set<String> externalSmartBoreStructures = ExternalDataPackPipeline.snapshotSmartBoreStructureKeys();
|
||||
IrisSettings.IrisSettingsGeneral general = IrisSettings.get().getGeneral();
|
||||
boolean intrinsicFoundationsEnabled = general.isIntrinsicStructureFoundations();
|
||||
int intrinsicFoundationDepth = Math.max(0, general.getIntrinsicFoundationMaxDepth());
|
||||
List<String> intrinsicAllowlist = general.getIntrinsicStructureAllowlist();
|
||||
|
||||
int seededStructureIndex = Integer.MIN_VALUE;
|
||||
for (int j = 0; j < starts.size(); j++) {
|
||||
StructureStart start = starts.get(j);
|
||||
Structure structure = start.getStructure();
|
||||
int structureIndex = structureOrder.getOrDefault(structure, j);
|
||||
if (structureIndex != seededStructureIndex) {
|
||||
random.setFeatureSeed(i, structureIndex, structure.step().ordinal());
|
||||
seededStructureIndex = structureIndex;
|
||||
}
|
||||
Supplier<String> supplier = () -> structureRegistry.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||
String structureKey = resolveStructureKey(structureRegistry, structure);
|
||||
boolean isExternalSmartBoreStructure = externalSmartBoreStructures.contains(structureKey);
|
||||
boolean isIntrinsicFoundationStructure = !isExternalSmartBoreStructure
|
||||
&& intrinsicFoundationsEnabled
|
||||
&& intrinsicFoundationDepth > 0
|
||||
&& matchesIntrinsicAllowlist(structureKey, intrinsicAllowlist);
|
||||
int foundationDepth = isExternalSmartBoreStructure
|
||||
? EXTERNAL_FOUNDATION_MAX_DEPTH
|
||||
: (isIntrinsicFoundationStructure ? intrinsicFoundationDepth : 0);
|
||||
BitSet[] beforeSolidColumns = null;
|
||||
if (foundationDepth > 0) {
|
||||
beforeSolidColumns = snapshotChunkSolidColumns(level, chunkAccess);
|
||||
}
|
||||
|
||||
try {
|
||||
level.setCurrentlyGenerating(supplier);
|
||||
start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos());
|
||||
if (beforeSolidColumns != null) {
|
||||
applyStructureFoundations(level, chunkAccess, beforeSolidColumns, foundationDepth);
|
||||
}
|
||||
if (shouldLogExternalStructureFingerprint(structureKey)) {
|
||||
logExternalStructureFingerprint(structureKey, start);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||
category.setDetail("Description", supplier::get);
|
||||
throw new ReportedException(crashReport);
|
||||
int terrainTop = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||
int terrainNoFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||
SET_HEIGHT.invoke(ocean, x, z, terrainNoFluid);
|
||||
SET_HEIGHT.invoke(surface, x, z, terrainTop);
|
||||
SET_HEIGHT.invoke(motion, x, z, terrainTop);
|
||||
SET_HEIGHT.invoke(motionNoLeaves, x, z, terrainTop);
|
||||
}
|
||||
}
|
||||
|
||||
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.FINAL_HEIGHTMAPS);
|
||||
}
|
||||
|
||||
private static String resolveStructureKey(Registry<Structure> structureRegistry, Structure structure) {
|
||||
Identifier directKey = structureRegistry.getKey(structure);
|
||||
if (directKey != null) {
|
||||
return directKey.toString().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
String fallback = String.valueOf(structure);
|
||||
int slash = fallback.lastIndexOf('/');
|
||||
int end = fallback.lastIndexOf(']');
|
||||
if (slash >= 0 && end > slash) {
|
||||
return fallback.substring(slash + 1, end).toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
return fallback.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||
int minX = chunkPos.getMinBlockX();
|
||||
int minZ = chunkPos.getMinBlockZ();
|
||||
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||
int minY = heightAccessor.getMinY() + 1;
|
||||
int maxY = heightAccessor.getMaxY();
|
||||
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||
}
|
||||
|
||||
private static BitSet[] snapshotChunkSolidColumns(WorldGenLevel level, ChunkAccess chunkAccess) {
|
||||
int minY = level.getMinY();
|
||||
int maxY = level.getMaxY();
|
||||
int ySpan = maxY - minY;
|
||||
if (ySpan <= 0) {
|
||||
return new BitSet[0];
|
||||
}
|
||||
|
||||
ChunkPos chunkPos = chunkAccess.getPos();
|
||||
int minX = chunkPos.getMinBlockX();
|
||||
int minZ = chunkPos.getMinBlockZ();
|
||||
BitSet[] columns = new BitSet[16 * 16];
|
||||
BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
||||
for (int localX = 0; localX < 16; localX++) {
|
||||
for (int localZ = 0; localZ < 16; localZ++) {
|
||||
int index = (localX << 4) | localZ;
|
||||
BitSet solids = new BitSet(ySpan);
|
||||
int worldX = minX + localX;
|
||||
int worldZ = minZ + localZ;
|
||||
for (int y = minY; y < maxY; y++) {
|
||||
mutablePos.set(worldX, y, worldZ);
|
||||
if (isFoundationSolid(level.getBlockState(mutablePos))) {
|
||||
solids.set(y - minY);
|
||||
}
|
||||
}
|
||||
columns[index] = solids;
|
||||
}
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
private static boolean matchesIntrinsicAllowlist(String structureKey, List<String> allowlist) {
|
||||
if (structureKey == null || structureKey.isBlank() || allowlist == null || allowlist.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String key = structureKey.toLowerCase(Locale.ROOT);
|
||||
for (String raw : allowlist) {
|
||||
if (raw == null) {
|
||||
continue;
|
||||
}
|
||||
String pattern = raw.trim().toLowerCase(Locale.ROOT);
|
||||
if (pattern.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (pattern.endsWith("*")) {
|
||||
if (key.startsWith(pattern.substring(0, pattern.length() - 1))) {
|
||||
return true;
|
||||
}
|
||||
} else if (key.equals(pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void applyStructureFoundations(
|
||||
WorldGenLevel level,
|
||||
ChunkAccess chunkAccess,
|
||||
BitSet[] beforeSolidColumns,
|
||||
int maxDepth
|
||||
) {
|
||||
if (beforeSolidColumns == null || beforeSolidColumns.length == 0 || maxDepth <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int minY = level.getMinY();
|
||||
int maxY = level.getMaxY();
|
||||
int ySpan = maxY - minY;
|
||||
if (ySpan <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChunkPos chunkPos = chunkAccess.getPos();
|
||||
int minX = chunkPos.getMinBlockX();
|
||||
int minZ = chunkPos.getMinBlockZ();
|
||||
BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
||||
for (int localX = 0; localX < 16; localX++) {
|
||||
for (int localZ = 0; localZ < 16; localZ++) {
|
||||
int index = (localX << 4) | localZ;
|
||||
BitSet before = beforeSolidColumns[index];
|
||||
if (before == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int worldX = minX + localX;
|
||||
int worldZ = minZ + localZ;
|
||||
int lowestNewSolidY = Integer.MIN_VALUE;
|
||||
for (int y = minY; y < maxY; y++) {
|
||||
mutablePos.set(worldX, y, worldZ);
|
||||
BlockState state = level.getBlockState(mutablePos);
|
||||
if (!isFoundationSolid(state)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (before.get(y - minY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lowestNewSolidY = y;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lowestNewSolidY == Integer.MIN_VALUE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mutablePos.set(worldX, lowestNewSolidY, worldZ);
|
||||
BlockState foundationState = level.getBlockState(mutablePos);
|
||||
if (!isFoundationSolid(foundationState)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int depth = 0;
|
||||
for (int y = lowestNewSolidY - 1; y >= minY && depth < maxDepth; y--) {
|
||||
mutablePos.set(worldX, y, worldZ);
|
||||
BlockState state = level.getBlockState(mutablePos);
|
||||
if (isFoundationSolid(state)) {
|
||||
break;
|
||||
}
|
||||
|
||||
level.setBlock(mutablePos, foundationState, 2);
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isFoundationSolid(BlockState state) {
|
||||
if (state == null || state.isAir()) {
|
||||
return false;
|
||||
}
|
||||
if (!state.getFluidState().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return Heightmap.Types.MOTION_BLOCKING_NO_LEAVES.isOpaque().test(state);
|
||||
}
|
||||
|
||||
private static boolean shouldLogExternalStructureFingerprint(String structureKey) {
|
||||
if (!IrisSettings.get().getGeneral().isDebug()) {
|
||||
return false;
|
||||
}
|
||||
if (structureKey == null || structureKey.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String normalized = structureKey.toLowerCase(Locale.ROOT);
|
||||
if (!"minecraft:ancient_city".equals(normalized)
|
||||
&& !"minecraft:mineshaft".equals(normalized)
|
||||
&& !"minecraft:mineshaft_mesa".equals(normalized)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return loggedExternalStructureFingerprintKeys.add(normalized);
|
||||
}
|
||||
|
||||
private static void logExternalStructureFingerprint(String structureKey, StructureStart start) {
|
||||
if (start == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<?> pieces = extractPieces(start);
|
||||
int pieceCount = pieces.size();
|
||||
String firstPieceType = "none";
|
||||
String firstPieceFingerprint = "none";
|
||||
if (!pieces.isEmpty()) {
|
||||
Object firstPiece = pieces.get(0);
|
||||
if (firstPiece != null) {
|
||||
firstPieceType = firstPiece.getClass().getName();
|
||||
firstPieceFingerprint = resolvePieceFingerprint(firstPiece);
|
||||
}
|
||||
}
|
||||
|
||||
Iris.debug("External structure fingerprint: key=" + structureKey
|
||||
+ ", pieces=" + pieceCount
|
||||
+ ", firstPiece=" + firstPieceType
|
||||
+ ", fingerprint=" + firstPieceFingerprint);
|
||||
}
|
||||
|
||||
private static List<?> extractPieces(StructureStart start) {
|
||||
try {
|
||||
Method getPiecesMethod = start.getClass().getMethod("getPieces");
|
||||
Object result = getPiecesMethod.invoke(start);
|
||||
if (result instanceof List<?> list) {
|
||||
return list;
|
||||
}
|
||||
if (result != null) {
|
||||
Method piecesMethod = result.getClass().getMethod("pieces");
|
||||
Object piecesResult = piecesMethod.invoke(result);
|
||||
if (piecesResult instanceof List<?> list) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
Method piecesMethod = start.getClass().getMethod("pieces");
|
||||
Object result = piecesMethod.invoke(start);
|
||||
if (result instanceof List<?> list) {
|
||||
return list;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private static String resolvePieceFingerprint(Object piece) {
|
||||
if (piece == null) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
try {
|
||||
Method templateNameMethod = piece.getClass().getMethod("templateName");
|
||||
Object value = templateNameMethod.invoke(piece);
|
||||
if (value != null) {
|
||||
String normalized = String.valueOf(value);
|
||||
if (!normalized.isBlank()) {
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
Method templateMethod = piece.getClass().getMethod("template");
|
||||
Object value = templateMethod.invoke(piece);
|
||||
if (value != null) {
|
||||
return value.getClass().getName();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
Class<?> current = piece.getClass();
|
||||
while (current != null && current != Object.class) {
|
||||
Field[] fields = current.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(piece);
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value instanceof Identifier identifier) {
|
||||
String normalized = identifier.toString();
|
||||
if (!normalized.isBlank()) {
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
|
||||
if (value instanceof String text) {
|
||||
String fieldName = field.getName() == null ? "" : field.getName().toLowerCase(Locale.ROOT);
|
||||
if (fieldName.contains("template") || fieldName.contains("name") || fieldName.contains("id")) {
|
||||
if (!text.isBlank()) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
current = current.getSuperclass();
|
||||
}
|
||||
|
||||
return piece.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
private Map<Structure, Integer> getStructureOrder(Registry<Structure> structureRegistry) {
|
||||
Map<Structure, Integer> localOrder = cachedStructureOrder;
|
||||
Registry<Structure> localRegistry = cachedStructureRegistry;
|
||||
if (localRegistry == structureRegistry && localOrder != null) {
|
||||
return localOrder;
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
Map<Structure, Integer> synchronizedOrder = cachedStructureOrder;
|
||||
Registry<Structure> synchronizedRegistry = cachedStructureRegistry;
|
||||
if (synchronizedRegistry == structureRegistry && synchronizedOrder != null) {
|
||||
return synchronizedOrder;
|
||||
}
|
||||
|
||||
List<Structure> sortedStructures = structureRegistry.stream()
|
||||
.sorted(Comparator.comparingInt(structure -> structure.step().ordinal()))
|
||||
.toList();
|
||||
Map<Structure, Integer> builtOrder = new IdentityHashMap<>(sortedStructures.size());
|
||||
for (int index = 0; index < sortedStructures.size(); index++) {
|
||||
Structure structure = sortedStructures.get(index);
|
||||
builtOrder.put(structure, index);
|
||||
}
|
||||
|
||||
cachedStructureRegistry = structureRegistry;
|
||||
cachedStructureOrder = builtOrder;
|
||||
return builtOrder;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
|
||||
delegate.spawnOriginalMobs(regionlimitedworldaccess);
|
||||
|
||||
@@ -5,7 +5,6 @@ import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.nms.INMSBinding;
|
||||
import art.arcane.iris.core.nms.container.BiomeColor;
|
||||
import art.arcane.iris.core.nms.container.Pair;
|
||||
import art.arcane.iris.core.nms.container.StructurePlacement;
|
||||
import art.arcane.iris.core.nms.container.BlockProperty;
|
||||
import art.arcane.iris.core.nms.datapack.DataVersion;
|
||||
import art.arcane.iris.engine.data.cache.AtomicCache;
|
||||
@@ -731,65 +730,6 @@ public class NMSBinding implements INMSBinding {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KList<String> getStructureKeys() {
|
||||
KList<String> keys = new KList<>();
|
||||
|
||||
var registry = registry().lookup(Registries.STRUCTURE).orElse(null);
|
||||
if (registry == null) return keys;
|
||||
registry.keySet().stream().map(Identifier::toString).forEach(keys::add);
|
||||
registry.getTags()
|
||||
.map(HolderSet.Named::key)
|
||||
.map(TagKey::location)
|
||||
.map(Identifier::toString)
|
||||
.map(s -> "#" + s)
|
||||
.forEach(keys::add);
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMap<String, KList<String>> getVanillaStructureBiomeTags() {
|
||||
KMap<String, KList<String>> tags = new KMap<>();
|
||||
|
||||
Registry<net.minecraft.world.level.biome.Biome> registry = registry().lookup(Registries.BIOME).orElse(null);
|
||||
if (registry == null) {
|
||||
return tags;
|
||||
}
|
||||
|
||||
registry.getTags().forEach(named -> {
|
||||
TagKey<net.minecraft.world.level.biome.Biome> tagKey = named.key();
|
||||
Identifier location = tagKey.location();
|
||||
if (!"minecraft".equals(location.getNamespace())) {
|
||||
return;
|
||||
}
|
||||
|
||||
String path = location.getPath();
|
||||
if (!path.startsWith("has_structure/")) {
|
||||
return;
|
||||
}
|
||||
|
||||
KList<String> values = new KList<>();
|
||||
named.stream().forEach(holder -> {
|
||||
net.minecraft.world.level.biome.Biome biome = holder.value();
|
||||
Identifier biomeLocation = registry.getKey(biome);
|
||||
if (biomeLocation == null) {
|
||||
return;
|
||||
}
|
||||
if ("minecraft".equals(biomeLocation.getNamespace())) {
|
||||
values.add(biomeLocation.toString());
|
||||
}
|
||||
});
|
||||
|
||||
KList<String> uniqueValues = values.removeDuplicates();
|
||||
if (!uniqueValues.isEmpty()) {
|
||||
tags.put(path, uniqueValues);
|
||||
}
|
||||
});
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean missingDimensionTypes(String... keys) {
|
||||
var type = registry().lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||
@@ -848,76 +788,8 @@ public class NMSBinding implements INMSBinding {
|
||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void placeStructures(Chunk chunk) {
|
||||
var craft = ((CraftChunk) chunk);
|
||||
var level = craft.getCraftWorld().getHandle();
|
||||
var access = craft.getHandle(ChunkStatus.FEATURES);
|
||||
if (access instanceof LevelChunk) {
|
||||
return;
|
||||
}
|
||||
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMap<art.arcane.iris.core.link.Identifier, StructurePlacement> collectStructures() {
|
||||
var structureSets = registry().lookupOrThrow(Registries.STRUCTURE_SET);
|
||||
var structurePlacements = registry().lookupOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||
return structureSets.keySet()
|
||||
.stream()
|
||||
.map(structureSets::get)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.map(holder -> {
|
||||
var set = holder.value();
|
||||
var placement = set.placement();
|
||||
var key = holder.key().identifier();
|
||||
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||
builder = StructurePlacement.RandomSpread.builder()
|
||||
.separation(random.separation())
|
||||
.spacing(random.spacing())
|
||||
.spreadType(switch (random.spreadType()) {
|
||||
case LINEAR -> StructurePlacement.SpreadType.LINEAR;
|
||||
case TRIANGULAR -> StructurePlacement.SpreadType.TRIANGULAR;
|
||||
});
|
||||
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||
builder = StructurePlacement.ConcentricRings.builder()
|
||||
.distance(rings.distance())
|
||||
.spread(rings.spread())
|
||||
.count(rings.count());
|
||||
} else {
|
||||
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Pair<>(new art.arcane.iris.core.link.Identifier(key.getNamespace(), key.getPath()), builder
|
||||
.salt(placement.salt)
|
||||
.frequency(placement.frequency)
|
||||
.structures(set.structures()
|
||||
.stream()
|
||||
.map(entry -> new StructurePlacement.Structure(
|
||||
entry.weight(),
|
||||
entry.structure()
|
||||
.unwrapKey()
|
||||
.map(ResourceKey::identifier)
|
||||
.map(Identifier::toString)
|
||||
.orElse(null),
|
||||
entry.structure().tags()
|
||||
.map(TagKey::location)
|
||||
.map(Identifier::toString)
|
||||
.toList()
|
||||
))
|
||||
.filter(StructurePlacement.Structure::isValid)
|
||||
.toList())
|
||||
.build());
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Pair::getA, Pair::getB, (a, b) -> a, KMap::new));
|
||||
}
|
||||
|
||||
private static final Pattern VANILLA_DATAPACK_ENTRY = Pattern.compile(
|
||||
"^data/minecraft/(?:worldgen/(?:structure|structure_set|template_pool|processor_list)/.+\\.json"
|
||||
"^data/minecraft/(?:worldgen/(?:structure|structure_set|template_pool|processor_list|configured_feature|placed_feature)/.+\\.json"
|
||||
+ "|structures?/.+\\.nbt"
|
||||
+ "|tags/worldgen/biome/has_structure/.+\\.json)$"
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user