Code/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java

923 lines
42 KiB
Java

package net.minecraft.world.level.levelgen.structure.templatesystem;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.IdMapper;
import net.minecraft.core.Vec3i;
import net.minecraft.data.worldgen.Pools;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.DoubleTag;
import net.minecraft.nbt.IntTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.RandomSource;
import net.minecraft.world.RandomizableContainer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.decoration.Painting;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.JigsawBlock;
import net.minecraft.world.level.block.LiquidBlockContainer;
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.JigsawBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape;
import net.minecraft.world.phys.shapes.DiscreteVoxelShape;
public class StructureTemplate {
public static final String PALETTE_TAG = "palette";
public static final String PALETTE_LIST_TAG = "palettes";
public static final String ENTITIES_TAG = "entities";
public static final String BLOCKS_TAG = "blocks";
public static final String BLOCK_TAG_POS = "pos";
public static final String BLOCK_TAG_STATE = "state";
public static final String BLOCK_TAG_NBT = "nbt";
public static final String ENTITY_TAG_POS = "pos";
public static final String ENTITY_TAG_BLOCKPOS = "blockPos";
public static final String ENTITY_TAG_NBT = "nbt";
public static final String SIZE_TAG = "size";
private final List<StructureTemplate.Palette> palettes = Lists.newArrayList();
private final List<StructureTemplate.StructureEntityInfo> entityInfoList = Lists.newArrayList();
private Vec3i size = Vec3i.ZERO;
private String author = "?";
public Vec3i getSize() {
return this.size;
}
public void setAuthor(String p_74613_) {
this.author = p_74613_;
}
public String getAuthor() {
return this.author;
}
public void fillFromWorld(Level p_163803_, BlockPos p_163804_, Vec3i p_163805_, boolean p_163806_, @Nullable Block p_163807_) {
if (p_163805_.getX() >= 1 && p_163805_.getY() >= 1 && p_163805_.getZ() >= 1) {
BlockPos blockpos = p_163804_.offset(p_163805_).offset(-1, -1, -1);
List<StructureTemplate.StructureBlockInfo> list = Lists.newArrayList();
List<StructureTemplate.StructureBlockInfo> list1 = Lists.newArrayList();
List<StructureTemplate.StructureBlockInfo> list2 = Lists.newArrayList();
BlockPos blockpos1 = new BlockPos(
Math.min(p_163804_.getX(), blockpos.getX()),
Math.min(p_163804_.getY(), blockpos.getY()),
Math.min(p_163804_.getZ(), blockpos.getZ())
);
BlockPos blockpos2 = new BlockPos(
Math.max(p_163804_.getX(), blockpos.getX()),
Math.max(p_163804_.getY(), blockpos.getY()),
Math.max(p_163804_.getZ(), blockpos.getZ())
);
this.size = p_163805_;
for (BlockPos blockpos3 : BlockPos.betweenClosed(blockpos1, blockpos2)) {
BlockPos blockpos4 = blockpos3.subtract(blockpos1);
BlockState blockstate = p_163803_.getBlockState(blockpos3);
if (p_163807_ == null || !blockstate.is(p_163807_)) {
BlockEntity blockentity = p_163803_.getBlockEntity(blockpos3);
StructureTemplate.StructureBlockInfo structuretemplate$structureblockinfo;
if (blockentity != null) {
structuretemplate$structureblockinfo = new StructureTemplate.StructureBlockInfo(
blockpos4, blockstate, blockentity.saveWithId(p_163803_.registryAccess())
);
} else {
structuretemplate$structureblockinfo = new StructureTemplate.StructureBlockInfo(blockpos4, blockstate, null);
}
addToLists(structuretemplate$structureblockinfo, list, list1, list2);
}
}
List<StructureTemplate.StructureBlockInfo> list3 = buildInfoList(list, list1, list2);
this.palettes.clear();
this.palettes.add(new StructureTemplate.Palette(list3));
if (p_163806_) {
this.fillEntityList(p_163803_, blockpos1, blockpos2);
} else {
this.entityInfoList.clear();
}
}
}
private static void addToLists(
StructureTemplate.StructureBlockInfo p_74574_,
List<StructureTemplate.StructureBlockInfo> p_74575_,
List<StructureTemplate.StructureBlockInfo> p_74576_,
List<StructureTemplate.StructureBlockInfo> p_74577_
) {
if (p_74574_.nbt != null) {
p_74576_.add(p_74574_);
} else if (!p_74574_.state.getBlock().hasDynamicShape() && p_74574_.state.isCollisionShapeFullBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO)) {
p_74575_.add(p_74574_);
} else {
p_74577_.add(p_74574_);
}
}
private static List<StructureTemplate.StructureBlockInfo> buildInfoList(
List<StructureTemplate.StructureBlockInfo> p_74615_,
List<StructureTemplate.StructureBlockInfo> p_74616_,
List<StructureTemplate.StructureBlockInfo> p_74617_
) {
Comparator<StructureTemplate.StructureBlockInfo> comparator = Comparator.<StructureTemplate.StructureBlockInfo>comparingInt(
p_74641_ -> p_74641_.pos.getY()
)
.thenComparingInt(p_74637_ -> p_74637_.pos.getX())
.thenComparingInt(p_74572_ -> p_74572_.pos.getZ());
p_74615_.sort(comparator);
p_74617_.sort(comparator);
p_74616_.sort(comparator);
List<StructureTemplate.StructureBlockInfo> list = Lists.newArrayList();
list.addAll(p_74615_);
list.addAll(p_74617_);
list.addAll(p_74616_);
return list;
}
private void fillEntityList(Level p_74501_, BlockPos p_74502_, BlockPos p_74503_) {
List<Entity> list = p_74501_.getEntitiesOfClass(Entity.class, AABB.encapsulatingFullBlocks(p_74502_, p_74503_), p_74499_ -> !(p_74499_ instanceof Player));
this.entityInfoList.clear();
for (Entity entity : list) {
Vec3 vec3 = new Vec3(entity.getX() - p_74502_.getX(), entity.getY() - p_74502_.getY(), entity.getZ() - p_74502_.getZ());
CompoundTag compoundtag = new CompoundTag();
entity.save(compoundtag);
BlockPos blockpos;
if (entity instanceof Painting) {
blockpos = ((Painting)entity).getPos().subtract(p_74502_);
} else {
blockpos = BlockPos.containing(vec3);
}
this.entityInfoList.add(new StructureTemplate.StructureEntityInfo(vec3, blockpos, compoundtag.copy()));
}
}
public List<StructureTemplate.StructureBlockInfo> filterBlocks(BlockPos p_74604_, StructurePlaceSettings p_74605_, Block p_74606_) {
return this.filterBlocks(p_74604_, p_74605_, p_74606_, true);
}
public List<StructureTemplate.JigsawBlockInfo> getJigsaws(BlockPos p_361797_, Rotation p_365954_) {
if (this.palettes.isEmpty()) {
return new ArrayList<>();
} else {
StructurePlaceSettings structureplacesettings = new StructurePlaceSettings().setRotation(p_365954_);
List<StructureTemplate.JigsawBlockInfo> list = structureplacesettings.getRandomPalette(this.palettes, p_361797_).jigsaws();
List<StructureTemplate.JigsawBlockInfo> list1 = new ArrayList<>(list.size());
for (StructureTemplate.JigsawBlockInfo structuretemplate$jigsawblockinfo : list) {
StructureTemplate.StructureBlockInfo structuretemplate$structureblockinfo = structuretemplate$jigsawblockinfo.info;
list1.add(
structuretemplate$jigsawblockinfo.withInfo(
new StructureTemplate.StructureBlockInfo(
calculateRelativePosition(structureplacesettings, structuretemplate$structureblockinfo.pos()).offset(p_361797_),
structuretemplate$structureblockinfo.state.rotate(structureplacesettings.getRotation()),
structuretemplate$structureblockinfo.nbt
)
)
);
}
return list1;
}
}
public ObjectArrayList<StructureTemplate.StructureBlockInfo> filterBlocks(
BlockPos p_230336_, StructurePlaceSettings p_230337_, Block p_230338_, boolean p_230339_
) {
ObjectArrayList<StructureTemplate.StructureBlockInfo> objectarraylist = new ObjectArrayList<>();
BoundingBox boundingbox = p_230337_.getBoundingBox();
if (this.palettes.isEmpty()) {
return objectarraylist;
} else {
for (StructureTemplate.StructureBlockInfo structuretemplate$structureblockinfo : p_230337_.getRandomPalette(this.palettes, p_230336_).blocks(p_230338_)) {
BlockPos blockpos = p_230339_
? calculateRelativePosition(p_230337_, structuretemplate$structureblockinfo.pos).offset(p_230336_)
: structuretemplate$structureblockinfo.pos;
if (boundingbox == null || boundingbox.isInside(blockpos)) {
objectarraylist.add(
new StructureTemplate.StructureBlockInfo(
blockpos,
structuretemplate$structureblockinfo.state.rotate(p_230337_.getRotation()),
structuretemplate$structureblockinfo.nbt
)
);
}
}
return objectarraylist;
}
}
public BlockPos calculateConnectedPosition(StructurePlaceSettings p_74567_, BlockPos p_74568_, StructurePlaceSettings p_74569_, BlockPos p_74570_) {
BlockPos blockpos = calculateRelativePosition(p_74567_, p_74568_);
BlockPos blockpos1 = calculateRelativePosition(p_74569_, p_74570_);
return blockpos.subtract(blockpos1);
}
public static BlockPos calculateRelativePosition(StructurePlaceSettings p_74564_, BlockPos p_74565_) {
return transform(p_74565_, p_74564_.getMirror(), p_74564_.getRotation(), p_74564_.getRotationPivot());
}
public boolean placeInWorld(
ServerLevelAccessor p_230329_, BlockPos p_230330_, BlockPos p_230331_, StructurePlaceSettings p_230332_, RandomSource p_230333_, int p_230334_
) {
if (this.palettes.isEmpty()) {
return false;
} else {
List<StructureTemplate.StructureBlockInfo> list = p_230332_.getRandomPalette(this.palettes, p_230330_).blocks();
if ((!list.isEmpty() || !p_230332_.isIgnoreEntities() && !this.entityInfoList.isEmpty())
&& this.size.getX() >= 1
&& this.size.getY() >= 1
&& this.size.getZ() >= 1) {
BoundingBox boundingbox = p_230332_.getBoundingBox();
List<BlockPos> list1 = Lists.newArrayListWithCapacity(p_230332_.shouldApplyWaterlogging() ? list.size() : 0);
List<BlockPos> list2 = Lists.newArrayListWithCapacity(p_230332_.shouldApplyWaterlogging() ? list.size() : 0);
List<Pair<BlockPos, CompoundTag>> list3 = Lists.newArrayListWithCapacity(list.size());
int i = Integer.MAX_VALUE;
int j = Integer.MAX_VALUE;
int k = Integer.MAX_VALUE;
int l = Integer.MIN_VALUE;
int i1 = Integer.MIN_VALUE;
int j1 = Integer.MIN_VALUE;
for (StructureTemplate.StructureBlockInfo structuretemplate$structureblockinfo : processBlockInfos(p_230329_, p_230330_, p_230331_, p_230332_, list)) {
BlockPos blockpos = structuretemplate$structureblockinfo.pos;
if (boundingbox == null || boundingbox.isInside(blockpos)) {
FluidState fluidstate = p_230332_.shouldApplyWaterlogging() ? p_230329_.getFluidState(blockpos) : null;
BlockState blockstate = structuretemplate$structureblockinfo.state.mirror(p_230332_.getMirror()).rotate(p_230332_.getRotation());
if (structuretemplate$structureblockinfo.nbt != null) {
p_230329_.setBlock(blockpos, Blocks.BARRIER.defaultBlockState(), 820);
}
if (p_230329_.setBlock(blockpos, blockstate, p_230334_)) {
i = Math.min(i, blockpos.getX());
j = Math.min(j, blockpos.getY());
k = Math.min(k, blockpos.getZ());
l = Math.max(l, blockpos.getX());
i1 = Math.max(i1, blockpos.getY());
j1 = Math.max(j1, blockpos.getZ());
list3.add(Pair.of(blockpos, structuretemplate$structureblockinfo.nbt));
if (structuretemplate$structureblockinfo.nbt != null) {
BlockEntity blockentity = p_230329_.getBlockEntity(blockpos);
if (blockentity != null) {
if (blockentity instanceof RandomizableContainer) {
structuretemplate$structureblockinfo.nbt.putLong("LootTableSeed", p_230333_.nextLong());
}
blockentity.loadWithComponents(structuretemplate$structureblockinfo.nbt, p_230329_.registryAccess());
}
}
if (fluidstate != null) {
if (blockstate.getFluidState().isSource()) {
list2.add(blockpos);
} else if (blockstate.getBlock() instanceof LiquidBlockContainer) {
((LiquidBlockContainer)blockstate.getBlock()).placeLiquid(p_230329_, blockpos, blockstate, fluidstate);
if (!fluidstate.isSource()) {
list1.add(blockpos);
}
}
}
}
}
}
boolean flag = true;
Direction[] adirection = new Direction[]{Direction.UP, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST};
while (flag && !list1.isEmpty()) {
flag = false;
Iterator<BlockPos> iterator = list1.iterator();
while (iterator.hasNext()) {
BlockPos blockpos3 = iterator.next();
FluidState fluidstate2 = p_230329_.getFluidState(blockpos3);
for (int i2 = 0; i2 < adirection.length && !fluidstate2.isSource(); i2++) {
BlockPos blockpos1 = blockpos3.relative(adirection[i2]);
FluidState fluidstate1 = p_230329_.getFluidState(blockpos1);
if (fluidstate1.isSource() && !list2.contains(blockpos1)) {
fluidstate2 = fluidstate1;
}
}
if (fluidstate2.isSource()) {
BlockState blockstate1 = p_230329_.getBlockState(blockpos3);
Block block = blockstate1.getBlock();
if (block instanceof LiquidBlockContainer) {
((LiquidBlockContainer)block).placeLiquid(p_230329_, blockpos3, blockstate1, fluidstate2);
flag = true;
iterator.remove();
}
}
}
}
if (i <= l) {
if (!p_230332_.getKnownShape()) {
DiscreteVoxelShape discretevoxelshape = new BitSetDiscreteVoxelShape(l - i + 1, i1 - j + 1, j1 - k + 1);
int k1 = i;
int l1 = j;
int j2 = k;
for (Pair<BlockPos, CompoundTag> pair1 : list3) {
BlockPos blockpos2 = pair1.getFirst();
discretevoxelshape.fill(blockpos2.getX() - k1, blockpos2.getY() - l1, blockpos2.getZ() - j2);
}
updateShapeAtEdge(p_230329_, p_230334_, discretevoxelshape, k1, l1, j2);
}
for (Pair<BlockPos, CompoundTag> pair : list3) {
BlockPos blockpos4 = pair.getFirst();
if (!p_230332_.getKnownShape()) {
BlockState blockstate2 = p_230329_.getBlockState(blockpos4);
BlockState blockstate3 = Block.updateFromNeighbourShapes(blockstate2, p_230329_, blockpos4);
if (blockstate2 != blockstate3) {
p_230329_.setBlock(blockpos4, blockstate3, p_230334_ & -2 | 16);
}
p_230329_.updateNeighborsAt(blockpos4, blockstate3.getBlock());
}
if (pair.getSecond() != null) {
BlockEntity blockentity1 = p_230329_.getBlockEntity(blockpos4);
if (blockentity1 != null) {
blockentity1.setChanged();
}
}
}
}
if (!p_230332_.isIgnoreEntities()) {
this.placeEntities(p_230329_, p_230330_, p_230332_.getMirror(), p_230332_.getRotation(), p_230332_.getRotationPivot(), boundingbox, p_230332_.shouldFinalizeEntities());
}
return true;
} else {
return false;
}
}
}
public static void updateShapeAtEdge(LevelAccessor p_331910_, int p_330850_, DiscreteVoxelShape p_333161_, BlockPos p_335658_) {
updateShapeAtEdge(p_331910_, p_330850_, p_333161_, p_335658_.getX(), p_335658_.getY(), p_335658_.getZ());
}
public static void updateShapeAtEdge(LevelAccessor p_74511_, int p_74512_, DiscreteVoxelShape p_74513_, int p_74514_, int p_74515_, int p_74516_) {
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
BlockPos.MutableBlockPos blockpos$mutableblockpos1 = new BlockPos.MutableBlockPos();
p_74513_.forAllFaces(
(p_360634_, p_360635_, p_360636_, p_360637_) -> {
blockpos$mutableblockpos.set(p_74514_ + p_360635_, p_74515_ + p_360636_, p_74516_ + p_360637_);
blockpos$mutableblockpos1.setWithOffset(blockpos$mutableblockpos, p_360634_);
BlockState blockstate = p_74511_.getBlockState(blockpos$mutableblockpos);
BlockState blockstate1 = p_74511_.getBlockState(blockpos$mutableblockpos1);
BlockState blockstate2 = blockstate.updateShape(
p_74511_, p_74511_, blockpos$mutableblockpos, p_360634_, blockpos$mutableblockpos1, blockstate1, p_74511_.getRandom()
);
if (blockstate != blockstate2) {
p_74511_.setBlock(blockpos$mutableblockpos, blockstate2, p_74512_ & -2);
}
BlockState blockstate3 = blockstate1.updateShape(
p_74511_, p_74511_, blockpos$mutableblockpos1, p_360634_.getOpposite(), blockpos$mutableblockpos, blockstate2, p_74511_.getRandom()
);
if (blockstate1 != blockstate3) {
p_74511_.setBlock(blockpos$mutableblockpos1, blockstate3, p_74512_ & -2);
}
}
);
}
public static List<StructureTemplate.StructureBlockInfo> processBlockInfos(
ServerLevelAccessor p_278297_,
BlockPos p_74519_,
BlockPos p_74520_,
StructurePlaceSettings p_74521_,
List<StructureTemplate.StructureBlockInfo> p_74522_
) {
List<StructureTemplate.StructureBlockInfo> list = new ArrayList<>();
List<StructureTemplate.StructureBlockInfo> list1 = new ArrayList<>();
for (StructureTemplate.StructureBlockInfo structuretemplate$structureblockinfo : p_74522_) {
BlockPos blockpos = calculateRelativePosition(p_74521_, structuretemplate$structureblockinfo.pos).offset(p_74519_);
StructureTemplate.StructureBlockInfo structuretemplate$structureblockinfo1 = new StructureTemplate.StructureBlockInfo(
blockpos,
structuretemplate$structureblockinfo.state,
structuretemplate$structureblockinfo.nbt != null ? structuretemplate$structureblockinfo.nbt.copy() : null
);
Iterator<StructureProcessor> iterator = p_74521_.getProcessors().iterator();
while (structuretemplate$structureblockinfo1 != null && iterator.hasNext()) {
structuretemplate$structureblockinfo1 = iterator.next()
.processBlock(p_278297_, p_74519_, p_74520_, structuretemplate$structureblockinfo, structuretemplate$structureblockinfo1, p_74521_);
}
if (structuretemplate$structureblockinfo1 != null) {
list1.add(structuretemplate$structureblockinfo1);
list.add(structuretemplate$structureblockinfo);
}
}
for (StructureProcessor structureprocessor : p_74521_.getProcessors()) {
list1 = structureprocessor.finalizeProcessing(p_278297_, p_74519_, p_74520_, list, list1, p_74521_);
}
return list1;
}
private void placeEntities(
ServerLevelAccessor p_74524_,
BlockPos p_74525_,
Mirror p_74526_,
Rotation p_74527_,
BlockPos p_74528_,
@Nullable BoundingBox p_74529_,
boolean p_74530_
) {
for (StructureTemplate.StructureEntityInfo structuretemplate$structureentityinfo : this.entityInfoList) {
BlockPos blockpos = transform(structuretemplate$structureentityinfo.blockPos, p_74526_, p_74527_, p_74528_).offset(p_74525_);
if (p_74529_ == null || p_74529_.isInside(blockpos)) {
CompoundTag compoundtag = structuretemplate$structureentityinfo.nbt.copy();
Vec3 vec3 = transform(structuretemplate$structureentityinfo.pos, p_74526_, p_74527_, p_74528_);
Vec3 vec31 = vec3.add(p_74525_.getX(), p_74525_.getY(), p_74525_.getZ());
ListTag listtag = new ListTag();
listtag.add(DoubleTag.valueOf(vec31.x));
listtag.add(DoubleTag.valueOf(vec31.y));
listtag.add(DoubleTag.valueOf(vec31.z));
compoundtag.put("Pos", listtag);
compoundtag.remove("UUID");
createEntityIgnoreException(p_74524_, compoundtag).ifPresent(p_275190_ -> {
float f = p_275190_.rotate(p_74527_);
f += p_275190_.mirror(p_74526_) - p_275190_.getYRot();
p_275190_.snapTo(vec31.x, vec31.y, vec31.z, f, p_275190_.getXRot());
if (p_74530_ && p_275190_ instanceof Mob) {
((Mob)p_275190_).finalizeSpawn(p_74524_, p_74524_.getCurrentDifficultyAt(BlockPos.containing(vec31)), EntitySpawnReason.STRUCTURE, null);
}
p_74524_.addFreshEntityWithPassengers(p_275190_);
});
}
}
}
private static Optional<Entity> createEntityIgnoreException(ServerLevelAccessor p_74544_, CompoundTag p_74545_) {
try {
return EntityType.create(p_74545_, p_74544_.getLevel(), EntitySpawnReason.STRUCTURE);
} catch (Exception exception) {
return Optional.empty();
}
}
public Vec3i getSize(Rotation p_163809_) {
switch (p_163809_) {
case COUNTERCLOCKWISE_90:
case CLOCKWISE_90:
return new Vec3i(this.size.getZ(), this.size.getY(), this.size.getX());
default:
return this.size;
}
}
public static BlockPos transform(BlockPos p_74594_, Mirror p_74595_, Rotation p_74596_, BlockPos p_74597_) {
int i = p_74594_.getX();
int j = p_74594_.getY();
int k = p_74594_.getZ();
boolean flag = true;
switch (p_74595_) {
case LEFT_RIGHT:
k = -k;
break;
case FRONT_BACK:
i = -i;
break;
default:
flag = false;
}
int l = p_74597_.getX();
int i1 = p_74597_.getZ();
switch (p_74596_) {
case COUNTERCLOCKWISE_90:
return new BlockPos(l - i1 + k, j, l + i1 - i);
case CLOCKWISE_90:
return new BlockPos(l + i1 - k, j, i1 - l + i);
case CLOCKWISE_180:
return new BlockPos(l + l - i, j, i1 + i1 - k);
default:
return flag ? new BlockPos(i, j, k) : p_74594_;
}
}
public static Vec3 transform(Vec3 p_74579_, Mirror p_74580_, Rotation p_74581_, BlockPos p_74582_) {
double d0 = p_74579_.x;
double d1 = p_74579_.y;
double d2 = p_74579_.z;
boolean flag = true;
switch (p_74580_) {
case LEFT_RIGHT:
d2 = 1.0 - d2;
break;
case FRONT_BACK:
d0 = 1.0 - d0;
break;
default:
flag = false;
}
int i = p_74582_.getX();
int j = p_74582_.getZ();
switch (p_74581_) {
case COUNTERCLOCKWISE_90:
return new Vec3(i - j + d2, d1, i + j + 1 - d0);
case CLOCKWISE_90:
return new Vec3(i + j + 1 - d2, d1, j - i + d0);
case CLOCKWISE_180:
return new Vec3(i + i + 1 - d0, d1, j + j + 1 - d2);
default:
return flag ? new Vec3(d0, d1, d2) : p_74579_;
}
}
public BlockPos getZeroPositionWithTransform(BlockPos p_74584_, Mirror p_74585_, Rotation p_74586_) {
return getZeroPositionWithTransform(p_74584_, p_74585_, p_74586_, this.getSize().getX(), this.getSize().getZ());
}
public static BlockPos getZeroPositionWithTransform(BlockPos p_74588_, Mirror p_74589_, Rotation p_74590_, int p_74591_, int p_74592_) {
p_74591_--;
p_74592_--;
int i = p_74589_ == Mirror.FRONT_BACK ? p_74591_ : 0;
int j = p_74589_ == Mirror.LEFT_RIGHT ? p_74592_ : 0;
BlockPos blockpos = p_74588_;
switch (p_74590_) {
case COUNTERCLOCKWISE_90:
blockpos = p_74588_.offset(j, 0, p_74591_ - i);
break;
case CLOCKWISE_90:
blockpos = p_74588_.offset(p_74592_ - j, 0, i);
break;
case CLOCKWISE_180:
blockpos = p_74588_.offset(p_74591_ - i, 0, p_74592_ - j);
break;
case NONE:
blockpos = p_74588_.offset(i, 0, j);
}
return blockpos;
}
public BoundingBox getBoundingBox(StructurePlaceSettings p_74634_, BlockPos p_74635_) {
return this.getBoundingBox(p_74635_, p_74634_.getRotation(), p_74634_.getRotationPivot(), p_74634_.getMirror());
}
public BoundingBox getBoundingBox(BlockPos p_74599_, Rotation p_74600_, BlockPos p_74601_, Mirror p_74602_) {
return getBoundingBox(p_74599_, p_74600_, p_74601_, p_74602_, this.size);
}
@VisibleForTesting
protected static BoundingBox getBoundingBox(BlockPos p_163811_, Rotation p_163812_, BlockPos p_163813_, Mirror p_163814_, Vec3i p_163815_) {
Vec3i vec3i = p_163815_.offset(-1, -1, -1);
BlockPos blockpos = transform(BlockPos.ZERO, p_163814_, p_163812_, p_163813_);
BlockPos blockpos1 = transform(BlockPos.ZERO.offset(vec3i), p_163814_, p_163812_, p_163813_);
return BoundingBox.fromCorners(blockpos, blockpos1).move(p_163811_);
}
public CompoundTag save(CompoundTag p_74619_) {
if (this.palettes.isEmpty()) {
p_74619_.put("blocks", new ListTag());
p_74619_.put("palette", new ListTag());
} else {
List<StructureTemplate.SimplePalette> list = Lists.newArrayList();
StructureTemplate.SimplePalette structuretemplate$simplepalette = new StructureTemplate.SimplePalette();
list.add(structuretemplate$simplepalette);
for (int i = 1; i < this.palettes.size(); i++) {
list.add(new StructureTemplate.SimplePalette());
}
ListTag listtag1 = new ListTag();
List<StructureTemplate.StructureBlockInfo> list1 = this.palettes.get(0).blocks();
for (int j = 0; j < list1.size(); j++) {
StructureTemplate.StructureBlockInfo structuretemplate$structureblockinfo = list1.get(j);
CompoundTag compoundtag = new CompoundTag();
compoundtag.put(
"pos",
this.newIntegerList(
structuretemplate$structureblockinfo.pos.getX(),
structuretemplate$structureblockinfo.pos.getY(),
structuretemplate$structureblockinfo.pos.getZ()
)
);
int k = structuretemplate$simplepalette.idFor(structuretemplate$structureblockinfo.state);
compoundtag.putInt("state", k);
if (structuretemplate$structureblockinfo.nbt != null) {
compoundtag.put("nbt", structuretemplate$structureblockinfo.nbt);
}
listtag1.add(compoundtag);
for (int l = 1; l < this.palettes.size(); l++) {
StructureTemplate.SimplePalette structuretemplate$simplepalette1 = list.get(l);
structuretemplate$simplepalette1.addMapping(this.palettes.get(l).blocks().get(j).state, k);
}
}
p_74619_.put("blocks", listtag1);
if (list.size() == 1) {
ListTag listtag2 = new ListTag();
for (BlockState blockstate : structuretemplate$simplepalette) {
listtag2.add(NbtUtils.writeBlockState(blockstate));
}
p_74619_.put("palette", listtag2);
} else {
ListTag listtag3 = new ListTag();
for (StructureTemplate.SimplePalette structuretemplate$simplepalette2 : list) {
ListTag listtag4 = new ListTag();
for (BlockState blockstate1 : structuretemplate$simplepalette2) {
listtag4.add(NbtUtils.writeBlockState(blockstate1));
}
listtag3.add(listtag4);
}
p_74619_.put("palettes", listtag3);
}
}
ListTag listtag = new ListTag();
for (StructureTemplate.StructureEntityInfo structuretemplate$structureentityinfo : this.entityInfoList) {
CompoundTag compoundtag1 = new CompoundTag();
compoundtag1.put(
"pos",
this.newDoubleList(
structuretemplate$structureentityinfo.pos.x,
structuretemplate$structureentityinfo.pos.y,
structuretemplate$structureentityinfo.pos.z
)
);
compoundtag1.put(
"blockPos",
this.newIntegerList(
structuretemplate$structureentityinfo.blockPos.getX(),
structuretemplate$structureentityinfo.blockPos.getY(),
structuretemplate$structureentityinfo.blockPos.getZ()
)
);
if (structuretemplate$structureentityinfo.nbt != null) {
compoundtag1.put("nbt", structuretemplate$structureentityinfo.nbt);
}
listtag.add(compoundtag1);
}
p_74619_.put("entities", listtag);
p_74619_.put("size", this.newIntegerList(this.size.getX(), this.size.getY(), this.size.getZ()));
return NbtUtils.addCurrentDataVersion(p_74619_);
}
public void load(HolderGetter<Block> p_255773_, CompoundTag p_248574_) {
this.palettes.clear();
this.entityInfoList.clear();
ListTag listtag = p_248574_.getListOrEmpty("size");
this.size = new Vec3i(listtag.getIntOr(0, 0), listtag.getIntOr(1, 0), listtag.getIntOr(2, 0));
ListTag listtag1 = p_248574_.getListOrEmpty("blocks");
Optional<ListTag> optional = p_248574_.getList("palettes");
if (optional.isPresent()) {
for (int i = 0; i < optional.get().size(); i++) {
this.loadPalette(p_255773_, optional.get().getListOrEmpty(i), listtag1);
}
} else {
this.loadPalette(p_255773_, p_248574_.getListOrEmpty("palette"), listtag1);
}
p_248574_.getListOrEmpty("entities").compoundStream().forEach(p_391093_ -> {
ListTag listtag2 = p_391093_.getListOrEmpty("pos");
Vec3 vec3 = new Vec3(listtag2.getDoubleOr(0, 0.0), listtag2.getDoubleOr(1, 0.0), listtag2.getDoubleOr(2, 0.0));
ListTag listtag3 = p_391093_.getListOrEmpty("blockPos");
BlockPos blockpos = new BlockPos(listtag3.getIntOr(0, 0), listtag3.getIntOr(1, 0), listtag3.getIntOr(2, 0));
p_391093_.getCompound("nbt").ifPresent(p_391086_ -> this.entityInfoList.add(new StructureTemplate.StructureEntityInfo(vec3, blockpos, p_391086_)));
});
}
private void loadPalette(HolderGetter<Block> p_256546_, ListTag p_251056_, ListTag p_251493_) {
StructureTemplate.SimplePalette structuretemplate$simplepalette = new StructureTemplate.SimplePalette();
for (int i = 0; i < p_251056_.size(); i++) {
structuretemplate$simplepalette.addMapping(NbtUtils.readBlockState(p_256546_, p_251056_.getCompoundOrEmpty(i)), i);
}
List<StructureTemplate.StructureBlockInfo> list3 = Lists.newArrayList();
List<StructureTemplate.StructureBlockInfo> list = Lists.newArrayList();
List<StructureTemplate.StructureBlockInfo> list1 = Lists.newArrayList();
p_251493_.compoundStream()
.forEach(
p_391091_ -> {
ListTag listtag = p_391091_.getListOrEmpty("pos");
BlockPos blockpos = new BlockPos(listtag.getIntOr(0, 0), listtag.getIntOr(1, 0), listtag.getIntOr(2, 0));
BlockState blockstate = structuretemplate$simplepalette.stateFor(p_391091_.getIntOr("state", 0));
CompoundTag compoundtag = p_391091_.getCompound("nbt").orElse(null);
StructureTemplate.StructureBlockInfo structuretemplate$structureblockinfo = new StructureTemplate.StructureBlockInfo(
blockpos, blockstate, compoundtag
);
addToLists(structuretemplate$structureblockinfo, list3, list, list1);
}
);
List<StructureTemplate.StructureBlockInfo> list2 = buildInfoList(list3, list, list1);
this.palettes.add(new StructureTemplate.Palette(list2));
}
private ListTag newIntegerList(int... p_74626_) {
ListTag listtag = new ListTag();
for (int i : p_74626_) {
listtag.add(IntTag.valueOf(i));
}
return listtag;
}
private ListTag newDoubleList(double... p_74624_) {
ListTag listtag = new ListTag();
for (double d0 : p_74624_) {
listtag.add(DoubleTag.valueOf(d0));
}
return listtag;
}
public static JigsawBlockEntity.JointType getJointType(CompoundTag p_368468_, BlockState p_365504_) {
return p_368468_.read("joint", JigsawBlockEntity.JointType.CODEC).orElseGet(() -> getDefaultJointType(p_365504_));
}
public static JigsawBlockEntity.JointType getDefaultJointType(BlockState p_395106_) {
return JigsawBlock.getFrontFacing(p_395106_).getAxis().isHorizontal() ? JigsawBlockEntity.JointType.ALIGNED : JigsawBlockEntity.JointType.ROLLABLE;
}
public record JigsawBlockInfo(
StructureTemplate.StructureBlockInfo info,
JigsawBlockEntity.JointType jointType,
ResourceLocation name,
ResourceKey<StructureTemplatePool> pool,
ResourceLocation target,
int placementPriority,
int selectionPriority
) {
public static StructureTemplate.JigsawBlockInfo of(StructureTemplate.StructureBlockInfo p_365601_) {
CompoundTag compoundtag = Objects.requireNonNull(p_365601_.nbt(), () -> p_365601_ + " nbt was null");
return new StructureTemplate.JigsawBlockInfo(
p_365601_,
StructureTemplate.getJointType(compoundtag, p_365601_.state()),
compoundtag.read("name", ResourceLocation.CODEC).orElse(JigsawBlockEntity.EMPTY_ID),
compoundtag.read("pool", JigsawBlockEntity.POOL_CODEC).orElse(Pools.EMPTY),
compoundtag.read("target", ResourceLocation.CODEC).orElse(JigsawBlockEntity.EMPTY_ID),
compoundtag.getIntOr("placement_priority", 0),
compoundtag.getIntOr("selection_priority", 0)
);
}
@Override
public String toString() {
return String.format(
Locale.ROOT,
"<JigsawBlockInfo | %s | %s | name: %s | pool: %s | target: %s | placement: %d | selection: %d | %s>",
this.info.pos,
this.info.state,
this.name,
this.pool.location(),
this.target,
this.placementPriority,
this.selectionPriority,
this.info.nbt
);
}
public StructureTemplate.JigsawBlockInfo withInfo(StructureTemplate.StructureBlockInfo p_363148_) {
return new StructureTemplate.JigsawBlockInfo(
p_363148_, this.jointType, this.name, this.pool, this.target, this.placementPriority, this.selectionPriority
);
}
}
public static final class Palette {
private final List<StructureTemplate.StructureBlockInfo> blocks;
private final Map<Block, List<StructureTemplate.StructureBlockInfo>> cache = Maps.newHashMap();
@Nullable
private List<StructureTemplate.JigsawBlockInfo> cachedJigsaws;
Palette(List<StructureTemplate.StructureBlockInfo> p_74648_) {
this.blocks = p_74648_;
}
public List<StructureTemplate.JigsawBlockInfo> jigsaws() {
if (this.cachedJigsaws == null) {
this.cachedJigsaws = this.blocks(Blocks.JIGSAW).stream().map(StructureTemplate.JigsawBlockInfo::of).toList();
}
return this.cachedJigsaws;
}
public List<StructureTemplate.StructureBlockInfo> blocks() {
return this.blocks;
}
public List<StructureTemplate.StructureBlockInfo> blocks(Block p_74654_) {
return this.cache
.computeIfAbsent(
p_74654_, p_74659_ -> this.blocks.stream().filter(p_163818_ -> p_163818_.state.is(p_74659_)).collect(Collectors.toList())
);
}
}
static class SimplePalette implements Iterable<BlockState> {
public static final BlockState DEFAULT_BLOCK_STATE = Blocks.AIR.defaultBlockState();
private final IdMapper<BlockState> ids = new IdMapper<>(16);
private int lastId;
public int idFor(BlockState p_74670_) {
int i = this.ids.getId(p_74670_);
if (i == -1) {
i = this.lastId++;
this.ids.addMapping(p_74670_, i);
}
return i;
}
@Nullable
public BlockState stateFor(int p_74668_) {
BlockState blockstate = this.ids.byId(p_74668_);
return blockstate == null ? DEFAULT_BLOCK_STATE : blockstate;
}
@Override
public Iterator<BlockState> iterator() {
return this.ids.iterator();
}
public void addMapping(BlockState p_74672_, int p_74673_) {
this.ids.addMapping(p_74672_, p_74673_);
}
}
public record StructureBlockInfo(BlockPos pos, BlockState state, @Nullable CompoundTag nbt) {
@Override
public String toString() {
return String.format(Locale.ROOT, "<StructureBlockInfo | %s | %s | %s>", this.pos, this.state, this.nbt);
}
}
public static class StructureEntityInfo {
public final Vec3 pos;
public final BlockPos blockPos;
public final CompoundTag nbt;
public StructureEntityInfo(Vec3 p_74687_, BlockPos p_74688_, CompoundTag p_74689_) {
this.pos = p_74687_;
this.blockPos = p_74688_;
this.nbt = p_74689_;
}
}
}