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

197 lines
8.7 KiB
Java

package net.minecraft.world.level.levelgen.structure.pools;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.properties.StructureMode;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockIgnoreProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.JigsawReplacementProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorType;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
public class SinglePoolElement extends StructurePoolElement {
private static final Comparator<StructureTemplate.JigsawBlockInfo> HIGHEST_SELECTION_PRIORITY_FIRST = Comparator.comparingInt(
StructureTemplate.JigsawBlockInfo::selectionPriority
)
.reversed();
private static final Codec<Either<ResourceLocation, StructureTemplate>> TEMPLATE_CODEC = Codec.of(
SinglePoolElement::encodeTemplate, ResourceLocation.CODEC.map(Either::left)
);
public static final MapCodec<SinglePoolElement> CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(templateCodec(), processorsCodec(), projectionCodec(), overrideLiquidSettingsCodec()).apply(instance, SinglePoolElement::new)
);
protected final Either<ResourceLocation, StructureTemplate> template;
protected final Holder<StructureProcessorList> processors;
protected final Optional<LiquidSettings> overrideLiquidSettings;
private static <T> DataResult<T> encodeTemplate(Either<ResourceLocation, StructureTemplate> template, DynamicOps<T> ops, T values) {
Optional<ResourceLocation> optional = template.left();
return optional.isEmpty()
? DataResult.error(() -> "Can not serialize a runtime pool element")
: ResourceLocation.CODEC.encode((ResourceLocation)optional.get(), ops, values);
}
protected static <E extends SinglePoolElement> RecordCodecBuilder<E, Holder<StructureProcessorList>> processorsCodec() {
return StructureProcessorType.LIST_CODEC.fieldOf("processors").forGetter(singlePoolElement -> singlePoolElement.processors);
}
protected static <E extends SinglePoolElement> RecordCodecBuilder<E, Optional<LiquidSettings>> overrideLiquidSettingsCodec() {
return LiquidSettings.CODEC.optionalFieldOf("override_liquid_settings").forGetter(singlePoolElement -> singlePoolElement.overrideLiquidSettings);
}
protected static <E extends SinglePoolElement> RecordCodecBuilder<E, Either<ResourceLocation, StructureTemplate>> templateCodec() {
return TEMPLATE_CODEC.fieldOf("location").forGetter(singlePoolElement -> singlePoolElement.template);
}
protected SinglePoolElement(
Either<ResourceLocation, StructureTemplate> template,
Holder<StructureProcessorList> processors,
StructureTemplatePool.Projection projection,
Optional<LiquidSettings> overrideLiquidSettings
) {
super(projection);
this.template = template;
this.processors = processors;
this.overrideLiquidSettings = overrideLiquidSettings;
}
@Override
public Vec3i getSize(StructureTemplateManager structureTemplateManager, Rotation rotation) {
StructureTemplate structureTemplate = this.getTemplate(structureTemplateManager);
return structureTemplate.getSize(rotation);
}
private StructureTemplate getTemplate(StructureTemplateManager structureTemplateManager) {
return this.template.map(structureTemplateManager::getOrCreate, Function.identity());
}
public List<StructureTemplate.StructureBlockInfo> getDataMarkers(
StructureTemplateManager structureTemplateManager, BlockPos pos, Rotation rotation, boolean relativePosition
) {
StructureTemplate structureTemplate = this.getTemplate(structureTemplateManager);
List<StructureTemplate.StructureBlockInfo> list = structureTemplate.filterBlocks(
pos, new StructurePlaceSettings().setRotation(rotation), Blocks.STRUCTURE_BLOCK, relativePosition
);
List<StructureTemplate.StructureBlockInfo> list2 = Lists.<StructureTemplate.StructureBlockInfo>newArrayList();
for (StructureTemplate.StructureBlockInfo structureBlockInfo : list) {
CompoundTag compoundTag = structureBlockInfo.nbt();
if (compoundTag != null) {
StructureMode structureMode = (StructureMode)compoundTag.read("mode", StructureMode.LEGACY_CODEC).orElseThrow();
if (structureMode == StructureMode.DATA) {
list2.add(structureBlockInfo);
}
}
}
return list2;
}
@Override
public List<StructureTemplate.JigsawBlockInfo> getShuffledJigsawBlocks(
StructureTemplateManager structureTemplateManager, BlockPos pos, Rotation rotation, RandomSource random
) {
List<StructureTemplate.JigsawBlockInfo> list = this.getTemplate(structureTemplateManager).getJigsaws(pos, rotation);
Util.shuffle(list, random);
sortBySelectionPriority(list);
return list;
}
@VisibleForTesting
static void sortBySelectionPriority(List<StructureTemplate.JigsawBlockInfo> structureBlockInfos) {
structureBlockInfos.sort(HIGHEST_SELECTION_PRIORITY_FIRST);
}
@Override
public BoundingBox getBoundingBox(StructureTemplateManager structureTemplateManager, BlockPos pos, Rotation rotation) {
StructureTemplate structureTemplate = this.getTemplate(structureTemplateManager);
return structureTemplate.getBoundingBox(new StructurePlaceSettings().setRotation(rotation), pos);
}
@Override
public boolean place(
StructureTemplateManager structureTemplateManager,
WorldGenLevel level,
StructureManager structureManager,
ChunkGenerator generator,
BlockPos offset,
BlockPos pos,
Rotation rotation,
BoundingBox box,
RandomSource random,
LiquidSettings liquidSettings,
boolean keepJigsaws
) {
StructureTemplate structureTemplate = this.getTemplate(structureTemplateManager);
StructurePlaceSettings structurePlaceSettings = this.getSettings(rotation, box, liquidSettings, keepJigsaws);
if (!structureTemplate.placeInWorld(level, offset, pos, structurePlaceSettings, random, 18)) {
return false;
} else {
for (StructureTemplate.StructureBlockInfo structureBlockInfo : StructureTemplate.processBlockInfos(
level, offset, pos, structurePlaceSettings, this.getDataMarkers(structureTemplateManager, offset, rotation, false)
)) {
this.handleDataMarker(level, structureBlockInfo, offset, rotation, random, box);
}
return true;
}
}
protected StructurePlaceSettings getSettings(Rotation rotation, BoundingBox boundingBox, LiquidSettings liquidSettings, boolean offset) {
StructurePlaceSettings structurePlaceSettings = new StructurePlaceSettings();
structurePlaceSettings.setBoundingBox(boundingBox);
structurePlaceSettings.setRotation(rotation);
structurePlaceSettings.setKnownShape(true);
structurePlaceSettings.setIgnoreEntities(false);
structurePlaceSettings.addProcessor(BlockIgnoreProcessor.STRUCTURE_BLOCK);
structurePlaceSettings.setFinalizeEntities(true);
structurePlaceSettings.setLiquidSettings((LiquidSettings)this.overrideLiquidSettings.orElse(liquidSettings));
if (!offset) {
structurePlaceSettings.addProcessor(JigsawReplacementProcessor.INSTANCE);
}
this.processors.value().list().forEach(structurePlaceSettings::addProcessor);
this.getProjection().getProcessors().forEach(structurePlaceSettings::addProcessor);
return structurePlaceSettings;
}
@Override
public StructurePoolElementType<?> getType() {
return StructurePoolElementType.SINGLE;
}
public String toString() {
return "Single[" + this.template + "]";
}
@VisibleForTesting
public ResourceLocation getTemplateLocation() {
return this.template.orThrow();
}
}