Improved batch placement command and added eas jigsaw command
This commit is contained in:
parent
dd13f09bd2
commit
36f28c1561
3 changed files with 339 additions and 109 deletions
|
@ -27,6 +27,7 @@ import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -111,13 +112,13 @@ public class StructureNBT {
|
||||||
return READER_CACHE.computeIfAbsent(resource, r -> _readStructureFromJar(r));
|
return READER_CACHE.computeIfAbsent(resource, r -> _readStructureFromJar(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StructureTemplate _readStructureFromJar(ResourceLocation resource) {
|
private static String getStructurePath(ResourceLocation resource) {
|
||||||
String ns = resource.getNamespace();
|
return "data/" + resource.getNamespace() + "/structures/" + resource.getPath();
|
||||||
String nm = resource.getPath();
|
}
|
||||||
|
|
||||||
allResourcesFrom(resource);
|
private static StructureTemplate _readStructureFromJar(ResourceLocation resource) {
|
||||||
try {
|
try {
|
||||||
InputStream inputstream = MinecraftServer.class.getResourceAsStream("/data/" + ns + "/structures/" + nm + ".nbt");
|
InputStream inputstream = MinecraftServer.class.getResourceAsStream("/" + getStructurePath(resource) + ".nbt");
|
||||||
return readStructureFromStream(inputstream);
|
return readStructureFromStream(inputstream);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -126,11 +127,19 @@ public class StructureNBT {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<StructureNBT> allResourcesFrom(ResourceLocation resource) {
|
/**
|
||||||
|
* Returns a list of all structures found at the given resource location.
|
||||||
|
*
|
||||||
|
* @param resource The resource location to search.
|
||||||
|
* @param recursionDepth The maximum recursion depth or 0 to indicate no limitation
|
||||||
|
* @return A list of all structures found at the given resource location.
|
||||||
|
*/
|
||||||
|
public static List<StructureNBT> createResourcesFrom(ResourceLocation resource, int recursionDepth) {
|
||||||
String ns = resource.getNamespace();
|
String ns = resource.getNamespace();
|
||||||
String nm = resource.getPath();
|
String nm = resource.getPath();
|
||||||
|
|
||||||
final URL url = MinecraftServer.class.getClassLoader().getResource("data/" + ns + "/structures/" + nm);
|
final String resourceFolder = getStructurePath(resource);
|
||||||
|
final URL url = MinecraftServer.class.getClassLoader().getResource(resourceFolder);
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
final URI uri;
|
final URI uri;
|
||||||
try {
|
try {
|
||||||
|
@ -143,26 +152,38 @@ public class StructureNBT {
|
||||||
if (uri.getScheme().equals("jar")) {
|
if (uri.getScheme().equals("jar")) {
|
||||||
FileSystem fileSystem = null;
|
FileSystem fileSystem = null;
|
||||||
try {
|
try {
|
||||||
fileSystem = FileSystems.newFileSystem(uri, new HashMap<>());
|
fileSystem = FileSystems.getFileSystem(uri);
|
||||||
} catch (IOException e) {
|
} catch (FileSystemNotFoundException notLoaded) {
|
||||||
BCLib.LOGGER.error("Unable to load Resources: ", e);
|
try {
|
||||||
return null;
|
fileSystem = FileSystems.newFileSystem(uri, new HashMap<>());
|
||||||
|
} catch (IOException e) {
|
||||||
|
BCLib.LOGGER.error("Unable to load Filesystem: ", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
myPath = fileSystem.getPath("/resources");
|
|
||||||
|
myPath = fileSystem.getPath(resourceFolder);
|
||||||
} else {
|
} else {
|
||||||
myPath = Paths.get(uri);
|
myPath = Paths.get(uri);
|
||||||
}
|
}
|
||||||
if (myPath.toFile().isDirectory()) {
|
if (Files.isDirectory(myPath)) {
|
||||||
try {
|
try {
|
||||||
return Files.walk(myPath, 1)
|
// /bclib place nbt minecraft:village/plains 0 southOf 0 -60 -0 controller
|
||||||
.filter(p -> p.toFile().isFile())
|
return Files.walk(myPath, recursionDepth <= 0 ? Integer.MAX_VALUE : recursionDepth)
|
||||||
.map(p -> p.getFileName().toFile())
|
.filter(p -> Files.isRegularFile(p))
|
||||||
.filter(f -> f.toString().endsWith(".nbt"))
|
.map(p -> {
|
||||||
.map(f -> f.toString())
|
if (p.isAbsolute())
|
||||||
|
return Path.of(uri).relativize(p).toString();
|
||||||
|
else {
|
||||||
|
return p.toString().replace(resourceFolder, "").replaceAll("^/+", "");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(s -> s.endsWith(".nbt"))
|
||||||
.map(s -> new ResourceLocation(
|
.map(s -> new ResourceLocation(
|
||||||
ns,
|
ns,
|
||||||
(nm.isEmpty() ? "" : (nm + "/")) + s.substring(0, s.length() - 4)
|
(nm.isEmpty() ? "" : (nm + "/")) + s.substring(0, s.length() - 4)
|
||||||
))
|
))
|
||||||
|
.sorted(Comparator.comparing(ResourceLocation::toString))
|
||||||
.map(r -> {
|
.map(r -> {
|
||||||
BCLib.LOGGER.info("Loading Structure: " + r);
|
BCLib.LOGGER.info("Loading Structure: " + r);
|
||||||
try {
|
try {
|
||||||
|
@ -171,7 +192,8 @@ public class StructureNBT {
|
||||||
BCLib.LOGGER.error("Unable to load Structure " + r, e);
|
BCLib.LOGGER.error("Unable to load Structure " + r, e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}).toList();
|
})
|
||||||
|
.toList();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
BCLib.LOGGER.error("Unable to load Resources: ", e);
|
BCLib.LOGGER.error("Unable to load Resources: ", e);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -3,12 +3,14 @@ package org.betterx.bclib.commands;
|
||||||
import de.ambertation.wunderlib.math.Bounds;
|
import de.ambertation.wunderlib.math.Bounds;
|
||||||
import de.ambertation.wunderlib.math.Float3;
|
import de.ambertation.wunderlib.math.Float3;
|
||||||
import org.betterx.bclib.api.v2.levelgen.structures.StructureNBT;
|
import org.betterx.bclib.api.v2.levelgen.structures.StructureNBT;
|
||||||
|
import org.betterx.bclib.commands.arguments.ConnectorArgument;
|
||||||
import org.betterx.bclib.commands.arguments.Float3ArgumentType;
|
import org.betterx.bclib.commands.arguments.Float3ArgumentType;
|
||||||
import org.betterx.bclib.commands.arguments.PlacementDirections;
|
import org.betterx.bclib.commands.arguments.PlacementDirections;
|
||||||
import org.betterx.bclib.commands.arguments.TemplatePlacementArgument;
|
import org.betterx.bclib.commands.arguments.TemplatePlacementArgument;
|
||||||
import org.betterx.bclib.util.BlocksHelper;
|
import org.betterx.bclib.util.BlocksHelper;
|
||||||
|
|
||||||
import com.mojang.brigadier.Command;
|
import com.mojang.brigadier.Command;
|
||||||
|
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
@ -17,28 +19,34 @@ import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.commands.CommandBuildContext;
|
import net.minecraft.commands.CommandBuildContext;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.Commands;
|
import net.minecraft.commands.Commands;
|
||||||
|
import net.minecraft.commands.arguments.ResourceKeyArgument;
|
||||||
import net.minecraft.commands.arguments.ResourceLocationArgument;
|
import net.minecraft.commands.arguments.ResourceLocationArgument;
|
||||||
import net.minecraft.commands.arguments.blocks.BlockInput;
|
import net.minecraft.commands.arguments.blocks.BlockInput;
|
||||||
import net.minecraft.commands.arguments.blocks.BlockStateArgument;
|
import net.minecraft.commands.arguments.blocks.BlockStateArgument;
|
||||||
|
import net.minecraft.commands.arguments.blocks.BlockStateParser;
|
||||||
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
|
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
|
||||||
import net.minecraft.commands.arguments.coordinates.Coordinates;
|
import net.minecraft.commands.arguments.coordinates.Coordinates;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.core.Vec3i;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.TagParser;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.chat.Style;
|
import net.minecraft.network.chat.Style;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.*;
|
import net.minecraft.world.level.block.*;
|
||||||
import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
import net.minecraft.world.level.block.entity.*;
|
||||||
import net.minecraft.world.level.block.entity.StructureBlockEntity;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.properties.AttachFace;
|
import net.minecraft.world.level.block.state.properties.AttachFace;
|
||||||
import net.minecraft.world.level.block.state.properties.StructureMode;
|
import net.minecraft.world.level.block.state.properties.StructureMode;
|
||||||
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -49,8 +57,16 @@ class PlaceCommandBuilder {
|
||||||
public static final String EMPTY = "empty";
|
public static final String EMPTY = "empty";
|
||||||
public static final String PLACEMENT = "placement";
|
public static final String PLACEMENT = "placement";
|
||||||
public static final String POS = "pos";
|
public static final String POS = "pos";
|
||||||
|
public static final String RECURSION_DEPTH = "recursion_depth";
|
||||||
public static final String SPAN = "span";
|
public static final String SPAN = "span";
|
||||||
public static final String BORDER = "border";
|
public static final String BORDER = "border";
|
||||||
|
public static final String ADD_CONTROLL_BLOCKS = "controller";
|
||||||
|
public static final String FILL_VOID = "replaceair";
|
||||||
|
public static final String JIGSAW = "jigsaw";
|
||||||
|
public static final String CONNECTOR_NAME = "connector_name";
|
||||||
|
public static final String REPLACE_WITH = "replace_with";
|
||||||
|
public static final String ROLLABLE = "rollable";
|
||||||
|
public static final String REPLACE_FROM_WORLD = "fromWorld";
|
||||||
|
|
||||||
public void register(
|
public void register(
|
||||||
CommandBuildContext ctx,
|
CommandBuildContext ctx,
|
||||||
|
@ -68,17 +84,25 @@ class PlaceCommandBuilder {
|
||||||
POS,
|
POS,
|
||||||
BlockPosArgument.blockPos()
|
BlockPosArgument.blockPos()
|
||||||
);
|
);
|
||||||
|
final Supplier<RequiredArgumentBuilder<CommandSourceStack, Integer>> recursionDepth = () -> Commands.argument(
|
||||||
|
RECURSION_DEPTH,
|
||||||
|
IntegerArgumentType.integer(0, 16)
|
||||||
|
);
|
||||||
|
final Function<Boolean, RequiredArgumentBuilder<CommandSourceStack, PlacementDirections>> placeIt = (hasRecursionArg) -> placement
|
||||||
|
.get()
|
||||||
|
.then(
|
||||||
|
addOptionalsAndExecute(
|
||||||
|
ctx,
|
||||||
|
pos.get(),
|
||||||
|
hasRecursionArg,
|
||||||
|
PlaceCommandBuilder::placeNBT
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
final var nbtTree = Commands.literal(NBT).then(
|
final var nbtTree = Commands.literal(NBT).then(
|
||||||
path.get().then(
|
path.get()
|
||||||
placement.get().then(
|
.then(recursionDepth.get().then(placeIt.apply(true)))
|
||||||
addOptionalsAndExecute(
|
.then(placeIt.apply(false))
|
||||||
ctx,
|
|
||||||
pos.get(),
|
|
||||||
PlaceCommandBuilder::placeNBT
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final var emptyTree = Commands.literal(EMPTY).then(
|
final var emptyTree = Commands.literal(EMPTY).then(
|
||||||
|
@ -88,92 +112,169 @@ class PlaceCommandBuilder {
|
||||||
addOptionalsAndExecute(
|
addOptionalsAndExecute(
|
||||||
ctx,
|
ctx,
|
||||||
Commands.argument(SPAN, Float3ArgumentType.int3(0, 64)),
|
Commands.argument(SPAN, Float3ArgumentType.int3(0, 64)),
|
||||||
|
false,
|
||||||
PlaceCommandBuilder::placeEmpty
|
PlaceCommandBuilder::placeEmpty
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
final Supplier<RequiredArgumentBuilder<CommandSourceStack, BlockInput>> replace = () -> Commands.argument(
|
||||||
|
REPLACE_WITH,
|
||||||
|
BlockStateArgument.block(ctx)
|
||||||
|
);
|
||||||
|
final Supplier<LiteralArgumentBuilder<CommandSourceStack>> replace_source = () -> Commands.literal(
|
||||||
|
REPLACE_FROM_WORLD);
|
||||||
|
final Supplier<LiteralArgumentBuilder<CommandSourceStack>> rotate = () -> Commands.literal(ROLLABLE);
|
||||||
|
|
||||||
|
final var jigsawTree = Commands.literal(JIGSAW).then(
|
||||||
|
Commands.argument(PlaceCommand.POOL, ResourceKeyArgument.key(Registries.TEMPLATE_POOL)).then(
|
||||||
|
Commands.argument(CONNECTOR_NAME, ConnectorArgument.id())
|
||||||
|
.then(replace.get()
|
||||||
|
.then(rotate.get()
|
||||||
|
.then(pos.get()
|
||||||
|
.executes(cc -> placeJigsaw(cc, true, true, false))))
|
||||||
|
.then(pos.get().executes(cc -> placeJigsaw(cc, true, false, false)))
|
||||||
|
)
|
||||||
|
.then(replace_source.get()
|
||||||
|
.then(rotate.get()
|
||||||
|
.then(pos.get()
|
||||||
|
.executes(cc -> placeJigsaw(
|
||||||
|
cc,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
))))
|
||||||
|
.then(pos.get().executes(cc -> placeJigsaw(cc, false, false, true)))
|
||||||
|
)
|
||||||
|
.then(rotate.get()
|
||||||
|
.then(pos.get().executes(cc -> placeJigsaw(cc, true, true, false))))
|
||||||
|
.then(
|
||||||
|
pos.get().executes(cc -> placeJigsaw(cc, false, false, false))
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
final var testSpaner = Commands.literal("spawner")
|
||||||
|
.then(pos.get().executes(cc -> placeSpawner(cc)));
|
||||||
|
|
||||||
command
|
command
|
||||||
.then(nbtTree)
|
.then(nbtTree)
|
||||||
.then(emptyTree);
|
.then(emptyTree)
|
||||||
|
.then(jigsawTree)
|
||||||
|
.then(testSpaner);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> RequiredArgumentBuilder<CommandSourceStack, T> addOptionalsAndExecute(
|
private <T> RequiredArgumentBuilder<CommandSourceStack, T> addOptionalsAndExecute(
|
||||||
CommandBuildContext commandBuildContext,
|
CommandBuildContext commandBuildContext,
|
||||||
RequiredArgumentBuilder<CommandSourceStack, T> root,
|
RequiredArgumentBuilder<CommandSourceStack, T> root,
|
||||||
|
boolean hasRecursionArgs,
|
||||||
Executor runner
|
Executor runner
|
||||||
) {
|
) {
|
||||||
final Supplier<LiteralArgumentBuilder<CommandSourceStack>> addControllers = () -> Commands.literal("controller");
|
final Supplier<LiteralArgumentBuilder<CommandSourceStack>> addControllers = () -> Commands.literal(
|
||||||
|
ADD_CONTROLL_BLOCKS);
|
||||||
|
final Supplier<LiteralArgumentBuilder<CommandSourceStack>> replaceAir = () -> Commands.literal(FILL_VOID);
|
||||||
final Supplier<RequiredArgumentBuilder<CommandSourceStack, BlockInput>> addBorder = () -> Commands.argument(
|
final Supplier<RequiredArgumentBuilder<CommandSourceStack, BlockInput>> addBorder = () -> Commands.argument(
|
||||||
BORDER,
|
BORDER,
|
||||||
BlockStateArgument.block(commandBuildContext)
|
BlockStateArgument.block(commandBuildContext)
|
||||||
);
|
);
|
||||||
|
|
||||||
return root
|
return root
|
||||||
.executes(c -> runner.exec(c, false, false))
|
.executes(c -> runner.exec(c, false, false, false, hasRecursionArgs))
|
||||||
.then(addBorder.get()
|
.then(addBorder.get()
|
||||||
.executes(c -> runner.exec(c, true, false))
|
.executes(c -> runner.exec(c, true, false, false, hasRecursionArgs))
|
||||||
.then(addControllers.get()
|
.then(addControllers.get()
|
||||||
.executes(c -> runner.exec(c, true, true)))
|
.executes(c -> runner.exec(c, true, true, false, hasRecursionArgs)))
|
||||||
|
.then(addControllers.get()
|
||||||
|
.then(replaceAir.get()
|
||||||
|
.executes(c -> runner.exec(
|
||||||
|
c,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
hasRecursionArgs
|
||||||
|
)))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.then(addControllers.get().executes(c -> runner.exec(c, false, true)));
|
.then(addControllers.get().executes(c -> runner.exec(c, false, true, false, hasRecursionArgs)))
|
||||||
|
.then(addControllers.get()
|
||||||
|
.then(replaceAir.get()
|
||||||
|
.executes(c -> runner.exec(
|
||||||
|
c,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
hasRecursionArgs
|
||||||
|
))));
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Executor {
|
interface Executor {
|
||||||
int exec(
|
int exec(
|
||||||
CommandContext<CommandSourceStack> ctx,
|
CommandContext<CommandSourceStack> ctx,
|
||||||
boolean border,
|
boolean hasBorderArg,
|
||||||
boolean controlBlocks
|
boolean controlBlocks,
|
||||||
|
boolean replaceAir,
|
||||||
|
boolean hasRecursionArg
|
||||||
) throws CommandSyntaxException;
|
) throws CommandSyntaxException;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /bclib place nbt betternether:city southOf 0 -59 0 controller
|
// /bclib place nbt betternether:city southOf 0 -59 0 controller
|
||||||
|
// /bclib place nbt minecraft:village/plains 0 southOf 0 -59 0 controller
|
||||||
protected static int placeNBT(
|
protected static int placeNBT(
|
||||||
CommandContext<CommandSourceStack> ctx,
|
CommandContext<CommandSourceStack> ctx,
|
||||||
boolean border,
|
boolean hasBorderArg,
|
||||||
boolean controlBlocks
|
boolean controlBlocks,
|
||||||
|
boolean replaceAir,
|
||||||
|
boolean hasRecursionArg
|
||||||
) throws CommandSyntaxException {
|
) throws CommandSyntaxException {
|
||||||
final ResourceLocation id = ResourceLocationArgument.getId(ctx, PATH);
|
final ResourceLocation id = ResourceLocationArgument.getId(ctx, PATH);
|
||||||
final PlacementDirections searchDir = TemplatePlacementArgument.getPlacement(ctx, PLACEMENT);
|
final PlacementDirections searchDir = TemplatePlacementArgument.getPlacement(ctx, PLACEMENT);
|
||||||
final BlockInput blockInput = border ? BlockStateArgument.getBlock(ctx, BORDER) : null;
|
final BlockInput blockInput = hasBorderArg ? BlockStateArgument.getBlock(ctx, BORDER) : null;
|
||||||
final BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, POS);
|
final BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, POS);
|
||||||
var structures = StructureNBT.allResourcesFrom(id);
|
final int recursionDepth = hasRecursionArg ? IntegerArgumentType.getInteger(ctx, RECURSION_DEPTH) : 1;
|
||||||
|
final List<StructureNBT> structures = StructureNBT.createResourcesFrom(id, recursionDepth);
|
||||||
if (structures != null) {
|
if (structures != null) {
|
||||||
Bounds b = Bounds.of(pos);
|
Bounds b = Bounds.of(pos);
|
||||||
Bounds all = Bounds.of(pos);
|
Bounds all = Bounds.of(pos);
|
||||||
BlockPos pNew = pos;
|
BlockPos pNew = pos;
|
||||||
|
BlockPos rowStart = pos;
|
||||||
|
String lastPrefix = null;
|
||||||
for (var s : structures) {
|
for (var s : structures) {
|
||||||
Bounds bb = Bounds.of(PlaceCommand.placeBlocks(
|
String prefix = s.location.getPath().contains("/")
|
||||||
|
? s.location.getPath().replaceAll("/[^/]*$", "")
|
||||||
|
: "";
|
||||||
|
if (lastPrefix != null && !lastPrefix.equals(prefix)) {
|
||||||
|
pNew = searchDir.resetStart(b, pNew, 10);
|
||||||
|
rowStart = pNew;
|
||||||
|
b = Bounds.of(pNew);
|
||||||
|
}
|
||||||
|
lastPrefix = prefix;
|
||||||
|
|
||||||
|
Bounds bb = Bounds.of(Objects.requireNonNull(PlaceCommand.placeBlocks(
|
||||||
ctx.getSource(),
|
ctx.getSource(),
|
||||||
pNew,
|
rowStart,
|
||||||
searchDir.getOffset(),
|
searchDir.getOffset(),
|
||||||
blockInput,
|
blockInput,
|
||||||
controlBlocks,
|
controlBlocks,
|
||||||
|
replaceAir,
|
||||||
s.location,
|
s.location,
|
||||||
(p) -> s.getBoundingBox(p, Rotation.NONE, Mirror.NONE),
|
(p) -> s.getBoundingBox(p, Rotation.NONE, Mirror.NONE),
|
||||||
(level, p) -> s.generateAt(level, p, Rotation.NONE, Mirror.NONE)
|
(level, p) -> s.generateAt(level, p, Rotation.NONE, Mirror.NONE)
|
||||||
));
|
)));
|
||||||
|
rowStart = searchDir.advanceStart(bb, rowStart);
|
||||||
|
;
|
||||||
|
|
||||||
b = b.encapsulate(bb);
|
b = b.encapsulate(bb);
|
||||||
all = all.encapsulate(bb);
|
all = all.encapsulate(bb);
|
||||||
if (searchDir == PlacementDirections.NORTH_OF || searchDir == PlacementDirections.SOUTH_OF) {
|
|
||||||
if (b.getSize().z > 10 * 16) {
|
|
||||||
pNew = new BlockPos((int) b.max.x + 3, pNew.getY(), pNew.getZ());
|
|
||||||
b = Bounds.of(pNew);
|
|
||||||
}
|
|
||||||
} else if (searchDir == PlacementDirections.EAST_OF || searchDir == PlacementDirections.WEST_OF) {
|
|
||||||
if (b.getSize().x > 10 * 16) {
|
|
||||||
pNew = new BlockPos(pNew.getX(), pNew.getY(), (int) b.max.z + 3);
|
|
||||||
b = Bounds.of(pNew);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (b.getSize().y > 10 * 16) {
|
|
||||||
pNew = new BlockPos(pNew.getX(), pNew.getY(), (int) b.max.z + 3);
|
|
||||||
b = Bounds.of(pNew);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
if (searchDir.sizeInDirection(b) > 10 * 16) {
|
||||||
|
pNew = searchDir.resetStart(b, pNew);
|
||||||
|
rowStart = pNew;
|
||||||
|
b = Bounds.of(pNew);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Bounds finalAll = all;
|
Bounds finalAll = all;
|
||||||
ctx.getSource()
|
ctx.getSource()
|
||||||
|
@ -191,6 +292,7 @@ class PlaceCommandBuilder {
|
||||||
searchDir.getOffset(),
|
searchDir.getOffset(),
|
||||||
blockInput,
|
blockInput,
|
||||||
controlBlocks,
|
controlBlocks,
|
||||||
|
replaceAir,
|
||||||
structureNBT.location,
|
structureNBT.location,
|
||||||
(p) -> structureNBT.getBoundingBox(p, Rotation.NONE, Mirror.NONE),
|
(p) -> structureNBT.getBoundingBox(p, Rotation.NONE, Mirror.NONE),
|
||||||
(level, p) -> structureNBT.generateAt(level, p, Rotation.NONE, Mirror.NONE)
|
(level, p) -> structureNBT.generateAt(level, p, Rotation.NONE, Mirror.NONE)
|
||||||
|
@ -200,12 +302,14 @@ class PlaceCommandBuilder {
|
||||||
|
|
||||||
protected static int placeEmpty(
|
protected static int placeEmpty(
|
||||||
CommandContext<CommandSourceStack> ctx,
|
CommandContext<CommandSourceStack> ctx,
|
||||||
boolean border,
|
boolean hasBorderArg,
|
||||||
boolean controlBlocks
|
boolean controlBlocks,
|
||||||
|
boolean replaceAir,
|
||||||
|
boolean hasRecursionArg
|
||||||
) throws CommandSyntaxException {
|
) throws CommandSyntaxException {
|
||||||
final ResourceLocation id = ResourceLocationArgument.getId(ctx, PATH);
|
final ResourceLocation id = ResourceLocationArgument.getId(ctx, PATH);
|
||||||
final PlacementDirections searchDir = TemplatePlacementArgument.getPlacement(ctx, PLACEMENT);
|
final PlacementDirections searchDir = TemplatePlacementArgument.getPlacement(ctx, PLACEMENT);
|
||||||
final BlockInput blockInput = border ? BlockStateArgument.getBlock(ctx, BORDER) : null;
|
final BlockInput blockInput = hasBorderArg ? BlockStateArgument.getBlock(ctx, BORDER) : null;
|
||||||
final BlockPos span = Float3ArgumentType.getFloat3(ctx, SPAN).toBlockPos();
|
final BlockPos span = Float3ArgumentType.getFloat3(ctx, SPAN).toBlockPos();
|
||||||
|
|
||||||
return PlaceCommand.placeBlocks(
|
return PlaceCommand.placeBlocks(
|
||||||
|
@ -214,6 +318,7 @@ class PlaceCommandBuilder {
|
||||||
searchDir == null || searchDir.dir == Float3.ZERO ? null : searchDir.dir.toBlockPos(),
|
searchDir == null || searchDir.dir == Float3.ZERO ? null : searchDir.dir.toBlockPos(),
|
||||||
blockInput,
|
blockInput,
|
||||||
controlBlocks,
|
controlBlocks,
|
||||||
|
replaceAir,
|
||||||
id,
|
id,
|
||||||
(p) -> BoundingBox.fromCorners(p, p.offset(span)),
|
(p) -> BoundingBox.fromCorners(p, p.offset(span)),
|
||||||
(level, p) -> {
|
(level, p) -> {
|
||||||
|
@ -232,9 +337,90 @@ class PlaceCommandBuilder {
|
||||||
}
|
}
|
||||||
) == null ? Command.SINGLE_SUCCESS : -1;
|
) == null ? Command.SINGLE_SUCCESS : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int placeJigsaw(
|
||||||
|
CommandContext<CommandSourceStack> ctx,
|
||||||
|
boolean hasReplaceArg,
|
||||||
|
boolean rotate,
|
||||||
|
boolean replaceFromWorld
|
||||||
|
) throws CommandSyntaxException {
|
||||||
|
// /bclib place jigsaw betterend:village/center_piece betterend:entrance fromWorld rollable 1235 -60 42
|
||||||
|
final BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, POS);
|
||||||
|
final Holder.Reference<StructureTemplatePool> pool = ResourceKeyArgument.getStructureTemplatePool(
|
||||||
|
ctx,
|
||||||
|
PlaceCommand.POOL
|
||||||
|
);
|
||||||
|
ResourceLocation connector = ResourceLocationArgument.getId(ctx, CONNECTOR_NAME);
|
||||||
|
if (connector.getNamespace().equals("-")) {
|
||||||
|
connector = new ResourceLocation(pool.key().location().getNamespace(), connector.getPath());
|
||||||
|
}
|
||||||
|
BlockState replaceWith = hasReplaceArg
|
||||||
|
? BlockStateArgument.getBlock(ctx, REPLACE_WITH).getState()
|
||||||
|
: Blocks.AIR.defaultBlockState();
|
||||||
|
|
||||||
|
final ServerLevel level = ctx.getSource().getLevel();
|
||||||
|
final ServerPlayer player = ctx.getSource().getPlayer();
|
||||||
|
final int deltaY = player.getBlockY() - pos.getY();
|
||||||
|
|
||||||
|
BlockState state = Blocks.JIGSAW.defaultBlockState();
|
||||||
|
|
||||||
|
|
||||||
|
if (deltaY < 2 && deltaY > -2 && !rotate) {
|
||||||
|
state = state.setValue(
|
||||||
|
JigsawBlock.ORIENTATION,
|
||||||
|
FrontAndTop.fromFrontAndTop(player.getDirection().getOpposite(), Direction.UP)
|
||||||
|
);
|
||||||
|
} else if (deltaY < 0) {
|
||||||
|
state = state.setValue(
|
||||||
|
JigsawBlock.ORIENTATION,
|
||||||
|
FrontAndTop.fromFrontAndTop(Direction.DOWN, player.getDirection().getOpposite())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
state = state.setValue(
|
||||||
|
JigsawBlock.ORIENTATION,
|
||||||
|
FrontAndTop.fromFrontAndTop(Direction.UP, player.getDirection().getOpposite())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replaceFromWorld) {
|
||||||
|
replaceWith = level.getBlockState(pos);
|
||||||
|
}
|
||||||
|
level.setBlock(pos, state, BlocksHelper.SET_SILENT);
|
||||||
|
if (level.getBlockEntity(pos) instanceof JigsawBlockEntity entity) {
|
||||||
|
entity.setName(connector);
|
||||||
|
entity.setTarget(connector);
|
||||||
|
entity.setPool(pool.key());
|
||||||
|
entity.setFinalState(BlockStateParser.serialize(replaceWith));
|
||||||
|
if (rotate) {
|
||||||
|
entity.setJoint(JigsawBlockEntity.JointType.ROLLABLE);
|
||||||
|
} else {
|
||||||
|
entity.setJoint(JigsawBlockEntity.JointType.ALIGNED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Command.SINGLE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int placeSpawner(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
|
||||||
|
final BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, POS);
|
||||||
|
final ServerLevel level = ctx.getSource().getLevel();
|
||||||
|
|
||||||
|
level.setBlock(pos, Blocks.SPAWNER.defaultBlockState(), BlocksHelper.SET_SILENT);
|
||||||
|
|
||||||
|
if (level.getBlockEntity(pos) instanceof SpawnerBlockEntity entity) {
|
||||||
|
CompoundTag tag = TagParser.parseTag(
|
||||||
|
"{SpawnData:{entity:{id:wither_skeleton,PersistenceRequired:1,HandItems:[{Count:1,id:netherite_sword},{Count:1,id:shield}],ArmorItems:[{Count:1,id:netherite_boots,tag:{Enchantments:[{id:protection,lvl:1}]}},{Count:1,id:netherite_leggings,tag:{Enchantments:[{id:protection,lvl:1}]}},{Count:1,id:netherite_chestplate,tag:{Enchantments:[{id:protection,lvl:1},{id:thorns,lvl:3}]}},{Count:1,id:netherite_helmet,tag:{Enchantments:[{id:protection,lvl:1}]}}],HandDropChances:[0.0f,0.0f],ArmorDropChances:[0.0f,0.0f,0.0f,0.0f]}, custom_spawn_rules:{sky_light_limit:{max_inclusive:13},block_light_limit:{max_inclusive:11}}},SpawnRange:4,SpawnCount:8,MaxNearbyEntities:18,Delay:499,MinSpawnDelay:300,MaxSpawnDelay:1600,RequiredPlayerRange:20}");
|
||||||
|
entity.load(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command.SINGLE_SUCCESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PlaceCommand {
|
public class PlaceCommand {
|
||||||
|
|
||||||
|
public static final String PLACE_COMMAND = "place";
|
||||||
|
public static final String POOL = "pool";
|
||||||
|
|
||||||
public PlaceCommand() {
|
public PlaceCommand() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +429,7 @@ public class PlaceCommand {
|
||||||
CommandBuildContext commandBuildContext
|
CommandBuildContext commandBuildContext
|
||||||
) {
|
) {
|
||||||
final var command = Commands
|
final var command = Commands
|
||||||
.literal("place")
|
.literal(PLACE_COMMAND)
|
||||||
.requires(commandSourceStack -> commandSourceStack.hasPermission(2));
|
.requires(commandSourceStack -> commandSourceStack.hasPermission(2));
|
||||||
|
|
||||||
new PlaceCommandBuilder().register(commandBuildContext, command);
|
new PlaceCommandBuilder().register(commandBuildContext, command);
|
||||||
|
@ -264,23 +450,23 @@ public class PlaceCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void replaceAir(Level level, BoundingBox bb) {
|
private static void replaceAir(Level level, BoundingBox bb) {
|
||||||
for (int x = bb.minX(); x <= bb.maxX(); x++)
|
BlocksHelper.forAllInBounds(bb, (bp) -> {
|
||||||
for (int y = bb.minY(); y <= bb.maxY(); y++)
|
if (level.getBlockState(bp).is(Blocks.AIR)) {
|
||||||
for (int z = bb.minZ(); z <= bb.maxZ(); z++) {
|
level.setBlock(bp, Blocks.STRUCTURE_VOID.defaultBlockState(), BlocksHelper.SET_OBSERV);
|
||||||
BlockPos bp = new BlockPos(x, y, z);
|
}
|
||||||
if (level.getBlockState(bp).is(Blocks.AIR)) {
|
});
|
||||||
level.setBlock(bp, Blocks.STRUCTURE_VOID.defaultBlockState(), BlocksHelper.SET_OBSERV);
|
}
|
||||||
}
|
|
||||||
}
|
private static void removeLootTableSeed(Level level, BoundingBox bb) {
|
||||||
|
BlocksHelper.forAllInBounds(bb, (bp) -> {
|
||||||
|
if (level.getBlockEntity(bp) instanceof RandomizableContainerBlockEntity rnd) {
|
||||||
|
rnd.setLootTable(null, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fill(Level level, BoundingBox bb, BlockState blockState) {
|
static void fill(Level level, BoundingBox bb, BlockState blockState) {
|
||||||
for (int x = bb.minX(); x <= bb.maxX(); x++)
|
BlocksHelper.forAllInBounds(bb, (bp) -> level.setBlock(bp, blockState, BlocksHelper.SET_OBSERV));
|
||||||
for (int y = bb.minY(); y <= bb.maxY(); y++)
|
|
||||||
for (int z = bb.minZ(); z <= bb.maxZ(); z++) {
|
|
||||||
BlockPos bp = new BlockPos(x, y, z);
|
|
||||||
level.setBlock(bp, blockState, BlocksHelper.SET_OBSERV);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fillStructureVoid(Level level, BoundingBox bb) {
|
static void fillStructureVoid(Level level, BoundingBox bb) {
|
||||||
|
@ -289,24 +475,7 @@ public class PlaceCommand {
|
||||||
|
|
||||||
//Draws a border around the bounding box
|
//Draws a border around the bounding box
|
||||||
private static void outline(Level level, BoundingBox bb, BlockState outlineState) {
|
private static void outline(Level level, BoundingBox bb, BlockState outlineState) {
|
||||||
for (int x = bb.minX(); x <= bb.maxX(); x++) {
|
BlocksHelper.forOutlineInBounds(bb, (bp) -> level.setBlock(bp, outlineState, BlocksHelper.SET_OBSERV));
|
||||||
level.setBlock(new BlockPos(x, bb.minY(), bb.minZ()), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(x, bb.maxY(), bb.minZ()), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(x, bb.minY(), bb.maxZ()), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(x, bb.maxY(), bb.maxZ()), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
}
|
|
||||||
for (int y = bb.minY(); y <= bb.maxY(); y++) {
|
|
||||||
level.setBlock(new BlockPos(bb.minX(), y, bb.minZ()), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(bb.maxX(), y, bb.minZ()), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(bb.minX(), y, bb.maxZ()), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(bb.maxX(), y, bb.maxZ()), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
}
|
|
||||||
for (int z = bb.minZ(); z <= bb.maxZ(); z++) {
|
|
||||||
level.setBlock(new BlockPos(bb.minX(), bb.minY(), z), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(bb.maxX(), bb.minY(), z), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(bb.minX(), bb.maxY(), z), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
level.setBlock(new BlockPos(bb.maxX(), bb.maxY(), z), outlineState, BlocksHelper.SET_OBSERV);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundingBox adapt(BoundingBox bb, boolean border, boolean structureBlock) {
|
private static BoundingBox adapt(BoundingBox bb, boolean border, boolean structureBlock) {
|
||||||
|
@ -314,12 +483,12 @@ public class PlaceCommand {
|
||||||
return bb.inflatedBy(1);
|
return bb.inflatedBy(1);
|
||||||
} else if (structureBlock) {
|
} else if (structureBlock) {
|
||||||
return new BoundingBox(
|
return new BoundingBox(
|
||||||
bb.minX() - 1,
|
bb.minX(),
|
||||||
bb.minY() - 1,
|
bb.minY(),
|
||||||
bb.minZ() - 1,
|
bb.minZ(),
|
||||||
bb.maxX(),
|
bb.maxX() + 1,
|
||||||
bb.maxY(),
|
bb.maxY() + 1,
|
||||||
bb.maxZ()
|
bb.maxZ() + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return bb;
|
return bb;
|
||||||
|
@ -374,6 +543,7 @@ public class PlaceCommand {
|
||||||
BlockPos searchDir,
|
BlockPos searchDir,
|
||||||
BlockInput blockInput,
|
BlockInput blockInput,
|
||||||
boolean structureBlock,
|
boolean structureBlock,
|
||||||
|
boolean replaceAir,
|
||||||
ResourceLocation location,
|
ResourceLocation location,
|
||||||
Function<BlockPos, BoundingBox> getBounds,
|
Function<BlockPos, BoundingBox> getBounds,
|
||||||
BiConsumer<ServerLevel, BlockPos> generate
|
BiConsumer<ServerLevel, BlockPos> generate
|
||||||
|
@ -399,10 +569,13 @@ public class PlaceCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (structureBlock) {
|
||||||
|
pos = pos.offset(1, 0, 1);
|
||||||
|
}
|
||||||
final BoundingBox bbNBT = getBounds.apply(pos);
|
final BoundingBox bbNBT = getBounds.apply(pos);
|
||||||
final BoundingBox bb;
|
final BoundingBox bb;
|
||||||
if (blockInput != null) {
|
if (blockInput != null) {
|
||||||
bb = bbNBT.inflatedBy(1);
|
bb = adapt(bbNBT, true, structureBlock);
|
||||||
outline(stack.getLevel(), bb, blockInput.getState());
|
outline(stack.getLevel(), bb, blockInput.getState());
|
||||||
stack.sendSuccess(() -> Component.literal("Placed border: " + bb.toString())
|
stack.sendSuccess(() -> Component.literal("Placed border: " + bb.toString())
|
||||||
.setStyle(Style.EMPTY.withColor(ChatFormatting.GREEN)), true);
|
.setStyle(Style.EMPTY.withColor(ChatFormatting.GREEN)), true);
|
||||||
|
@ -411,7 +584,10 @@ public class PlaceCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
generate.accept(stack.getLevel(), pos);
|
generate.accept(stack.getLevel(), pos);
|
||||||
replaceAir(stack.getLevel(), bbNBT);
|
if (replaceAir) {
|
||||||
|
replaceAir(stack.getLevel(), bbNBT);
|
||||||
|
}
|
||||||
|
removeLootTableSeed(stack.getLevel(), bbNBT);
|
||||||
|
|
||||||
stack.sendSuccess(() -> Component.literal("Placed NBT: " + bbNBT.toString())
|
stack.sendSuccess(() -> Component.literal("Placed NBT: " + bbNBT.toString())
|
||||||
.setStyle(Style.EMPTY.withColor(ChatFormatting.GREEN)), true);
|
.setStyle(Style.EMPTY.withColor(ChatFormatting.GREEN)), true);
|
||||||
|
|
|
@ -13,6 +13,7 @@ import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.block.*;
|
import net.minecraft.world.level.block.*;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.material.LavaFluid;
|
import net.minecraft.world.level.material.LavaFluid;
|
||||||
import net.minecraft.world.level.material.PushReaction;
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ import com.google.common.collect.Maps;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class BlocksHelper {
|
public class BlocksHelper {
|
||||||
|
@ -364,7 +366,37 @@ public class BlocksHelper {
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.canBeReplaced();
|
return state.canBeReplaced();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void forAllInBounds(BoundingBox bb, Consumer<BlockPos> worker) {
|
||||||
|
for (int x = bb.minX(); x <= bb.maxX(); x++)
|
||||||
|
for (int y = bb.minY(); y <= bb.maxY(); y++)
|
||||||
|
for (int z = bb.minZ(); z <= bb.maxZ(); z++) {
|
||||||
|
BlockPos bp = new BlockPos(x, y, z);
|
||||||
|
worker.accept(bp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void forOutlineInBounds(BoundingBox bb, Consumer<BlockPos> worker) {
|
||||||
|
for (int x = bb.minX(); x <= bb.maxX(); x++) {
|
||||||
|
worker.accept(new BlockPos(x, bb.minY(), bb.minZ()));
|
||||||
|
worker.accept(new BlockPos(x, bb.maxY(), bb.minZ()));
|
||||||
|
worker.accept(new BlockPos(x, bb.minY(), bb.maxZ()));
|
||||||
|
worker.accept(new BlockPos(x, bb.maxY(), bb.maxZ()));
|
||||||
|
}
|
||||||
|
for (int y = bb.minY(); y <= bb.maxY(); y++) {
|
||||||
|
worker.accept(new BlockPos(bb.minX(), y, bb.minZ()));
|
||||||
|
worker.accept(new BlockPos(bb.maxX(), y, bb.minZ()));
|
||||||
|
worker.accept(new BlockPos(bb.minX(), y, bb.maxZ()));
|
||||||
|
worker.accept(new BlockPos(bb.maxX(), y, bb.maxZ()));
|
||||||
|
}
|
||||||
|
for (int z = bb.minZ(); z <= bb.maxZ(); z++) {
|
||||||
|
worker.accept(new BlockPos(bb.minX(), bb.minY(), z));
|
||||||
|
worker.accept(new BlockPos(bb.maxX(), bb.minY(), z));
|
||||||
|
worker.accept(new BlockPos(bb.minX(), bb.maxY(), z));
|
||||||
|
worker.accept(new BlockPos(bb.maxX(), bb.maxY(), z));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue