Skip to content

Commit

Permalink
Merge pull request #4452 from ZacSharp/pr/1.19.4/builder/rotateAndMir…
Browse files Browse the repository at this point in the history
…rorSchematics

Add settings to rotate/mirror schematics
  • Loading branch information
leijurv authored Sep 16, 2024
2 parents ef72c56 + 7e8c852 commit d25d6c2
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 1 deletion.
25 changes: 25 additions & 0 deletions src/api/java/baritone/api/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
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;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -1089,6 +1092,28 @@ public final class Settings {
*/
public final Setting<Boolean> schematicOrientationZ = new Setting<>(false);

/**
* Rotates the schematic before building it.
* Possible values are
* <ul>
* <li> NONE - No rotation </li>
* <li> CLOCKWISE_90 - Rotate 90° clockwise </li>
* <li> CLOCKWISE_180 - Rotate 180° clockwise </li>
* <li> COUNTERCLOCKWISE_90 - Rotate 270° clockwise </li>
* </ul>
*/
public final Setting<Rotation> buildSchematicRotation = new Setting<>(Rotation.NONE);

/**
* Mirrors the schematic before building it.
* Possible values are
* <ul>
* <li> FRONT_BACK - mirror the schematic along its local x axis </li>
* <li> LEFT_RIGHT - mirror the schematic along its local z axis </li>
* </ul>
*/
public final Setting<Mirror> 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.
Expand Down
114 changes: 114 additions & 0 deletions src/api/java/baritone/api/schematic/MirroredSchematic.java
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

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<BlockState> 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<BlockState> mirror(List<BlockState> states, Mirror mirror) {
if (states == null) {
return null;
}
return states.stream()
.map(s -> mirror(s, mirror))
.collect(Collectors.toList());
}
}
136 changes: 136 additions & 0 deletions src/api/java/baritone/api/schematic/RotatedSchematic.java
Original file line number Diff line number Diff line change
@@ -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 <https://www.gnu.org/licenses/>.
*/

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<BlockState> 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<BlockState> rotate(List<BlockState> states, Rotation rotation) {
if (states == null) {
return null;
}
return states.stream()
.map(s -> rotate(s, rotation))
.collect(Collectors.toList());
}
}
6 changes: 5 additions & 1 deletion src/api/java/baritone/api/utils/SettingsUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
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.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
Expand Down Expand Up @@ -220,7 +223,8 @@ private enum Parser implements ISettingParser {
FLOAT(Float.class, Float::parseFloat),
LONG(Long.class, Long::parseLong),
STRING(String.class, String::new),
DIRECTION(Direction.class, Direction::byName),
MIRROR(Mirror.class, Mirror::valueOf, Mirror::name),
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])),
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/baritone/process/BuilderProcess.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
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;
Expand Down Expand Up @@ -118,6 +120,12 @@ public void build(String name, ISchematic schematic, Vec3i origin) {
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);
}
// TODO this preserves the old behavior, but maybe we should bake the setting value right here
this.schematic = new MaskSchematic(this.schematic) {
@Override
Expand Down

0 comments on commit d25d6c2

Please sign in to comment.