219 lines
10 KiB
Java
219 lines
10 KiB
Java
package net.minecraft.gametest.framework;
|
|
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraft.world.level.levelgen.ChunkGeneratorSettings;
|
|
import net.minecraft.commands.arguments.blocks.BlockInput;
|
|
import net.minecraft.world.level.block.state.properties.Property;
|
|
import java.util.Collections;
|
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
|
import java.io.BufferedReader;
|
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
import java.io.IOException;
|
|
import net.minecraft.nbt.TagParser;
|
|
import java.io.Reader;
|
|
import org.apache.commons.io.IOUtils;
|
|
import java.nio.file.Files;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import java.nio.file.Path;
|
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
|
import java.nio.file.Paths;
|
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import com.google.common.collect.Lists;
|
|
import javax.annotation.Nullable;
|
|
import java.util.Collection;
|
|
import java.util.Comparator;
|
|
import java.util.Optional;
|
|
import java.util.List;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
|
import net.minecraft.world.level.block.state.properties.StructureMode;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Vec3i;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
|
|
|
public class StructureUtils {
|
|
public static String testStructuresDir;
|
|
|
|
public static AABB getStructureBounds(final StructureBlockEntity bxi) {
|
|
final BlockPos fk2 = bxi.getBlockPos().offset(bxi.getStructurePos());
|
|
return new AABB(fk2, fk2.offset(bxi.getStructureSize()));
|
|
}
|
|
|
|
public static void addCommandBlockAndButtonToStartTest(final BlockPos fk, final ServerLevel xd) {
|
|
xd.setBlockAndUpdate(fk, Blocks.COMMAND_BLOCK.defaultBlockState());
|
|
final CommandBlockEntity bwn3 = (CommandBlockEntity)xd.getBlockEntity(fk);
|
|
bwn3.getCommandBlock().setCommand("test runthis");
|
|
xd.setBlockAndUpdate(fk.offset(0, 0, -1), Blocks.STONE_BUTTON.defaultBlockState());
|
|
}
|
|
|
|
public static void createNewEmptyStructureBlock(final String string, final BlockPos fk2, final BlockPos fk3, final int integer, final ServerLevel xd) {
|
|
final BoundingBox cky6 = createStructureBoundingBox(fk2, fk3, integer);
|
|
clearSpaceForStructure(cky6, fk2.getY(), xd);
|
|
xd.setBlockAndUpdate(fk2, Blocks.STRUCTURE_BLOCK.defaultBlockState());
|
|
final StructureBlockEntity bxi7 = (StructureBlockEntity)xd.getBlockEntity(fk2);
|
|
bxi7.setIgnoreEntities(false);
|
|
bxi7.setStructureName(new ResourceLocation(string));
|
|
bxi7.setStructureSize(fk3);
|
|
bxi7.setMode(StructureMode.SAVE);
|
|
bxi7.setShowBoundingBox(true);
|
|
}
|
|
|
|
public static StructureBlockEntity spawnStructure(final String string, final BlockPos fk, final int integer, final ServerLevel xd, final boolean boolean5) {
|
|
final BoundingBox cky6 = createStructureBoundingBox(fk, getStructureTemplate(string, xd).getSize(), integer);
|
|
forceLoadChunks(fk, xd);
|
|
clearSpaceForStructure(cky6, fk.getY(), xd);
|
|
final StructureBlockEntity bxi7 = createStructureBlock(string, fk, xd, boolean5);
|
|
xd.getBlockTicks().fetchTicksInArea(cky6, true, false);
|
|
xd.clearBlockEvents(cky6);
|
|
return bxi7;
|
|
}
|
|
|
|
private static void forceLoadChunks(final BlockPos fk, final ServerLevel xd) {
|
|
final ChunkPos bje3 = new ChunkPos(fk);
|
|
for (int integer4 = -1; integer4 < 4; ++integer4) {
|
|
for (int integer5 = -1; integer5 < 4; ++integer5) {
|
|
final int integer6 = bje3.x + integer4;
|
|
final int integer7 = bje3.z + integer5;
|
|
xd.setChunkForced(integer6, integer7, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void clearSpaceForStructure(final BoundingBox cky, final int integer, final ServerLevel xd) {
|
|
BlockPos.betweenClosedStream(cky).forEach(fk -> clearBlock(integer, fk, xd));
|
|
xd.getBlockTicks().fetchTicksInArea(cky, true, false);
|
|
xd.clearBlockEvents(cky);
|
|
final AABB cvc4 = new AABB(cky.x0, cky.y0, cky.z0, cky.x1, cky.y1, cky.z1);
|
|
final List<Entity> list5 = xd.<Entity>getEntitiesOfClass(Entity.class, cvc4, akn -> !(akn instanceof Player));
|
|
list5.forEach(Entity::remove);
|
|
}
|
|
|
|
public static BoundingBox createStructureBoundingBox(final BlockPos fk1, final BlockPos fk2, final int integer) {
|
|
final BlockPos fk3 = fk1.offset(-integer, -3, -integer);
|
|
final BlockPos fk4 = fk1.offset(fk2).offset(integer - 1, 30, integer - 1);
|
|
return BoundingBox.createProper(fk3.getX(), fk3.getY(), fk3.getZ(), fk4.getX(), fk4.getY(), fk4.getZ());
|
|
}
|
|
|
|
public static Optional<BlockPos> findStructureBlockContainingPos(final BlockPos fk, final int integer, final ServerLevel xd) {
|
|
return findStructureBlocks(fk, integer, xd).stream().filter(fk3 -> doesStructureContain(fk3, fk, xd)).findFirst();
|
|
}
|
|
|
|
@Nullable
|
|
public static BlockPos findNearestStructureBlock(final BlockPos fk, final int integer, final ServerLevel xd) {
|
|
final Comparator<BlockPos> comparator4 = Comparator.<BlockPos>comparingInt(fk2 -> fk2.distManhattan(fk));
|
|
final Collection<BlockPos> collection5 = findStructureBlocks(fk, integer, xd);
|
|
final Optional<BlockPos> optional6 = collection5.stream().min(comparator4);
|
|
return optional6.orElse(null);
|
|
}
|
|
|
|
public static Collection<BlockPos> findStructureBlocks(final BlockPos fk, final int integer, final ServerLevel xd) {
|
|
final Collection<BlockPos> collection4 = Lists.newArrayList();
|
|
AABB cvc5 = new AABB(fk);
|
|
cvc5 = cvc5.inflate(integer);
|
|
for (int integer2 = (int)cvc5.minX; integer2 <= (int)cvc5.maxX; ++integer2) {
|
|
for (int integer3 = (int)cvc5.minY; integer3 <= (int)cvc5.maxY; ++integer3) {
|
|
for (int integer4 = (int)cvc5.minZ; integer4 <= (int)cvc5.maxZ; ++integer4) {
|
|
final BlockPos fk2 = new BlockPos(integer2, integer3, integer4);
|
|
final BlockState byg10 = xd.getBlockState(fk2);
|
|
if (byg10.getBlock() == Blocks.STRUCTURE_BLOCK) {
|
|
collection4.add(fk2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return collection4;
|
|
}
|
|
|
|
private static StructureTemplate getStructureTemplate(final String string, final ServerLevel xd) {
|
|
final StructureManager cml3 = xd.getStructureManager();
|
|
final StructureTemplate cmp4 = cml3.get(new ResourceLocation(string));
|
|
if (cmp4 != null) {
|
|
return cmp4;
|
|
}
|
|
final String string2 = string + ".snbt";
|
|
final Path path6 = Paths.get(StructureUtils.testStructuresDir, string2);
|
|
final CompoundTag jt7 = tryLoadStructure(path6);
|
|
if (jt7 == null) {
|
|
throw new RuntimeException("Could not find structure file " + path6 + ", and the structure is not available in the world structures either.");
|
|
}
|
|
return cml3.readStructure(jt7);
|
|
}
|
|
|
|
private static StructureBlockEntity createStructureBlock(final String string, final BlockPos fk, final ServerLevel xd, final boolean boolean4) {
|
|
xd.setBlockAndUpdate(fk, Blocks.STRUCTURE_BLOCK.defaultBlockState());
|
|
final StructureBlockEntity bxi5 = (StructureBlockEntity)xd.getBlockEntity(fk);
|
|
bxi5.setMode(StructureMode.LOAD);
|
|
bxi5.setIgnoreEntities(false);
|
|
bxi5.setStructureName(new ResourceLocation(string));
|
|
bxi5.loadStructure(boolean4);
|
|
if (bxi5.getStructureSize() != BlockPos.ZERO) {
|
|
return bxi5;
|
|
}
|
|
final StructureTemplate cmp6 = getStructureTemplate(string, xd);
|
|
bxi5.loadStructure(boolean4, cmp6);
|
|
if (bxi5.getStructureSize() == BlockPos.ZERO) {
|
|
throw new RuntimeException("Failed to load structure " + string);
|
|
}
|
|
return bxi5;
|
|
}
|
|
|
|
@Nullable
|
|
private static CompoundTag tryLoadStructure(final Path path) {
|
|
try {
|
|
final BufferedReader bufferedReader2 = Files.newBufferedReader(path);
|
|
final String string3 = IOUtils.toString((Reader)bufferedReader2);
|
|
return TagParser.parseTag(string3);
|
|
}
|
|
catch (IOException iOException2) {
|
|
return null;
|
|
}
|
|
catch (CommandSyntaxException commandSyntaxException2) {
|
|
throw new RuntimeException("Error while trying to load structure " + path, (Throwable)commandSyntaxException2);
|
|
}
|
|
}
|
|
|
|
private static void clearBlock(final int integer, final BlockPos fk, final ServerLevel xd) {
|
|
final ChunkGeneratorSettings cbn5 = (ChunkGeneratorSettings)xd.getChunkSource().getGenerator().getSettings();
|
|
BlockState byg4;
|
|
if (cbn5 instanceof FlatLevelGeneratorSettings) {
|
|
final BlockState[] arr6 = ((FlatLevelGeneratorSettings)cbn5).getLayers();
|
|
if (fk.getY() < integer) {
|
|
byg4 = arr6[fk.getY() - 1];
|
|
}
|
|
else {
|
|
byg4 = Blocks.AIR.defaultBlockState();
|
|
}
|
|
}
|
|
else if (fk.getY() == integer - 1) {
|
|
byg4 = xd.getBiome(fk).getSurfaceBuilderConfig().getTopMaterial();
|
|
}
|
|
else if (fk.getY() < integer - 1) {
|
|
byg4 = xd.getBiome(fk).getSurfaceBuilderConfig().getUnderMaterial();
|
|
}
|
|
else {
|
|
byg4 = Blocks.AIR.defaultBlockState();
|
|
}
|
|
final BlockInput ds6 = new BlockInput(byg4, Collections.<Property<?>>emptySet(), null);
|
|
ds6.place(xd, fk, 2);
|
|
xd.blockUpdated(fk, byg4.getBlock());
|
|
}
|
|
|
|
private static boolean doesStructureContain(final BlockPos fk1, final BlockPos fk2, final ServerLevel xd) {
|
|
final StructureBlockEntity bxi4 = (StructureBlockEntity)xd.getBlockEntity(fk1);
|
|
final AABB cvc5 = getStructureBounds(bxi4);
|
|
return cvc5.contains(new Vec3(fk2));
|
|
}
|
|
|
|
static {
|
|
StructureUtils.testStructuresDir = "gameteststructures";
|
|
}
|
|
}
|