From 42032890ed64af5aeba9a7a040393fbfc56fec9c Mon Sep 17 00:00:00 2001 From: ZacSharp <68165024+ZacSharp@users.noreply.github.com> Date: Sun, 28 Jul 2024 23:50:03 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20Setting=20to=20rotate=20schemat?= =?UTF-8?q?ics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/java/baritone/api/Settings.java | 14 ++ .../api/schematic/RotatedSchematic.java | 136 ++++++++++++++++++ .../java/baritone/api/utils/SettingsUtil.java | 4 +- .../java/baritone/process/BuilderProcess.java | 4 + 4 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/api/java/baritone/api/schematic/RotatedSchematic.java diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 1812fe486..b7612a46e 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -29,6 +29,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Rotation; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -1089,6 +1091,18 @@ public final class Settings { */ public final Setting schematicOrientationZ = new Setting<>(false); + /** + * Rotates the schematic before building it. + * Possible values are + * + */ + public final Setting buildSchematicRotation = new Setting<>(Rotation.NONE); + /** * The fallback used by the build command when no extension is specified. This may be useful if schematics of a * particular format are used often, and the user does not wish to have to specify the extension with every usage. diff --git a/src/api/java/baritone/api/schematic/RotatedSchematic.java b/src/api/java/baritone/api/schematic/RotatedSchematic.java new file mode 100644 index 000000000..e3c9ed7aa --- /dev/null +++ b/src/api/java/baritone/api/schematic/RotatedSchematic.java @@ -0,0 +1,136 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.schematic; + +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.Rotation; + +import java.util.List; +import java.util.stream.Collectors; + +public class RotatedSchematic implements ISchematic { + + private final ISchematic schematic; + private final Rotation rotation; + private final Rotation inverseRotation; + + public RotatedSchematic(ISchematic schematic, Rotation rotation) { + this.schematic = schematic; + this.rotation = rotation; + // I don't think a 14 line switch would improve readability + this.inverseRotation = rotation.getRotated(rotation).getRotated(rotation); + } + + @Override + public boolean inSchematic(int x, int y, int z, BlockState currentState) { + return schematic.inSchematic( + rotateX(x, z, widthX(), lengthZ(), inverseRotation), + y, + rotateZ(x, z, widthX(), lengthZ(), inverseRotation), + rotate(currentState, inverseRotation) + ); + } + + @Override + public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { + return rotate(schematic.desiredState( + rotateX(x, z, widthX(), lengthZ(), inverseRotation), + y, + rotateZ(x, z, widthX(), lengthZ(), inverseRotation), + rotate(current, inverseRotation), + rotate(approxPlaceable, inverseRotation) + ), rotation); + } + + @Override + public void reset() { + schematic.reset(); + } + + @Override + public int widthX() { + return flipsCoordinates(rotation) ? schematic.lengthZ() : schematic.widthX(); + } + + @Override + public int heightY() { + return schematic.heightY(); + } + + @Override + public int lengthZ() { + return flipsCoordinates(rotation) ? schematic.widthX() : schematic.lengthZ(); + } + + /** + * Wether {@code rotation} swaps the x and z components + */ + private static boolean flipsCoordinates(Rotation rotation) { + return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90; + } + + /** + * The x component of x,y after applying the rotation + */ + private static int rotateX(int x, int z, int sizeX, int sizeZ, Rotation rotation) { + switch (rotation) { + case NONE: + return x; + case CLOCKWISE_90: + return sizeZ - z - 1; + case CLOCKWISE_180: + return sizeX - x - 1; + case COUNTERCLOCKWISE_90: + return z; + } + throw new IllegalArgumentException("Unknown rotation"); + } + + /** + * The z component of x,y after applying the rotation + */ + private static int rotateZ(int x, int z, int sizeX, int sizeZ, Rotation rotation) { + switch (rotation) { + case NONE: + return z; + case CLOCKWISE_90: + return x; + case CLOCKWISE_180: + return sizeZ - z - 1; + case COUNTERCLOCKWISE_90: + return sizeX - x - 1; + } + throw new IllegalArgumentException("Unknown rotation"); + } + + private static BlockState rotate(BlockState state, Rotation rotation) { + if (state == null) { + return null; + } + return state.rotate(rotation); + } + + private static List rotate(List states, Rotation rotation) { + if (states == null) { + return null; + } + return states.stream() + .map(s -> rotate(s, rotation)) + .collect(Collectors.toList()); + } +} diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java index 23c2acddb..53c95f441 100644 --- a/src/api/java/baritone/api/utils/SettingsUtil.java +++ b/src/api/java/baritone/api/utils/SettingsUtil.java @@ -27,6 +27,8 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Rotation; + import java.awt.*; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -220,7 +222,7 @@ public class SettingsUtil { FLOAT(Float.class, Float::parseFloat), LONG(Long.class, Long::parseLong), STRING(String.class, String::new), - DIRECTION(Direction.class, Direction::byName), + ROTATION(Rotation.class, Rotation::valueOf, Rotation::name), COLOR( Color.class, str -> new Color(Integer.parseInt(str.split(",")[0]), Integer.parseInt(str.split(",")[1]), Integer.parseInt(str.split(",")[2])), diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 4b49398a0..5202d03b2 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -30,6 +30,7 @@ import baritone.api.schematic.ISchematic; import baritone.api.schematic.IStaticSchematic; import baritone.api.schematic.MaskSchematic; import baritone.api.schematic.SubstituteSchematic; +import baritone.api.schematic.RotatedSchematic; import baritone.api.schematic.format.ISchematicFormat; import baritone.api.utils.*; import baritone.api.utils.input.Input; @@ -119,6 +120,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (!Baritone.settings().buildSubstitutes.value.isEmpty()) { this.schematic = new SubstituteSchematic(this.schematic, Baritone.settings().buildSubstitutes.value); } + if (Baritone.settings().buildSchematicRotation.value != net.minecraft.world.level.block.Rotation.NONE) { + this.schematic = new RotatedSchematic(this.schematic, Baritone.settings().buildSchematicRotation.value); + } // TODO this preserves the old behavior, but maybe we should bake the setting value right here this.schematic = new MaskSchematic(this.schematic) { @Override From 7e8c852528308cc0a877d7f2b6c48383678e7d5c Mon Sep 17 00:00:00 2001 From: ZacSharp <68165024+ZacSharp@users.noreply.github.com> Date: Mon, 29 Jul 2024 00:20:25 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20Setting=20to=20mirror=20schemat?= =?UTF-8?q?ics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/java/baritone/api/Settings.java | 11 ++ .../api/schematic/MirroredSchematic.java | 114 ++++++++++++++++++ .../java/baritone/api/utils/SettingsUtil.java | 2 + .../java/baritone/process/BuilderProcess.java | 4 + 4 files changed, 131 insertions(+) create mode 100644 src/api/java/baritone/api/schematic/MirroredSchematic.java diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index b7612a46e..d9cb501ef 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -29,6 +29,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; import org.slf4j.Logger; @@ -1103,6 +1104,16 @@ public final class Settings { */ public final Setting buildSchematicRotation = new Setting<>(Rotation.NONE); + /** + * Mirrors the schematic before building it. + * Possible values are + *
    + *
  • FRONT_BACK - mirror the schematic along its local x axis
  • + *
  • LEFT_RIGHT - mirror the schematic along its local z axis
  • + *
+ */ + public final Setting buildSchematicMirror = new Setting<>(Mirror.NONE); + /** * The fallback used by the build command when no extension is specified. This may be useful if schematics of a * particular format are used often, and the user does not wish to have to specify the extension with every usage. diff --git a/src/api/java/baritone/api/schematic/MirroredSchematic.java b/src/api/java/baritone/api/schematic/MirroredSchematic.java new file mode 100644 index 000000000..b9e10808c --- /dev/null +++ b/src/api/java/baritone/api/schematic/MirroredSchematic.java @@ -0,0 +1,114 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.schematic; + +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.Mirror; + +import java.util.List; +import java.util.stream.Collectors; + +public class MirroredSchematic implements ISchematic { + + private final ISchematic schematic; + private final Mirror mirror; + + public MirroredSchematic(ISchematic schematic, Mirror mirror) { + this.schematic = schematic; + this.mirror = mirror; + } + + @Override + public boolean inSchematic(int x, int y, int z, BlockState currentState) { + return schematic.inSchematic( + mirrorX(x, widthX(), mirror), + y, + mirrorZ(z, lengthZ(), mirror), + mirror(currentState, mirror) + ); + } + + @Override + public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { + return mirror(schematic.desiredState( + mirrorX(x, widthX(), mirror), + y, + mirrorZ(z, lengthZ(), mirror), + mirror(current, mirror), + mirror(approxPlaceable, mirror) + ), mirror); + } + + @Override + public void reset() { + schematic.reset(); + } + + @Override + public int widthX() { + return schematic.widthX(); + } + + @Override + public int heightY() { + return schematic.heightY(); + } + + @Override + public int lengthZ() { + return schematic.lengthZ(); + } + + private static int mirrorX(int x, int sizeX, Mirror mirror) { + switch (mirror) { + case NONE: + case LEFT_RIGHT: + return x; + case FRONT_BACK: + return sizeX - x - 1; + } + throw new IllegalArgumentException("Unknown mirror"); + } + + private static int mirrorZ(int z, int sizeZ, Mirror mirror) { + switch (mirror) { + case NONE: + case FRONT_BACK: + return z; + case LEFT_RIGHT: + return sizeZ - z - 1; + } + throw new IllegalArgumentException("Unknown mirror"); + } + + private static BlockState mirror(BlockState state, Mirror mirror) { + if (state == null) { + return null; + } + return state.mirror(mirror); + } + + private static List mirror(List states, Mirror mirror) { + if (states == null) { + return null; + } + return states.stream() + .map(s -> mirror(s, mirror)) + .collect(Collectors.toList()); + } +} diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java index 53c95f441..7a18b61c3 100644 --- a/src/api/java/baritone/api/utils/SettingsUtil.java +++ b/src/api/java/baritone/api/utils/SettingsUtil.java @@ -27,6 +27,7 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; import java.awt.*; @@ -222,6 +223,7 @@ public class SettingsUtil { FLOAT(Float.class, Float::parseFloat), LONG(Long.class, Long::parseLong), STRING(String.class, String::new), + MIRROR(Mirror.class, Mirror::valueOf, Mirror::name), ROTATION(Rotation.class, Rotation::valueOf, Rotation::name), COLOR( Color.class, diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 5202d03b2..8f9a5ba0d 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -31,6 +31,7 @@ import baritone.api.schematic.IStaticSchematic; import baritone.api.schematic.MaskSchematic; import baritone.api.schematic.SubstituteSchematic; import baritone.api.schematic.RotatedSchematic; +import baritone.api.schematic.MirroredSchematic; import baritone.api.schematic.format.ISchematicFormat; import baritone.api.utils.*; import baritone.api.utils.input.Input; @@ -120,6 +121,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (!Baritone.settings().buildSubstitutes.value.isEmpty()) { this.schematic = new SubstituteSchematic(this.schematic, Baritone.settings().buildSubstitutes.value); } + if (Baritone.settings().buildSchematicMirror.value != net.minecraft.world.level.block.Mirror.NONE) { + this.schematic = new MirroredSchematic(this.schematic, Baritone.settings().buildSchematicMirror.value); + } if (Baritone.settings().buildSchematicRotation.value != net.minecraft.world.level.block.Rotation.NONE) { this.schematic = new RotatedSchematic(this.schematic, Baritone.settings().buildSchematicRotation.value); }