minecraft-src/net/minecraft/world/level/levelgen/structure/structures/OceanRuinPieces.java
2025-07-04 03:45:38 +03:00

378 lines
18 KiB
Java

package net.minecraft.world.level.levelgen.structure.structures;
import com.google.common.collect.Lists;
import java.util.List;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.util.valueproviders.ConstantInt;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.monster.Drowned;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.StructurePieceAccessor;
import net.minecraft.world.level.levelgen.structure.TemplateStructurePiece;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceType;
import net.minecraft.world.level.levelgen.structure.templatesystem.AlwaysTrueTest;
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockIgnoreProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockMatchTest;
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockRotProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.CappedProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.PosAlwaysTrueTest;
import net.minecraft.world.level.levelgen.structure.templatesystem.ProcessorRule;
import net.minecraft.world.level.levelgen.structure.templatesystem.RuleProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
import net.minecraft.world.level.levelgen.structure.templatesystem.rule.blockentity.AppendLoot;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.level.storage.loot.LootTable;
public class OceanRuinPieces {
static final StructureProcessor WARM_SUSPICIOUS_BLOCK_PROCESSOR = archyRuleProcessor(
Blocks.SAND, Blocks.SUSPICIOUS_SAND, BuiltInLootTables.OCEAN_RUIN_WARM_ARCHAEOLOGY
);
static final StructureProcessor COLD_SUSPICIOUS_BLOCK_PROCESSOR = archyRuleProcessor(
Blocks.GRAVEL, Blocks.SUSPICIOUS_GRAVEL, BuiltInLootTables.OCEAN_RUIN_COLD_ARCHAEOLOGY
);
private static final ResourceLocation[] WARM_RUINS = new ResourceLocation[]{
ResourceLocation.withDefaultNamespace("underwater_ruin/warm_1"),
ResourceLocation.withDefaultNamespace("underwater_ruin/warm_2"),
ResourceLocation.withDefaultNamespace("underwater_ruin/warm_3"),
ResourceLocation.withDefaultNamespace("underwater_ruin/warm_4"),
ResourceLocation.withDefaultNamespace("underwater_ruin/warm_5"),
ResourceLocation.withDefaultNamespace("underwater_ruin/warm_6"),
ResourceLocation.withDefaultNamespace("underwater_ruin/warm_7"),
ResourceLocation.withDefaultNamespace("underwater_ruin/warm_8")
};
private static final ResourceLocation[] RUINS_BRICK = new ResourceLocation[]{
ResourceLocation.withDefaultNamespace("underwater_ruin/brick_1"),
ResourceLocation.withDefaultNamespace("underwater_ruin/brick_2"),
ResourceLocation.withDefaultNamespace("underwater_ruin/brick_3"),
ResourceLocation.withDefaultNamespace("underwater_ruin/brick_4"),
ResourceLocation.withDefaultNamespace("underwater_ruin/brick_5"),
ResourceLocation.withDefaultNamespace("underwater_ruin/brick_6"),
ResourceLocation.withDefaultNamespace("underwater_ruin/brick_7"),
ResourceLocation.withDefaultNamespace("underwater_ruin/brick_8")
};
private static final ResourceLocation[] RUINS_CRACKED = new ResourceLocation[]{
ResourceLocation.withDefaultNamespace("underwater_ruin/cracked_1"),
ResourceLocation.withDefaultNamespace("underwater_ruin/cracked_2"),
ResourceLocation.withDefaultNamespace("underwater_ruin/cracked_3"),
ResourceLocation.withDefaultNamespace("underwater_ruin/cracked_4"),
ResourceLocation.withDefaultNamespace("underwater_ruin/cracked_5"),
ResourceLocation.withDefaultNamespace("underwater_ruin/cracked_6"),
ResourceLocation.withDefaultNamespace("underwater_ruin/cracked_7"),
ResourceLocation.withDefaultNamespace("underwater_ruin/cracked_8")
};
private static final ResourceLocation[] RUINS_MOSSY = new ResourceLocation[]{
ResourceLocation.withDefaultNamespace("underwater_ruin/mossy_1"),
ResourceLocation.withDefaultNamespace("underwater_ruin/mossy_2"),
ResourceLocation.withDefaultNamespace("underwater_ruin/mossy_3"),
ResourceLocation.withDefaultNamespace("underwater_ruin/mossy_4"),
ResourceLocation.withDefaultNamespace("underwater_ruin/mossy_5"),
ResourceLocation.withDefaultNamespace("underwater_ruin/mossy_6"),
ResourceLocation.withDefaultNamespace("underwater_ruin/mossy_7"),
ResourceLocation.withDefaultNamespace("underwater_ruin/mossy_8")
};
private static final ResourceLocation[] BIG_RUINS_BRICK = new ResourceLocation[]{
ResourceLocation.withDefaultNamespace("underwater_ruin/big_brick_1"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_brick_2"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_brick_3"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_brick_8")
};
private static final ResourceLocation[] BIG_RUINS_MOSSY = new ResourceLocation[]{
ResourceLocation.withDefaultNamespace("underwater_ruin/big_mossy_1"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_mossy_2"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_mossy_3"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_mossy_8")
};
private static final ResourceLocation[] BIG_RUINS_CRACKED = new ResourceLocation[]{
ResourceLocation.withDefaultNamespace("underwater_ruin/big_cracked_1"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_cracked_2"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_cracked_3"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_cracked_8")
};
private static final ResourceLocation[] BIG_WARM_RUINS = new ResourceLocation[]{
ResourceLocation.withDefaultNamespace("underwater_ruin/big_warm_4"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_warm_5"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_warm_6"),
ResourceLocation.withDefaultNamespace("underwater_ruin/big_warm_7")
};
private static StructureProcessor archyRuleProcessor(Block block, Block suspiciousBlock, ResourceKey<LootTable> lootTable) {
return new CappedProcessor(
new RuleProcessor(
List.of(
new ProcessorRule(
new BlockMatchTest(block), AlwaysTrueTest.INSTANCE, PosAlwaysTrueTest.INSTANCE, suspiciousBlock.defaultBlockState(), new AppendLoot(lootTable)
)
)
),
ConstantInt.of(5)
);
}
private static ResourceLocation getSmallWarmRuin(RandomSource random) {
return Util.getRandom(WARM_RUINS, random);
}
private static ResourceLocation getBigWarmRuin(RandomSource random) {
return Util.getRandom(BIG_WARM_RUINS, random);
}
public static void addPieces(
StructureTemplateManager structureTemplateManager,
BlockPos pos,
Rotation rotation,
StructurePieceAccessor structurePieceAccessor,
RandomSource random,
OceanRuinStructure structure
) {
boolean bl = random.nextFloat() <= structure.largeProbability;
float f = bl ? 0.9F : 0.8F;
addPiece(structureTemplateManager, pos, rotation, structurePieceAccessor, random, structure, bl, f);
if (bl && random.nextFloat() <= structure.clusterProbability) {
addClusterRuins(structureTemplateManager, random, rotation, pos, structure, structurePieceAccessor);
}
}
private static void addClusterRuins(
StructureTemplateManager structureTemplateManager,
RandomSource random,
Rotation rotation,
BlockPos pos,
OceanRuinStructure structure,
StructurePieceAccessor structurePieceAccessor
) {
BlockPos blockPos = new BlockPos(pos.getX(), 90, pos.getZ());
BlockPos blockPos2 = StructureTemplate.transform(new BlockPos(15, 0, 15), Mirror.NONE, rotation, BlockPos.ZERO).offset(blockPos);
BoundingBox boundingBox = BoundingBox.fromCorners(blockPos, blockPos2);
BlockPos blockPos3 = new BlockPos(Math.min(blockPos.getX(), blockPos2.getX()), blockPos.getY(), Math.min(blockPos.getZ(), blockPos2.getZ()));
List<BlockPos> list = allPositions(random, blockPos3);
int i = Mth.nextInt(random, 4, 8);
for (int j = 0; j < i; j++) {
if (!list.isEmpty()) {
int k = random.nextInt(list.size());
BlockPos blockPos4 = (BlockPos)list.remove(k);
Rotation rotation2 = Rotation.getRandom(random);
BlockPos blockPos5 = StructureTemplate.transform(new BlockPos(5, 0, 6), Mirror.NONE, rotation2, BlockPos.ZERO).offset(blockPos4);
BoundingBox boundingBox2 = BoundingBox.fromCorners(blockPos4, blockPos5);
if (!boundingBox2.intersects(boundingBox)) {
addPiece(structureTemplateManager, blockPos4, rotation2, structurePieceAccessor, random, structure, false, 0.8F);
}
}
}
}
private static List<BlockPos> allPositions(RandomSource random, BlockPos pos) {
List<BlockPos> list = Lists.<BlockPos>newArrayList();
list.add(pos.offset(-16 + Mth.nextInt(random, 1, 8), 0, 16 + Mth.nextInt(random, 1, 7)));
list.add(pos.offset(-16 + Mth.nextInt(random, 1, 8), 0, Mth.nextInt(random, 1, 7)));
list.add(pos.offset(-16 + Mth.nextInt(random, 1, 8), 0, -16 + Mth.nextInt(random, 4, 8)));
list.add(pos.offset(Mth.nextInt(random, 1, 7), 0, 16 + Mth.nextInt(random, 1, 7)));
list.add(pos.offset(Mth.nextInt(random, 1, 7), 0, -16 + Mth.nextInt(random, 4, 6)));
list.add(pos.offset(16 + Mth.nextInt(random, 1, 7), 0, 16 + Mth.nextInt(random, 3, 8)));
list.add(pos.offset(16 + Mth.nextInt(random, 1, 7), 0, Mth.nextInt(random, 1, 7)));
list.add(pos.offset(16 + Mth.nextInt(random, 1, 7), 0, -16 + Mth.nextInt(random, 4, 8)));
return list;
}
private static void addPiece(
StructureTemplateManager structureTemplateManager,
BlockPos pos,
Rotation rotation,
StructurePieceAccessor structurePieceAccessor,
RandomSource random,
OceanRuinStructure structure,
boolean isLarge,
float integrity
) {
switch (structure.biomeTemp) {
case WARM:
default:
ResourceLocation resourceLocation = isLarge ? getBigWarmRuin(random) : getSmallWarmRuin(random);
structurePieceAccessor.addPiece(
new OceanRuinPieces.OceanRuinPiece(structureTemplateManager, resourceLocation, pos, rotation, integrity, structure.biomeTemp, isLarge)
);
break;
case COLD:
ResourceLocation[] resourceLocations = isLarge ? BIG_RUINS_BRICK : RUINS_BRICK;
ResourceLocation[] resourceLocations2 = isLarge ? BIG_RUINS_CRACKED : RUINS_CRACKED;
ResourceLocation[] resourceLocations3 = isLarge ? BIG_RUINS_MOSSY : RUINS_MOSSY;
int i = random.nextInt(resourceLocations.length);
structurePieceAccessor.addPiece(
new OceanRuinPieces.OceanRuinPiece(structureTemplateManager, resourceLocations[i], pos, rotation, integrity, structure.biomeTemp, isLarge)
);
structurePieceAccessor.addPiece(
new OceanRuinPieces.OceanRuinPiece(structureTemplateManager, resourceLocations2[i], pos, rotation, 0.7F, structure.biomeTemp, isLarge)
);
structurePieceAccessor.addPiece(
new OceanRuinPieces.OceanRuinPiece(structureTemplateManager, resourceLocations3[i], pos, rotation, 0.5F, structure.biomeTemp, isLarge)
);
}
}
public static class OceanRuinPiece extends TemplateStructurePiece {
private final OceanRuinStructure.Type biomeType;
private final float integrity;
private final boolean isLarge;
public OceanRuinPiece(
StructureTemplateManager structureTemplateManager,
ResourceLocation location,
BlockPos pos,
Rotation rotation,
float integrity,
OceanRuinStructure.Type biomeType,
boolean isLarge
) {
super(StructurePieceType.OCEAN_RUIN, 0, structureTemplateManager, location, location.toString(), makeSettings(rotation, integrity, biomeType), pos);
this.integrity = integrity;
this.biomeType = biomeType;
this.isLarge = isLarge;
}
private OceanRuinPiece(
StructureTemplateManager structureTemplateManager,
CompoundTag genDepth,
Rotation rotation,
float integrity,
OceanRuinStructure.Type biomeType,
boolean isLarge
) {
super(StructurePieceType.OCEAN_RUIN, genDepth, structureTemplateManager, resourceLocation -> makeSettings(rotation, integrity, biomeType));
this.integrity = integrity;
this.biomeType = biomeType;
this.isLarge = isLarge;
}
private static StructurePlaceSettings makeSettings(Rotation rotation, float integrity, OceanRuinStructure.Type structureType) {
StructureProcessor structureProcessor = structureType == OceanRuinStructure.Type.COLD
? OceanRuinPieces.COLD_SUSPICIOUS_BLOCK_PROCESSOR
: OceanRuinPieces.WARM_SUSPICIOUS_BLOCK_PROCESSOR;
return new StructurePlaceSettings()
.setRotation(rotation)
.setMirror(Mirror.NONE)
.addProcessor(new BlockRotProcessor(integrity))
.addProcessor(BlockIgnoreProcessor.STRUCTURE_AND_AIR)
.addProcessor(structureProcessor);
}
public static OceanRuinPieces.OceanRuinPiece create(StructureTemplateManager structureTemplateManager, CompoundTag tag) {
Rotation rotation = (Rotation)tag.read("Rot", Rotation.LEGACY_CODEC).orElseThrow();
float f = tag.getFloatOr("Integrity", 0.0F);
OceanRuinStructure.Type type = (OceanRuinStructure.Type)tag.read("BiomeType", OceanRuinStructure.Type.LEGACY_CODEC).orElseThrow();
boolean bl = tag.getBooleanOr("IsLarge", false);
return new OceanRuinPieces.OceanRuinPiece(structureTemplateManager, tag, rotation, f, type, bl);
}
@Override
protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) {
super.addAdditionalSaveData(context, tag);
tag.store("Rot", Rotation.LEGACY_CODEC, this.placeSettings.getRotation());
tag.putFloat("Integrity", this.integrity);
tag.store("BiomeType", OceanRuinStructure.Type.LEGACY_CODEC, this.biomeType);
tag.putBoolean("IsLarge", this.isLarge);
}
@Override
protected void handleDataMarker(String name, BlockPos pos, ServerLevelAccessor level, RandomSource random, BoundingBox box) {
if ("chest".equals(name)) {
level.setBlock(pos, Blocks.CHEST.defaultBlockState().setValue(ChestBlock.WATERLOGGED, level.getFluidState(pos).is(FluidTags.WATER)), 2);
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof ChestBlockEntity) {
((ChestBlockEntity)blockEntity)
.setLootTable(this.isLarge ? BuiltInLootTables.UNDERWATER_RUIN_BIG : BuiltInLootTables.UNDERWATER_RUIN_SMALL, random.nextLong());
}
} else if ("drowned".equals(name)) {
Drowned drowned = EntityType.DROWNED.create(level.getLevel(), EntitySpawnReason.STRUCTURE);
if (drowned != null) {
drowned.setPersistenceRequired();
drowned.snapTo(pos, 0.0F, 0.0F);
drowned.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.STRUCTURE, null);
level.addFreshEntityWithPassengers(drowned);
if (pos.getY() > level.getSeaLevel()) {
level.setBlock(pos, Blocks.AIR.defaultBlockState(), 2);
} else {
level.setBlock(pos, Blocks.WATER.defaultBlockState(), 2);
}
}
}
}
@Override
public void postProcess(
WorldGenLevel level, StructureManager structureManager, ChunkGenerator generator, RandomSource random, BoundingBox box, ChunkPos chunkPos, BlockPos pos
) {
int i = level.getHeight(Heightmap.Types.OCEAN_FLOOR_WG, this.templatePosition.getX(), this.templatePosition.getZ());
this.templatePosition = new BlockPos(this.templatePosition.getX(), i, this.templatePosition.getZ());
BlockPos blockPos = StructureTemplate.transform(
new BlockPos(this.template.getSize().getX() - 1, 0, this.template.getSize().getZ() - 1), Mirror.NONE, this.placeSettings.getRotation(), BlockPos.ZERO
)
.offset(this.templatePosition);
this.templatePosition = new BlockPos(this.templatePosition.getX(), this.getHeight(this.templatePosition, level, blockPos), this.templatePosition.getZ());
super.postProcess(level, structureManager, generator, random, box, chunkPos, pos);
}
private int getHeight(BlockPos templatePos, BlockGetter level, BlockPos pos) {
int i = templatePos.getY();
int j = 512;
int k = i - 1;
int l = 0;
for (BlockPos blockPos : BlockPos.betweenClosed(templatePos, pos)) {
int m = blockPos.getX();
int n = blockPos.getZ();
int o = templatePos.getY() - 1;
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(m, o, n);
BlockState blockState = level.getBlockState(mutableBlockPos);
for (FluidState fluidState = level.getFluidState(mutableBlockPos);
(blockState.isAir() || fluidState.is(FluidTags.WATER) || blockState.is(BlockTags.ICE)) && o > level.getMinY() + 1;
fluidState = level.getFluidState(mutableBlockPos)
) {
mutableBlockPos.set(m, --o, n);
blockState = level.getBlockState(mutableBlockPos);
}
j = Math.min(j, o);
if (o < k - 2) {
l++;
}
}
int p = Math.abs(templatePos.getX() - pos.getX());
if (k - j > 2 && l > p - 2) {
i = j + 1;
}
return i;
}
}
}