From 5c9f02810347ec8e5bc0c98d0938eefbbd1f4330 Mon Sep 17 00:00:00 2001 From: Brady Date: Wed, 18 Dec 2019 10:24:43 -0600 Subject: [PATCH 01/14] Initial sponge support --- .../api/schematic/AbstractSchematic.java | 4 + .../baritone/api/utils/BlockOptionalMeta.java | 8 +- .../java/baritone/process/BuilderProcess.java | 31 ++- .../utils/schematic/MapArtSchematic.java | 42 +++- .../baritone/utils/schematic/Schematic.java | 92 -------- .../schematic/format/SchematicFormat.java | 70 ++++++ .../schematic/parse/ISchematicParser.java | 32 +++ .../utils/schematic/parse/MCEditParser.java | 94 ++++++++ .../utils/schematic/parse/SpongeParser.java | 202 ++++++++++++++++++ 9 files changed, 456 insertions(+), 119 deletions(-) delete mode 100644 src/main/java/baritone/utils/schematic/Schematic.java create mode 100644 src/main/java/baritone/utils/schematic/format/SchematicFormat.java create mode 100644 src/main/java/baritone/utils/schematic/parse/ISchematicParser.java create mode 100644 src/main/java/baritone/utils/schematic/parse/MCEditParser.java create mode 100644 src/main/java/baritone/utils/schematic/parse/SpongeParser.java diff --git a/src/api/java/baritone/api/schematic/AbstractSchematic.java b/src/api/java/baritone/api/schematic/AbstractSchematic.java index 3cd14747..cca6bc96 100644 --- a/src/api/java/baritone/api/schematic/AbstractSchematic.java +++ b/src/api/java/baritone/api/schematic/AbstractSchematic.java @@ -23,6 +23,10 @@ public abstract class AbstractSchematic implements ISchematic { protected int y; protected int z; + public AbstractSchematic() { + this(0, 0, 0); + } + public AbstractSchematic(int x, int y, int z) { this.x = x; this.y = y; diff --git a/src/api/java/baritone/api/utils/BlockOptionalMeta.java b/src/api/java/baritone/api/utils/BlockOptionalMeta.java index 3ab76dd2..451d95eb 100644 --- a/src/api/java/baritone/api/utils/BlockOptionalMeta.java +++ b/src/api/java/baritone/api/utils/BlockOptionalMeta.java @@ -178,12 +178,12 @@ public final class BlockOptionalMeta { normalizations = Collections.unmodifiableMap(_normalizations); } - private static , P extends IProperty> P castToIProperty(Object value) { + public static , P extends IProperty> P castToIProperty(Object value) { //noinspection unchecked return (P) value; } - private static , P extends IProperty> C castToIPropertyValue(P iproperty, Object value) { + public static , P extends IProperty> C castToIPropertyValue(P iproperty, Object value) { //noinspection unchecked return (C) value; } @@ -191,6 +191,10 @@ public final class BlockOptionalMeta { public static IBlockState normalize(IBlockState state) { IBlockState newState = state; + // TODO: Can the state not be normalized by simply doing...? + // return state.getBlock().getDefaultState(); + // ??? + for (IProperty property : state.getProperties().keySet()) { Class valueClass = property.getValueClass(); if (normalizations.containsKey(property)) { diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 4d66a764..1dfd6c82 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -39,7 +39,7 @@ import baritone.utils.BlockStateInterface; import baritone.utils.PathingCommandContext; import baritone.utils.schematic.FillSchematic; import baritone.utils.schematic.MapArtSchematic; -import baritone.utils.schematic.Schematic; +import baritone.utils.schematic.format.SchematicFormat; import baritone.utils.schematic.schematica.SchematicaHelper; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.block.BlockAir; @@ -48,15 +48,12 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumFacing; import net.minecraft.util.Tuple; import net.minecraft.util.math.*; import java.io.File; import java.io.FileInputStream; -import java.io.IOException; import java.util.*; import static baritone.api.pathing.movement.ActionCosts.COST_INF; @@ -118,18 +115,24 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil @Override public boolean build(String name, File schematic, Vec3i origin) { - NBTTagCompound tag; - try (FileInputStream fileIn = new FileInputStream(schematic)) { - tag = CompressedStreamTools.readCompressed(fileIn); - } catch (IOException e) { + Optional format = SchematicFormat.getByFile(schematic); + if (!format.isPresent()) { + return false; + } + + ISchematic parsed; + try { + parsed = format.get().getParser().parse(new FileInputStream(schematic)); + } catch (Exception e) { e.printStackTrace(); return false; } - //noinspection ConstantConditions - if (tag == null) { - return false; + + if (Baritone.settings().mapArtMode.value) { + parsed = new MapArtSchematic(parsed); } - build(name, parse(tag), origin); + + build(name, parsed, origin); return true; } @@ -160,10 +163,6 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return new ArrayList<>(approxPlaceable); } - private static ISchematic parse(NBTTagCompound schematic) { - return Baritone.settings().mapArtMode.value ? new MapArtSchematic(schematic) : new Schematic(schematic); - } - @Override public boolean isActive() { return schematic != null; diff --git a/src/main/java/baritone/utils/schematic/MapArtSchematic.java b/src/main/java/baritone/utils/schematic/MapArtSchematic.java index 32b3292c..33ec3a15 100644 --- a/src/main/java/baritone/utils/schematic/MapArtSchematic.java +++ b/src/main/java/baritone/utils/schematic/MapArtSchematic.java @@ -17,24 +17,29 @@ package baritone.utils.schematic; +import baritone.api.schematic.AbstractSchematic; +import baritone.api.schematic.ISchematic; import net.minecraft.block.BlockAir; import net.minecraft.block.state.IBlockState; -import net.minecraft.nbt.NBTTagCompound; +import java.util.List; import java.util.OptionalInt; import java.util.function.Predicate; -public class MapArtSchematic extends Schematic { +public class MapArtSchematic extends AbstractSchematic { + private final ISchematic child; private final int[][] heightMap; - public MapArtSchematic(NBTTagCompound schematic) { - super(schematic); - heightMap = new int[widthX][lengthZ]; + public MapArtSchematic(ISchematic schematic) { + super(schematic.widthX(), schematic.heightY(), schematic.lengthZ()); + this.child = schematic; - for (int x = 0; x < widthX; x++) { - for (int z = 0; z < lengthZ; z++) { - IBlockState[] column = states[x][z]; + heightMap = new int[schematic.widthX()][schematic.lengthZ()]; + + for (int x = 0; x < schematic.widthX(); x++) { + for (int z = 0; z < schematic.lengthZ(); z++) { + IBlockState[] column = /*states[x][z]*/null; OptionalInt lowestBlockY = lastIndexMatching(column, state -> !(state.getBlock() instanceof BlockAir)); if (lowestBlockY.isPresent()) { @@ -44,7 +49,6 @@ public class MapArtSchematic extends Schematic { System.out.println("Letting it be whatever"); heightMap[x][z] = 256; } - } } } @@ -63,4 +67,24 @@ public class MapArtSchematic extends Schematic { // in map art, we only care about coordinates in or above the art return super.inSchematic(x, y, z, currentState) && y >= heightMap[x][z]; } + + @Override + public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { + return this.child.desiredState(x, y, z, current, approxPlaceable); + } + + @Override + public int widthX() { + return this.child.widthX(); + } + + @Override + public int heightY() { + return this.child.heightY(); + } + + @Override + public int lengthZ() { + return this.child.lengthZ(); + } } diff --git a/src/main/java/baritone/utils/schematic/Schematic.java b/src/main/java/baritone/utils/schematic/Schematic.java deleted file mode 100644 index 1169578a..00000000 --- a/src/main/java/baritone/utils/schematic/Schematic.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.utils.schematic; - -import baritone.api.schematic.ISchematic; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.nbt.NBTTagCompound; - -import java.util.List; - -public class Schematic implements ISchematic { - - public final int widthX; - public final int heightY; - public final int lengthZ; - protected final IBlockState[][][] states; - - public Schematic(NBTTagCompound schematic) { - String type = schematic.getString("Materials"); - if (!type.equals("Alpha")) { - throw new IllegalStateException("bad schematic " + type); - } - widthX = schematic.getInteger("Width"); - heightY = schematic.getInteger("Height"); - lengthZ = schematic.getInteger("Length"); - byte[] blocks = schematic.getByteArray("Blocks"); - byte[] metadata = schematic.getByteArray("Data"); - - byte[] additional = null; - if (schematic.hasKey("AddBlocks")) { - byte[] addBlocks = schematic.getByteArray("AddBlocks"); - additional = new byte[addBlocks.length * 2]; - for (int i = 0; i < addBlocks.length; i++) { - additional[i * 2 + 0] = (byte) ((addBlocks[i] >> 4) & 0xF); // lower nibble - additional[i * 2 + 1] = (byte) ((addBlocks[i] >> 0) & 0xF); // upper nibble - } - } - states = new IBlockState[widthX][lengthZ][heightY]; - for (int y = 0; y < heightY; y++) { - for (int z = 0; z < lengthZ; z++) { - for (int x = 0; x < widthX; x++) { - int blockInd = (y * lengthZ + z) * widthX + x; - - int blockID = blocks[blockInd] & 0xFF; - if (additional != null) { - // additional is 0 through 15 inclusive since it's & 0xF above - blockID |= additional[blockInd] << 8; - } - Block block = Block.REGISTRY.getObjectById(blockID); - int meta = metadata[blockInd] & 0xFF; - states[x][z][y] = block.getStateFromMeta(meta); - } - } - } - } - - @Override - public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { - return states[x][z][y]; - } - - @Override - public int widthX() { - return widthX; - } - - @Override - public int heightY() { - return heightY; - } - - @Override - public int lengthZ() { - return lengthZ; - } -} diff --git a/src/main/java/baritone/utils/schematic/format/SchematicFormat.java b/src/main/java/baritone/utils/schematic/format/SchematicFormat.java new file mode 100644 index 00000000..5f103d9a --- /dev/null +++ b/src/main/java/baritone/utils/schematic/format/SchematicFormat.java @@ -0,0 +1,70 @@ +/* + * 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.utils.schematic.format; + +import baritone.utils.schematic.parse.ISchematicParser; +import baritone.utils.schematic.parse.MCEditParser; +import baritone.utils.schematic.parse.SpongeParser; +import org.apache.commons.io.FilenameUtils; + +import java.io.File; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * @author Brady + * @since 12/13/2019 + */ +public enum SchematicFormat { + + /** + * The MCEdit schematic specification. Commonly denoted by the ".schematic" file extension. + */ + MCEDIT("schematic", MCEditParser.INSTANCE), + + /** + * The SpongePowered Schematic Specification. Commonly denoted by the ".schem" file extension. + * + * @see Sponge Schematic Specification + */ + SPONGE("schem", SpongeParser.INSTANCE); + + private final String extension; + private final ISchematicParser parser; + + SchematicFormat(String extension, ISchematicParser parser) { + this.extension = extension; + this.parser = parser; + } + + public final ISchematicParser getParser() { + return this.parser; + } + + public static Optional getByFile(File schematic) { + // TODO: Better identification + // Maybe peek file contents and make a safe determination? + return getByExtension(FilenameUtils.getExtension(schematic.getAbsolutePath())); + } + + public static Optional getByExtension(String extension) { + return extension == null || extension.isEmpty() + ? Optional.empty() + : Stream.of(values()).filter(format -> format.extension.equals(extension)).findFirst(); + } +} diff --git a/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java b/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java new file mode 100644 index 00000000..040addc1 --- /dev/null +++ b/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java @@ -0,0 +1,32 @@ +/* + * 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.utils.schematic.parse; + +import baritone.api.schematic.ISchematic; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author Brady + * @since 12/13/2019 + */ +public interface ISchematicParser { + + ISchematic parse(InputStream input) throws IOException; +} diff --git a/src/main/java/baritone/utils/schematic/parse/MCEditParser.java b/src/main/java/baritone/utils/schematic/parse/MCEditParser.java new file mode 100644 index 00000000..dce2c856 --- /dev/null +++ b/src/main/java/baritone/utils/schematic/parse/MCEditParser.java @@ -0,0 +1,94 @@ +/* + * 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.utils.schematic.parse; + +import baritone.api.schematic.AbstractSchematic; +import baritone.api.schematic.ISchematic; +import baritone.utils.schematic.format.SchematicFormat; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +/** + * An implementation of {@link ISchematicParser} for {@link SchematicFormat#MCEDIT} + * + * @author Brady + * @since 12/16/2019 + */ +public enum MCEditParser implements ISchematicParser { + INSTANCE; + + @Override + public ISchematic parse(InputStream input) throws IOException { + return new MCEditSchematic(CompressedStreamTools.readCompressed(input)); + } + + private static final class MCEditSchematic extends AbstractSchematic { + + private final IBlockState[][][] states; + + MCEditSchematic(NBTTagCompound schematic) { + String type = schematic.getString("Materials"); + if (!type.equals("Alpha")) { + throw new IllegalStateException("bad schematic " + type); + } + this.x = schematic.getInteger("Width"); + this.y = schematic.getInteger("Height"); + this.z = schematic.getInteger("Length"); + byte[] blocks = schematic.getByteArray("Blocks"); + byte[] metadata = schematic.getByteArray("Data"); + + byte[] additional = null; + if (schematic.hasKey("AddBlocks")) { + byte[] addBlocks = schematic.getByteArray("AddBlocks"); + additional = new byte[addBlocks.length * 2]; + for (int i = 0; i < addBlocks.length; i++) { + additional[i * 2 + 0] = (byte) ((addBlocks[i] >> 4) & 0xF); // lower nibble + additional[i * 2 + 1] = (byte) ((addBlocks[i] >> 0) & 0xF); // upper nibble + } + } + this.states = new IBlockState[this.x][this.z][this.y]; + for (int y = 0; y < this.y; y++) { + for (int z = 0; z < this.z; z++) { + for (int x = 0; x < this.x; x++) { + int blockInd = (y * this.z + z) * this.x + x; + + int blockID = blocks[blockInd] & 0xFF; + if (additional != null) { + // additional is 0 through 15 inclusive since it's & 0xF above + blockID |= additional[blockInd] << 8; + } + Block block = Block.REGISTRY.getObjectById(blockID); + int meta = metadata[blockInd] & 0xFF; + this.states[x][z][y] = block.getStateFromMeta(meta); + } + } + } + } + + @Override + public final IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { + return this.states[x][z][y]; + } + } +} diff --git a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java new file mode 100644 index 00000000..71984f91 --- /dev/null +++ b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java @@ -0,0 +1,202 @@ +/* + * 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.utils.schematic.parse; + +import baritone.api.schematic.AbstractSchematic; +import baritone.api.schematic.ISchematic; +import baritone.api.utils.BlockOptionalMeta; +import baritone.utils.schematic.format.SchematicFormat; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import net.minecraft.block.Block; +import net.minecraft.block.properties.IProperty; +import net.minecraft.block.state.IBlockState; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * An implementation of {@link ISchematicParser} for {@link SchematicFormat#SPONGE} + * + * @author Brady + * @since 12/16/2019 + */ +public enum SpongeParser implements ISchematicParser { + INSTANCE; + + @Override + public ISchematic parse(InputStream input) throws IOException { + NBTTagCompound nbt = CompressedStreamTools.readCompressed(input); + int version = nbt.getInteger("Version"); + switch (version) { + case 1: + case 2: + return new SpongeSchematic(nbt); + default: + throw new UnsupportedOperationException("Unsupported Version of the a Sponge Schematic"); + } + } + + /** + * Implementation of the Sponge Schematic Format supporting both V1 and V2. (For the current + * use case, there is no difference between reading a V1 and V2 schematic). + */ + private static final class SpongeSchematic extends AbstractSchematic { + + /** + * Block states for this schematic stored in [x, z, y] indexing order + */ + private IBlockState[][][] states; + + SpongeSchematic(NBTTagCompound nbt) { + this.x = nbt.getInteger("Width"); + this.y = nbt.getInteger("Height"); + this.z = nbt.getInteger("Length"); + this.states = new IBlockState[this.x][this.z][this.y]; + + Int2ObjectArrayMap palette = new Int2ObjectArrayMap<>(); + NBTTagCompound paletteTag = nbt.getCompoundTag("Palette"); + for (String tag : paletteTag.getKeySet()) { + int index = paletteTag.getInteger(tag); + + SerializedBlockState serializedState = SerializedBlockState.getFromString(tag); + if (serializedState == null) { + throw new IllegalArgumentException("Unable to parse palette tag"); + } + + IBlockState state = serializedState.deserialize(); + if (state == null) { + throw new IllegalArgumentException("Unable to deserialize palette tag"); + } + + palette.put(index, state); + } + + // BlockData is stored as an NBT byte[], however, the actual data that is represented is a varint[]. + // This is kind of a hacky approach but it works /shrug + byte[] rawBlockData = nbt.getByteArray("BlockData"); + int[] blockData = new int[this.x * this.y * this.z]; + PacketBuffer buffer = new PacketBuffer(Unpooled.wrappedBuffer(rawBlockData)); + for (int i = 0; i < blockData.length; i++) { + if (buffer.readableBytes() > 0) { + blockData[i] = buffer.readVarInt(); + } else { + throw new IllegalArgumentException("Not enough"); + } + } + + for (int y = 0; y < this.y; y++) { + for (int z = 0; z < this.z; z++) { + for (int x = 0; x < this.x; x++) { + int index = (y * this.z + z) * this.x + x; + this.states[x][z][y] = palette.get(blockData[index]); + } + } + } + } + + @Override + public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { + return this.states[x][z][y]; + } + } + + private static final class SerializedBlockState { + + private static final Pattern REGEX = Pattern.compile("(?(\\w+:)?\\w+)(\\[(?(\\w+=\\w+,?)+)])?"); + + private final ResourceLocation resourceLocation; + private final Map properties; + private IBlockState blockState; + + private SerializedBlockState(ResourceLocation resourceLocation, Map properties) { + this.resourceLocation = resourceLocation; + this.properties = properties; + } + + ResourceLocation getResourceLocation() { + return this.resourceLocation; + } + + Map getProperties() { + return this.properties; + } + + IBlockState deserialize() { + if (this.blockState == null) { + // Get the base state for the block specified + this.blockState = Block.REGISTRY.getObject(this.resourceLocation).getDefaultState(); + + // AFAIK it is best to order the property keys so that Minecraft caches the Block States ideally + this.properties.keySet().stream().sorted(String::compareTo).forEachOrdered(key -> { + // getProperty(String) when lol + IProperty property = this.blockState.getPropertyKeys().stream() + .filter(p -> p.getName().equals(key)) + .findFirst().orElseThrow(IllegalArgumentException::new); + + Optional value = property.parseValue(this.properties.get(key)).toJavaUtil(); + if (value.isPresent()) { + this.blockState = this.blockState.withProperty( + BlockOptionalMeta.castToIProperty(property), + BlockOptionalMeta.castToIPropertyValue(property, value) + ); + } else { + throw new IllegalArgumentException(); + } + }); + } + return this.blockState; + } + + static SerializedBlockState getFromString(String s) { + Matcher m = REGEX.matcher(s); + if (!m.matches()) { + return null; + } + + try { + String location = m.group("location"); + String properties = m.group("properties"); + + ResourceLocation resourceLocation = new ResourceLocation(location); + Map propertiesMap = new HashMap<>(); + if (properties != null) { + for (String property : properties.split(",")) { + String[] split = property.split("="); + propertiesMap.put(split[0], split[1]); + } + } + + return new SerializedBlockState(resourceLocation, propertiesMap); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + } +} From b4ddf381162aca4122fc7969c613e2aa6bf772f6 Mon Sep 17 00:00:00 2001 From: Brady Date: Wed, 18 Dec 2019 10:27:34 -0600 Subject: [PATCH 02/14] Check if state is null --- .../baritone/utils/schematic/parse/SpongeParser.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java index 71984f91..1b6cb5e0 100644 --- a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java +++ b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java @@ -106,7 +106,7 @@ public enum SpongeParser implements ISchematicParser { if (buffer.readableBytes() > 0) { blockData[i] = buffer.readVarInt(); } else { - throw new IllegalArgumentException("Not enough"); + throw new IllegalArgumentException("Buffer has no remaining bytes"); } } @@ -114,7 +114,12 @@ public enum SpongeParser implements ISchematicParser { for (int z = 0; z < this.z; z++) { for (int x = 0; x < this.x; x++) { int index = (y * this.z + z) * this.x + x; - this.states[x][z][y] = palette.get(blockData[index]); + IBlockState state = palette.get(blockData[index]); + if (state == null) { + throw new IllegalArgumentException("Invalid Palette Index " + index); + } + + this.states[x][z][y] = state; } } } From ea8d7fb3b9bfbe93e0c7415a4fdc1f37d26f5dc0 Mon Sep 17 00:00:00 2001 From: Brady Date: Wed, 18 Dec 2019 15:19:58 -0600 Subject: [PATCH 03/14] Improve file extension fallback mechanism --- src/api/java/baritone/api/Settings.java | 6 ++++++ src/main/java/baritone/command/defaults/BuildCommand.java | 7 ++++--- .../baritone/utils/schematic/format/SchematicFormat.java | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index bf077f1a..69bcabcb 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -811,6 +811,12 @@ public final class Settings { */ public final Setting schematicOrientationZ = new Setting<>(false); + /** + * 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. + */ + public final Setting schematicFallbackExtension = new Setting<>("schematic"); + /** * Distance to scan every tick for updates. Expanding this beyond player reach distance (i.e. setting it to 6 or above) * is only necessary in very large schematics where rescanning the whole thing is costly. diff --git a/src/main/java/baritone/command/defaults/BuildCommand.java b/src/main/java/baritone/command/defaults/BuildCommand.java index 39bf0d3f..3d549587 100644 --- a/src/main/java/baritone/command/defaults/BuildCommand.java +++ b/src/main/java/baritone/command/defaults/BuildCommand.java @@ -17,6 +17,7 @@ package baritone.command.defaults; +import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.utils.BetterBlockPos; import baritone.api.command.Command; @@ -26,11 +27,11 @@ import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandInvalidStateException; import baritone.api.command.argument.IArgConsumer; import net.minecraft.client.Minecraft; +import org.apache.commons.io.FilenameUtils; import java.io.File; import java.util.Arrays; import java.util.List; -import java.util.Locale; import java.util.stream.Stream; public class BuildCommand extends Command { @@ -44,8 +45,8 @@ public class BuildCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { File file = args.getDatatypePost(RelativeFile.INSTANCE, schematicsDir).getAbsoluteFile(); - if (!file.getName().toLowerCase(Locale.US).endsWith(".schematic")) { - file = new File(file.getAbsolutePath() + ".schematic"); + if (FilenameUtils.getExtension(file.getAbsolutePath()).isEmpty()) { + file = new File(file.getAbsolutePath() + "." + Baritone.settings().schematicFallbackExtension); } BetterBlockPos origin = ctx.playerFeet(); BetterBlockPos buildOrigin; diff --git a/src/main/java/baritone/utils/schematic/format/SchematicFormat.java b/src/main/java/baritone/utils/schematic/format/SchematicFormat.java index 5f103d9a..6c84273e 100644 --- a/src/main/java/baritone/utils/schematic/format/SchematicFormat.java +++ b/src/main/java/baritone/utils/schematic/format/SchematicFormat.java @@ -65,6 +65,6 @@ public enum SchematicFormat { public static Optional getByExtension(String extension) { return extension == null || extension.isEmpty() ? Optional.empty() - : Stream.of(values()).filter(format -> format.extension.equals(extension)).findFirst(); + : Stream.of(values()).filter(format -> format.extension.equalsIgnoreCase(extension)).findFirst(); } } From aa3bd80ab2066dc30452cc68de4265924ac18d9a Mon Sep 17 00:00:00 2001 From: Brady Date: Thu, 19 Dec 2019 11:40:38 -0600 Subject: [PATCH 04/14] Clean ups --- .../utils/schematic/MapArtSchematic.java | 2 +- .../utils/schematic/parse/SpongeParser.java | 59 +++++------- src/main/java/baritone/utils/type/VarInt.java | 94 +++++++++++++++++++ 3 files changed, 120 insertions(+), 35 deletions(-) create mode 100644 src/main/java/baritone/utils/type/VarInt.java diff --git a/src/main/java/baritone/utils/schematic/MapArtSchematic.java b/src/main/java/baritone/utils/schematic/MapArtSchematic.java index 33ec3a15..ec477b57 100644 --- a/src/main/java/baritone/utils/schematic/MapArtSchematic.java +++ b/src/main/java/baritone/utils/schematic/MapArtSchematic.java @@ -65,7 +65,7 @@ public class MapArtSchematic extends AbstractSchematic { @Override public boolean inSchematic(int x, int y, int z, IBlockState currentState) { // in map art, we only care about coordinates in or above the art - return super.inSchematic(x, y, z, currentState) && y >= heightMap[x][z]; + return this.child.inSchematic(x, y, z, currentState) && y >= heightMap[x][z]; } @Override diff --git a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java index 1b6cb5e0..6219f148 100644 --- a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java +++ b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java @@ -19,16 +19,14 @@ package baritone.utils.schematic.parse; import baritone.api.schematic.AbstractSchematic; import baritone.api.schematic.ISchematic; -import baritone.api.utils.BlockOptionalMeta; import baritone.utils.schematic.format.SchematicFormat; -import io.netty.buffer.Unpooled; +import baritone.utils.type.VarInt; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import net.minecraft.block.Block; import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import java.io.IOException; @@ -97,17 +95,18 @@ public enum SpongeParser implements ISchematicParser { palette.put(index, state); } - // BlockData is stored as an NBT byte[], however, the actual data that is represented is a varint[]. - // This is kind of a hacky approach but it works /shrug + // BlockData is stored as an NBT byte[], however, the actual data that is represented is a varint[] byte[] rawBlockData = nbt.getByteArray("BlockData"); int[] blockData = new int[this.x * this.y * this.z]; - PacketBuffer buffer = new PacketBuffer(Unpooled.wrappedBuffer(rawBlockData)); + int offset = 0; for (int i = 0; i < blockData.length; i++) { - if (buffer.readableBytes() > 0) { - blockData[i] = buffer.readVarInt(); - } else { - throw new IllegalArgumentException("Buffer has no remaining bytes"); + if (offset >= blockData.length) { + throw new IllegalArgumentException("No remaining bytes in BlockData for complete schematic"); } + + VarInt varInt = VarInt.read(rawBlockData, offset); + blockData[i] = varInt.getValue(); + offset += varInt.getSize(); } for (int y = 0; y < this.y; y++) { @@ -144,35 +143,18 @@ public enum SpongeParser implements ISchematicParser { this.properties = properties; } - ResourceLocation getResourceLocation() { - return this.resourceLocation; - } - - Map getProperties() { - return this.properties; - } - IBlockState deserialize() { if (this.blockState == null) { - // Get the base state for the block specified - this.blockState = Block.REGISTRY.getObject(this.resourceLocation).getDefaultState(); + Block block = Block.REGISTRY.getObject(this.resourceLocation); + this.blockState = block.getDefaultState(); - // AFAIK it is best to order the property keys so that Minecraft caches the Block States ideally this.properties.keySet().stream().sorted(String::compareTo).forEachOrdered(key -> { - // getProperty(String) when lol - IProperty property = this.blockState.getPropertyKeys().stream() - .filter(p -> p.getName().equals(key)) - .findFirst().orElseThrow(IllegalArgumentException::new); - - Optional value = property.parseValue(this.properties.get(key)).toJavaUtil(); - if (value.isPresent()) { - this.blockState = this.blockState.withProperty( - BlockOptionalMeta.castToIProperty(property), - BlockOptionalMeta.castToIPropertyValue(property, value) - ); - } else { - throw new IllegalArgumentException(); + IProperty property = block.getBlockState().getProperty(key); + if (property == null) { + throw new IllegalArgumentException("Invalid property"); } + + this.blockState = setPropertyValue(this.blockState, property, this.properties.get(key)); }); } return this.blockState; @@ -203,5 +185,14 @@ public enum SpongeParser implements ISchematicParser { return null; } } + + private static > IBlockState setPropertyValue(IBlockState state, IProperty property, String value) { + Optional parsed = property.parseValue(value).toJavaUtil(); + if (parsed.isPresent()) { + return state.withProperty(property, parsed.get()); + } else { + throw new IllegalArgumentException("Invalid value for property " + property); + } + } } } diff --git a/src/main/java/baritone/utils/type/VarInt.java b/src/main/java/baritone/utils/type/VarInt.java new file mode 100644 index 00000000..8eb31e7f --- /dev/null +++ b/src/main/java/baritone/utils/type/VarInt.java @@ -0,0 +1,94 @@ +/* + * 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.utils.type; + +import it.unimi.dsi.fastutil.bytes.ByteArrayList; +import it.unimi.dsi.fastutil.bytes.ByteList; + +/** + * @author Brady + * @since 12/19/2019 + */ +public final class VarInt { + + private final int value; + private final byte[] serialized; + private final int size; + + public VarInt(int value) { + this.value = value; + this.serialized = serialize0(this.value); + this.size = this.serialized.length; + } + + /** + * @return The integer value that is represented by this {@link VarInt}. + */ + public final int getValue() { + return this.value; + } + + /** + * @return The size of this {@link VarInt}, in bytes, once serialized. + */ + public final int getSize() { + return this.size; + } + + public final byte[] serialize() { + return this.serialized; + } + + private static byte[] serialize0(int value) { + ByteList bytes = new ByteArrayList(); + + while ((value & 0xFF) != 0) { + bytes.add((byte) (value & 0x7F | 0x80)); + value >>>= 7; + } + bytes.add((byte) (value & 0xFF)); + + return bytes.toByteArray(); + } + + public static VarInt read(byte[] bytes) { + return read(bytes, 0); + } + + public static VarInt read(byte[] bytes, int start) { + int value = 0; + int size = 0; + int index = start; + + while (true) { + byte b = bytes[index++]; + value |= (b & 0x7F) << size++ * 7; + + if (size > 5) { + throw new IllegalArgumentException("VarInt size cannot exceed 5 bytes"); + } + + // Most significant bit denotes another byte is to be read. + if ((b & 0x80) != 0x80) { + break; + } + } + + return new VarInt(value); + } +} From 6759917a2fbab523edd4532ebbd1f575ffcac24b Mon Sep 17 00:00:00 2001 From: Brady Date: Thu, 19 Dec 2019 11:58:47 -0600 Subject: [PATCH 05/14] Additional clean up --- .../baritone/api/schematic/FillSchematic.java | 3 ++ .../utils/schematic/FillSchematic.java | 26 ++------------ .../utils/schematic/MapArtSchematic.java | 34 +++---------------- 3 files changed, 11 insertions(+), 52 deletions(-) diff --git a/src/api/java/baritone/api/schematic/FillSchematic.java b/src/api/java/baritone/api/schematic/FillSchematic.java index aaaeb5dd..fbf16fb4 100644 --- a/src/api/java/baritone/api/schematic/FillSchematic.java +++ b/src/api/java/baritone/api/schematic/FillSchematic.java @@ -38,6 +38,9 @@ public class FillSchematic extends AbstractSchematic { @Override public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { + // TODO: is this even necessary??? + // Builder will already handle logic that requires breaking blocks before replacing them, and non-api Fill Schematic + // is used for clear area and doesn't have any issues. if (bom.matches(current)) { return current; } else if (current.getBlock() != Blocks.AIR) { diff --git a/src/main/java/baritone/utils/schematic/FillSchematic.java b/src/main/java/baritone/utils/schematic/FillSchematic.java index 2e67b121..67e5c734 100644 --- a/src/main/java/baritone/utils/schematic/FillSchematic.java +++ b/src/main/java/baritone/utils/schematic/FillSchematic.java @@ -17,22 +17,17 @@ package baritone.utils.schematic; -import baritone.api.schematic.ISchematic; +import baritone.api.schematic.AbstractSchematic; import net.minecraft.block.state.IBlockState; import java.util.List; -public class FillSchematic implements ISchematic { +public class FillSchematic extends AbstractSchematic { - private final int widthX; - private final int heightY; - private final int lengthZ; private final IBlockState state; public FillSchematic(int widthX, int heightY, int lengthZ, IBlockState state) { - this.widthX = widthX; - this.heightY = heightY; - this.lengthZ = lengthZ; + super(widthX, heightY, lengthZ); this.state = state; } @@ -40,19 +35,4 @@ public class FillSchematic implements ISchematic { public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { return state; } - - @Override - public int widthX() { - return widthX; - } - - @Override - public int heightY() { - return heightY; - } - - @Override - public int lengthZ() { - return lengthZ; - } } diff --git a/src/main/java/baritone/utils/schematic/MapArtSchematic.java b/src/main/java/baritone/utils/schematic/MapArtSchematic.java index ec477b57..a6bd2021 100644 --- a/src/main/java/baritone/utils/schematic/MapArtSchematic.java +++ b/src/main/java/baritone/utils/schematic/MapArtSchematic.java @@ -17,23 +17,20 @@ package baritone.utils.schematic; -import baritone.api.schematic.AbstractSchematic; import baritone.api.schematic.ISchematic; +import baritone.api.schematic.MaskSchematic; import net.minecraft.block.BlockAir; import net.minecraft.block.state.IBlockState; -import java.util.List; import java.util.OptionalInt; import java.util.function.Predicate; -public class MapArtSchematic extends AbstractSchematic { +public class MapArtSchematic extends MaskSchematic { - private final ISchematic child; private final int[][] heightMap; public MapArtSchematic(ISchematic schematic) { - super(schematic.widthX(), schematic.heightY(), schematic.lengthZ()); - this.child = schematic; + super(schematic); heightMap = new int[schematic.widthX()][schematic.lengthZ()]; @@ -63,28 +60,7 @@ public class MapArtSchematic extends AbstractSchematic { } @Override - public boolean inSchematic(int x, int y, int z, IBlockState currentState) { - // in map art, we only care about coordinates in or above the art - return this.child.inSchematic(x, y, z, currentState) && y >= heightMap[x][z]; - } - - @Override - public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { - return this.child.desiredState(x, y, z, current, approxPlaceable); - } - - @Override - public int widthX() { - return this.child.widthX(); - } - - @Override - public int heightY() { - return this.child.heightY(); - } - - @Override - public int lengthZ() { - return this.child.lengthZ(); + protected boolean partOfMask(int x, int y, int z, IBlockState currentState) { + return y >= heightMap[x][z]; } } From eea5b69b6cd8090afdb736d858a6dd16d8ecc28b Mon Sep 17 00:00:00 2001 From: Brady Date: Thu, 19 Dec 2019 12:03:02 -0600 Subject: [PATCH 06/14] Utilize new FillSchematic --- .../baritone/api/schematic/FillSchematic.java | 7 ++-- .../java/baritone/process/BuilderProcess.java | 2 +- .../utils/schematic/FillSchematic.java | 38 ------------------- 3 files changed, 5 insertions(+), 42 deletions(-) delete mode 100644 src/main/java/baritone/utils/schematic/FillSchematic.java diff --git a/src/api/java/baritone/api/schematic/FillSchematic.java b/src/api/java/baritone/api/schematic/FillSchematic.java index fbf16fb4..de9ccf97 100644 --- a/src/api/java/baritone/api/schematic/FillSchematic.java +++ b/src/api/java/baritone/api/schematic/FillSchematic.java @@ -32,15 +32,16 @@ public class FillSchematic extends AbstractSchematic { this.bom = bom; } + public FillSchematic(int x, int y, int z, IBlockState state) { + this(x, y, z, new BlockOptionalMeta(state.getBlock(), state.getBlock().getMetaFromState(state))); + } + public BlockOptionalMeta getBom() { return bom; } @Override public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { - // TODO: is this even necessary??? - // Builder will already handle logic that requires breaking blocks before replacing them, and non-api Fill Schematic - // is used for clear area and doesn't have any issues. if (bom.matches(current)) { return current; } else if (current.getBlock() != Blocks.AIR) { diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 1dfd6c82..88338a01 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -25,6 +25,7 @@ import baritone.api.pathing.goals.GoalGetToBlock; import baritone.api.process.IBuilderProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; +import baritone.api.schematic.FillSchematic; import baritone.api.schematic.ISchematic; import baritone.api.utils.BetterBlockPos; import baritone.api.utils.RayTraceUtils; @@ -37,7 +38,6 @@ import baritone.pathing.movement.MovementHelper; import baritone.utils.BaritoneProcessHelper; import baritone.utils.BlockStateInterface; import baritone.utils.PathingCommandContext; -import baritone.utils.schematic.FillSchematic; import baritone.utils.schematic.MapArtSchematic; import baritone.utils.schematic.format.SchematicFormat; import baritone.utils.schematic.schematica.SchematicaHelper; diff --git a/src/main/java/baritone/utils/schematic/FillSchematic.java b/src/main/java/baritone/utils/schematic/FillSchematic.java deleted file mode 100644 index 67e5c734..00000000 --- a/src/main/java/baritone/utils/schematic/FillSchematic.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.utils.schematic; - -import baritone.api.schematic.AbstractSchematic; -import net.minecraft.block.state.IBlockState; - -import java.util.List; - -public class FillSchematic extends AbstractSchematic { - - private final IBlockState state; - - public FillSchematic(int widthX, int heightY, int lengthZ, IBlockState state) { - super(widthX, heightY, lengthZ); - this.state = state; - } - - @Override - public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { - return state; - } -} From 0a858c040c981337ae1fd82eeda6befe62622c24 Mon Sep 17 00:00:00 2001 From: Brady Date: Thu, 19 Dec 2019 22:15:14 -0600 Subject: [PATCH 07/14] Working --- .../java/baritone/utils/schematic/parse/SpongeParser.java | 8 +++----- src/main/java/baritone/utils/type/VarInt.java | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java index 6219f148..190c6d48 100644 --- a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java +++ b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java @@ -100,7 +100,7 @@ public enum SpongeParser implements ISchematicParser { int[] blockData = new int[this.x * this.y * this.z]; int offset = 0; for (int i = 0; i < blockData.length; i++) { - if (offset >= blockData.length) { + if (offset >= rawBlockData.length) { throw new IllegalArgumentException("No remaining bytes in BlockData for complete schematic"); } @@ -150,11 +150,9 @@ public enum SpongeParser implements ISchematicParser { this.properties.keySet().stream().sorted(String::compareTo).forEachOrdered(key -> { IProperty property = block.getBlockState().getProperty(key); - if (property == null) { - throw new IllegalArgumentException("Invalid property"); + if (property != null) { + this.blockState = setPropertyValue(this.blockState, property, this.properties.get(key)); } - - this.blockState = setPropertyValue(this.blockState, property, this.properties.get(key)); }); } return this.blockState; diff --git a/src/main/java/baritone/utils/type/VarInt.java b/src/main/java/baritone/utils/type/VarInt.java index 8eb31e7f..45f83dda 100644 --- a/src/main/java/baritone/utils/type/VarInt.java +++ b/src/main/java/baritone/utils/type/VarInt.java @@ -57,7 +57,7 @@ public final class VarInt { private static byte[] serialize0(int value) { ByteList bytes = new ByteArrayList(); - while ((value & 0xFF) != 0) { + while ((value & 0x80) != 0) { bytes.add((byte) (value & 0x7F | 0x80)); value >>>= 7; } From 77bdf6e444d338d993f80efeae6e9a0e3cd3a3fb Mon Sep 17 00:00:00 2001 From: Brady Date: Mon, 23 Dec 2019 18:05:50 -0600 Subject: [PATCH 08/14] Fix MapSchematic --- .../java/baritone/process/BuilderProcess.java | 3 +- .../utils/schematic/MapArtSchematic.java | 34 +------ .../utils/schematic/StaticSchematic.java | 88 +++++++++++++++++++ .../schematic/parse/ISchematicParser.java | 4 +- .../utils/schematic/parse/MCEditParser.java | 15 +--- .../utils/schematic/parse/SpongeParser.java | 19 +--- 6 files changed, 101 insertions(+), 62 deletions(-) create mode 100644 src/main/java/baritone/utils/schematic/StaticSchematic.java diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 88338a01..a7a17160 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -39,6 +39,7 @@ import baritone.utils.BaritoneProcessHelper; import baritone.utils.BlockStateInterface; import baritone.utils.PathingCommandContext; import baritone.utils.schematic.MapArtSchematic; +import baritone.utils.schematic.StaticSchematic; import baritone.utils.schematic.format.SchematicFormat; import baritone.utils.schematic.schematica.SchematicaHelper; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; @@ -129,7 +130,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil } if (Baritone.settings().mapArtMode.value) { - parsed = new MapArtSchematic(parsed); + parsed = new MapArtSchematic((StaticSchematic) parsed); } build(name, parsed, origin); diff --git a/src/main/java/baritone/utils/schematic/MapArtSchematic.java b/src/main/java/baritone/utils/schematic/MapArtSchematic.java index a6bd2021..dc2edf2c 100644 --- a/src/main/java/baritone/utils/schematic/MapArtSchematic.java +++ b/src/main/java/baritone/utils/schematic/MapArtSchematic.java @@ -17,46 +17,16 @@ package baritone.utils.schematic; -import baritone.api.schematic.ISchematic; import baritone.api.schematic.MaskSchematic; -import net.minecraft.block.BlockAir; import net.minecraft.block.state.IBlockState; -import java.util.OptionalInt; -import java.util.function.Predicate; - public class MapArtSchematic extends MaskSchematic { private final int[][] heightMap; - public MapArtSchematic(ISchematic schematic) { + public MapArtSchematic(StaticSchematic schematic) { super(schematic); - - heightMap = new int[schematic.widthX()][schematic.lengthZ()]; - - for (int x = 0; x < schematic.widthX(); x++) { - for (int z = 0; z < schematic.lengthZ(); z++) { - IBlockState[] column = /*states[x][z]*/null; - - OptionalInt lowestBlockY = lastIndexMatching(column, state -> !(state.getBlock() instanceof BlockAir)); - if (lowestBlockY.isPresent()) { - heightMap[x][z] = lowestBlockY.getAsInt(); - } else { - System.out.println("Column " + x + "," + z + " has no blocks, but it's apparently map art? wtf"); - System.out.println("Letting it be whatever"); - heightMap[x][z] = 256; - } - } - } - } - - private static OptionalInt lastIndexMatching(T[] arr, Predicate predicate) { - for (int y = arr.length - 1; y >= 0; y--) { - if (predicate.test(arr[y])) { - return OptionalInt.of(y); - } - } - return OptionalInt.empty(); + this.heightMap = schematic.getHeightMap(); } @Override diff --git a/src/main/java/baritone/utils/schematic/StaticSchematic.java b/src/main/java/baritone/utils/schematic/StaticSchematic.java new file mode 100644 index 00000000..97fc91cd --- /dev/null +++ b/src/main/java/baritone/utils/schematic/StaticSchematic.java @@ -0,0 +1,88 @@ +/* + * 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.utils.schematic; + +import baritone.api.schematic.AbstractSchematic; +import net.minecraft.block.BlockAir; +import net.minecraft.block.state.IBlockState; + +import java.util.List; +import java.util.OptionalInt; +import java.util.function.Predicate; + +/** + * @author Brady + * @since 12/23/2019 + */ +public abstract class StaticSchematic extends AbstractSchematic { + + /** + * Block states for this schematic stored in [x, z, y] indexing order + */ + protected IBlockState[][][] states; + + /** + * The maximum height of a given block in this schematic, indexed as [x, z]. + * This is lazily initialized by {@link #getHeightMap()}. + */ + protected int[][] heightMap; + + public StaticSchematic() { + super(); + } + + public StaticSchematic(int x, int y, int z) { + super(x, y, z); + } + + @Override + public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { + return this.states[x][z][y]; + } + + public final int[][] getHeightMap() { + if (this.heightMap == null) { + this.heightMap = new int[this.x][this.z]; + + for (int x = 0; x < this.x; x++) { + for (int z = 0; z < this.z; z++) { + IBlockState[] column = states[x][z]; + + OptionalInt lowestBlockY = lastIndexMatching(column, state -> !(state.getBlock() instanceof BlockAir)); + if (lowestBlockY.isPresent()) { + this.heightMap[x][z] = lowestBlockY.getAsInt(); + } else { + System.out.println("Column " + x + "," + z + " has no blocks, but it's apparently map art? wtf"); + System.out.println("Letting it be whatever"); + this.heightMap[x][z] = 256; + } + } + } + } + return this.heightMap; + } + + private static OptionalInt lastIndexMatching(T[] arr, Predicate predicate) { + for (int y = arr.length - 1; y >= 0; y--) { + if (predicate.test(arr[y])) { + return OptionalInt.of(y); + } + } + return OptionalInt.empty(); + } +} diff --git a/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java b/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java index 040addc1..8bc716f1 100644 --- a/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java +++ b/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java @@ -17,7 +17,7 @@ package baritone.utils.schematic.parse; -import baritone.api.schematic.ISchematic; +import baritone.utils.schematic.StaticSchematic; import java.io.IOException; import java.io.InputStream; @@ -28,5 +28,5 @@ import java.io.InputStream; */ public interface ISchematicParser { - ISchematic parse(InputStream input) throws IOException; + StaticSchematic parse(InputStream input) throws IOException; } diff --git a/src/main/java/baritone/utils/schematic/parse/MCEditParser.java b/src/main/java/baritone/utils/schematic/parse/MCEditParser.java index dce2c856..54d78201 100644 --- a/src/main/java/baritone/utils/schematic/parse/MCEditParser.java +++ b/src/main/java/baritone/utils/schematic/parse/MCEditParser.java @@ -17,8 +17,7 @@ package baritone.utils.schematic.parse; -import baritone.api.schematic.AbstractSchematic; -import baritone.api.schematic.ISchematic; +import baritone.utils.schematic.StaticSchematic; import baritone.utils.schematic.format.SchematicFormat; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -27,7 +26,6 @@ import net.minecraft.nbt.NBTTagCompound; import java.io.IOException; import java.io.InputStream; -import java.util.List; /** * An implementation of {@link ISchematicParser} for {@link SchematicFormat#MCEDIT} @@ -39,13 +37,11 @@ public enum MCEditParser implements ISchematicParser { INSTANCE; @Override - public ISchematic parse(InputStream input) throws IOException { + public StaticSchematic parse(InputStream input) throws IOException { return new MCEditSchematic(CompressedStreamTools.readCompressed(input)); } - private static final class MCEditSchematic extends AbstractSchematic { - - private final IBlockState[][][] states; + private static final class MCEditSchematic extends StaticSchematic { MCEditSchematic(NBTTagCompound schematic) { String type = schematic.getString("Materials"); @@ -85,10 +81,5 @@ public enum MCEditParser implements ISchematicParser { } } } - - @Override - public final IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { - return this.states[x][z][y]; - } } } diff --git a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java index 190c6d48..48cc60aa 100644 --- a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java +++ b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java @@ -17,8 +17,7 @@ package baritone.utils.schematic.parse; -import baritone.api.schematic.AbstractSchematic; -import baritone.api.schematic.ISchematic; +import baritone.utils.schematic.StaticSchematic; import baritone.utils.schematic.format.SchematicFormat; import baritone.utils.type.VarInt; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; @@ -32,7 +31,6 @@ import net.minecraft.util.ResourceLocation; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; @@ -48,7 +46,7 @@ public enum SpongeParser implements ISchematicParser { INSTANCE; @Override - public ISchematic parse(InputStream input) throws IOException { + public StaticSchematic parse(InputStream input) throws IOException { NBTTagCompound nbt = CompressedStreamTools.readCompressed(input); int version = nbt.getInteger("Version"); switch (version) { @@ -56,7 +54,7 @@ public enum SpongeParser implements ISchematicParser { case 2: return new SpongeSchematic(nbt); default: - throw new UnsupportedOperationException("Unsupported Version of the a Sponge Schematic"); + throw new UnsupportedOperationException("Unsupported Version of a Sponge Schematic"); } } @@ -64,12 +62,8 @@ public enum SpongeParser implements ISchematicParser { * Implementation of the Sponge Schematic Format supporting both V1 and V2. (For the current * use case, there is no difference between reading a V1 and V2 schematic). */ - private static final class SpongeSchematic extends AbstractSchematic { + private static final class SpongeSchematic extends StaticSchematic { - /** - * Block states for this schematic stored in [x, z, y] indexing order - */ - private IBlockState[][][] states; SpongeSchematic(NBTTagCompound nbt) { this.x = nbt.getInteger("Width"); @@ -123,11 +117,6 @@ public enum SpongeParser implements ISchematicParser { } } } - - @Override - public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { - return this.states[x][z][y]; - } } private static final class SerializedBlockState { From eee705b371d27bf7f797ffa3d578c797cf046395 Mon Sep 17 00:00:00 2001 From: Brady Date: Tue, 24 Dec 2019 17:20:00 -0600 Subject: [PATCH 09/14] Schematic Format API support --- .../java/baritone/api/IBaritoneProvider.java | 6 ++ .../api/schematic/ISchematicSystem.java | 44 ++++++++++++++ .../api/schematic/IStaticSchematic.java | 60 +++++++++++++++++++ .../schematic/format/ISchematicFormat.java | 43 +++++++++++++ .../schematic/parse/ISchematicParser.java | 6 +- src/main/java/baritone/BaritoneProvider.java | 7 +++ .../java/baritone/process/BuilderProcess.java | 9 +-- .../utils/schematic/MapArtSchematic.java | 40 ++++++++++++- .../utils/schematic/SchematicSystem.java | 51 ++++++++++++++++ .../utils/schematic/StaticSchematic.java | 58 ++++-------------- ...rmat.java => DefaultSchematicFormats.java} | 25 ++++---- .../utils/schematic/parse/MCEditParser.java | 5 +- .../utils/schematic/parse/SpongeParser.java | 5 +- 13 files changed, 282 insertions(+), 77 deletions(-) create mode 100644 src/api/java/baritone/api/schematic/ISchematicSystem.java create mode 100644 src/api/java/baritone/api/schematic/IStaticSchematic.java create mode 100644 src/api/java/baritone/api/schematic/format/ISchematicFormat.java rename src/{main/java/baritone/utils => api/java/baritone/api}/schematic/parse/ISchematicParser.java (84%) create mode 100644 src/main/java/baritone/utils/schematic/SchematicSystem.java rename src/main/java/baritone/utils/schematic/format/{SchematicFormat.java => DefaultSchematicFormats.java} (68%) diff --git a/src/api/java/baritone/api/IBaritoneProvider.java b/src/api/java/baritone/api/IBaritoneProvider.java index b7228e33..84a8abbb 100644 --- a/src/api/java/baritone/api/IBaritoneProvider.java +++ b/src/api/java/baritone/api/IBaritoneProvider.java @@ -20,6 +20,7 @@ package baritone.api; import baritone.api.cache.IWorldScanner; import baritone.api.command.ICommand; import baritone.api.command.ICommandSystem; +import baritone.api.schematic.ISchematicSystem; import net.minecraft.client.entity.EntityPlayerSP; import java.util.List; @@ -82,4 +83,9 @@ public interface IBaritoneProvider { * @return The {@link ICommandSystem} instance. */ ICommandSystem getCommandSystem(); + + /** + * @return The {@link ISchematicSystem} instance. + */ + ISchematicSystem getSchematicSystem(); } diff --git a/src/api/java/baritone/api/schematic/ISchematicSystem.java b/src/api/java/baritone/api/schematic/ISchematicSystem.java new file mode 100644 index 00000000..c8f03907 --- /dev/null +++ b/src/api/java/baritone/api/schematic/ISchematicSystem.java @@ -0,0 +1,44 @@ +/* + * 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 baritone.api.command.registry.Registry; +import baritone.api.schematic.format.ISchematicFormat; + +import java.io.File; +import java.util.Optional; + +/** + * @author Brady + * @since 12/23/2019 + */ +public interface ISchematicSystem { + + /** + * @return The registry of supported schematic formats + */ + Registry getRegistry(); + + /** + * Attempts to find an {@link ISchematicFormat} that supports the specified schematic file. + * + * @param file A schematic file + * @return The corresponding format for the file, {@link Optional#empty()} if no candidates were found. + */ + Optional getByFile(File file); +} diff --git a/src/api/java/baritone/api/schematic/IStaticSchematic.java b/src/api/java/baritone/api/schematic/IStaticSchematic.java new file mode 100644 index 00000000..268b1b1f --- /dev/null +++ b/src/api/java/baritone/api/schematic/IStaticSchematic.java @@ -0,0 +1,60 @@ +/* + * 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.block.state.IBlockState; + +/** + * A static schematic is capable of providing the desired state at a given position without + * additional context. Schematics of this type are expected to have non-varying contents. + * + * @see #getDirect(int, int, int) + * + * @author Brady + * @since 12/24/2019 + */ +public interface IStaticSchematic extends ISchematic { + + /** + * Gets the {@link IBlockState} for a given position in this schematic. It should be guaranteed + * that the return value of this method will not change given that the parameters are the same. + * + * @param x The X block position + * @param y The Y block position + * @param z The Z block position + * @return The desired state at the specified position. + */ + IBlockState getDirect(int x, int y, int z); + + /** + * Returns an {@link IBlockState} array of size {@link #heightY()} which contains all + * desired block states in the specified vertical column. The index of {@link IBlockState}s + * in the array are equivalent to their Y position in the schematic. + * + * @param x The X column position + * @param z The Z column position + * @return An {@link IBlockState} array + */ + default IBlockState[] getColumn(int x, int z) { + IBlockState[] column = new IBlockState[this.heightY()]; + for (int i = 0; i < this.heightY(); i++) { + column[i] = getDirect(x, i, z); + } + return column; + } +} diff --git a/src/api/java/baritone/api/schematic/format/ISchematicFormat.java b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java new file mode 100644 index 00000000..260ab453 --- /dev/null +++ b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java @@ -0,0 +1,43 @@ +/* + * 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.format; + +import baritone.api.schematic.ISchematic; +import baritone.api.schematic.parse.ISchematicParser; + +import java.io.File; + +/** + * The base of a {@link ISchematic} file format + * + * @author Brady + * @since 12/23/2019 + */ +public interface ISchematicFormat { + + /** + * @return The parser for creating schematics of this format + */ + ISchematicParser getParser(); + + /** + * @param file The file to check against + * @return Whether or not the specified file matches this schematic format + */ + boolean isFileType(File file); +} diff --git a/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java b/src/api/java/baritone/api/schematic/parse/ISchematicParser.java similarity index 84% rename from src/main/java/baritone/utils/schematic/parse/ISchematicParser.java rename to src/api/java/baritone/api/schematic/parse/ISchematicParser.java index 8bc716f1..ab0f12f4 100644 --- a/src/main/java/baritone/utils/schematic/parse/ISchematicParser.java +++ b/src/api/java/baritone/api/schematic/parse/ISchematicParser.java @@ -15,9 +15,9 @@ * along with Baritone. If not, see . */ -package baritone.utils.schematic.parse; +package baritone.api.schematic.parse; -import baritone.utils.schematic.StaticSchematic; +import baritone.api.schematic.IStaticSchematic; import java.io.IOException; import java.io.InputStream; @@ -28,5 +28,5 @@ import java.io.InputStream; */ public interface ISchematicParser { - StaticSchematic parse(InputStream input) throws IOException; + IStaticSchematic parse(InputStream input) throws IOException; } diff --git a/src/main/java/baritone/BaritoneProvider.java b/src/main/java/baritone/BaritoneProvider.java index cb24dfe2..84034ef3 100644 --- a/src/main/java/baritone/BaritoneProvider.java +++ b/src/main/java/baritone/BaritoneProvider.java @@ -21,9 +21,11 @@ import baritone.api.IBaritone; import baritone.api.IBaritoneProvider; import baritone.api.cache.IWorldScanner; import baritone.api.command.ICommandSystem; +import baritone.api.schematic.ISchematicSystem; import baritone.command.BaritoneChatControl; import baritone.cache.WorldScanner; import baritone.command.CommandSystem; +import baritone.utils.schematic.SchematicSystem; import java.util.Collections; import java.util.List; @@ -64,4 +66,9 @@ public final class BaritoneProvider implements IBaritoneProvider { public ICommandSystem getCommandSystem() { return CommandSystem.INSTANCE; } + + @Override + public ISchematicSystem getSchematicSystem() { + return SchematicSystem.INSTANCE; + } } diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index a7a17160..55361602 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -27,6 +27,8 @@ import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; import baritone.api.schematic.FillSchematic; import baritone.api.schematic.ISchematic; +import baritone.api.schematic.IStaticSchematic; +import baritone.api.schematic.format.ISchematicFormat; import baritone.api.utils.BetterBlockPos; import baritone.api.utils.RayTraceUtils; import baritone.api.utils.Rotation; @@ -39,8 +41,7 @@ import baritone.utils.BaritoneProcessHelper; import baritone.utils.BlockStateInterface; import baritone.utils.PathingCommandContext; import baritone.utils.schematic.MapArtSchematic; -import baritone.utils.schematic.StaticSchematic; -import baritone.utils.schematic.format.SchematicFormat; +import baritone.utils.schematic.SchematicSystem; import baritone.utils.schematic.schematica.SchematicaHelper; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.block.BlockAir; @@ -116,7 +117,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil @Override public boolean build(String name, File schematic, Vec3i origin) { - Optional format = SchematicFormat.getByFile(schematic); + Optional format = SchematicSystem.INSTANCE.getByFile(schematic); if (!format.isPresent()) { return false; } @@ -130,7 +131,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil } if (Baritone.settings().mapArtMode.value) { - parsed = new MapArtSchematic((StaticSchematic) parsed); + parsed = new MapArtSchematic((IStaticSchematic) parsed); } build(name, parsed, origin); diff --git a/src/main/java/baritone/utils/schematic/MapArtSchematic.java b/src/main/java/baritone/utils/schematic/MapArtSchematic.java index dc2edf2c..31442261 100644 --- a/src/main/java/baritone/utils/schematic/MapArtSchematic.java +++ b/src/main/java/baritone/utils/schematic/MapArtSchematic.java @@ -17,20 +17,54 @@ package baritone.utils.schematic; +import baritone.api.schematic.IStaticSchematic; import baritone.api.schematic.MaskSchematic; +import net.minecraft.block.BlockAir; import net.minecraft.block.state.IBlockState; +import java.util.OptionalInt; +import java.util.function.Predicate; + public class MapArtSchematic extends MaskSchematic { private final int[][] heightMap; - public MapArtSchematic(StaticSchematic schematic) { + public MapArtSchematic(IStaticSchematic schematic) { super(schematic); - this.heightMap = schematic.getHeightMap(); + this.heightMap = generateHeightMap(schematic); } @Override protected boolean partOfMask(int x, int y, int z, IBlockState currentState) { - return y >= heightMap[x][z]; + return y >= this.heightMap[x][z]; + } + + private static int[][] generateHeightMap(IStaticSchematic schematic) { + int[][] heightMap = new int[schematic.widthX()][schematic.lengthZ()]; + + for (int x = 0; x < schematic.widthX(); x++) { + for (int z = 0; z < schematic.lengthZ(); z++) { + IBlockState[] column = schematic.getColumn(x, z); + + OptionalInt lowestBlockY = lastIndexMatching(column, state -> !(state.getBlock() instanceof BlockAir)); + if (lowestBlockY.isPresent()) { + heightMap[x][z] = lowestBlockY.getAsInt(); + } else { + System.out.println("Column " + x + "," + z + " has no blocks, but it's apparently map art? wtf"); + System.out.println("Letting it be whatever"); + heightMap[x][z] = 256; + } + } + } + return heightMap; + } + + private static OptionalInt lastIndexMatching(T[] arr, Predicate predicate) { + for (int y = arr.length - 1; y >= 0; y--) { + if (predicate.test(arr[y])) { + return OptionalInt.of(y); + } + } + return OptionalInt.empty(); } } diff --git a/src/main/java/baritone/utils/schematic/SchematicSystem.java b/src/main/java/baritone/utils/schematic/SchematicSystem.java new file mode 100644 index 00000000..8afafa8c --- /dev/null +++ b/src/main/java/baritone/utils/schematic/SchematicSystem.java @@ -0,0 +1,51 @@ +/* + * 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.utils.schematic; + +import baritone.api.command.registry.Registry; +import baritone.api.schematic.ISchematicSystem; +import baritone.api.schematic.format.ISchematicFormat; +import baritone.utils.schematic.format.DefaultSchematicFormats; + +import java.io.File; +import java.util.Arrays; +import java.util.Optional; + +/** + * @author Brady + * @since 12/24/2019 + */ +public enum SchematicSystem implements ISchematicSystem { + INSTANCE; + + private final Registry registry = new Registry<>(); + + SchematicSystem() { + Arrays.stream(DefaultSchematicFormats.values()).forEach(this.registry::register); + } + + @Override + public Registry getRegistry() { + return this.registry; + } + + @Override + public Optional getByFile(File file) { + return this.registry.stream().filter(format -> format.isFileType(file)).findFirst(); + } +} diff --git a/src/main/java/baritone/utils/schematic/StaticSchematic.java b/src/main/java/baritone/utils/schematic/StaticSchematic.java index 97fc91cd..2251450a 100644 --- a/src/main/java/baritone/utils/schematic/StaticSchematic.java +++ b/src/main/java/baritone/utils/schematic/StaticSchematic.java @@ -18,71 +18,33 @@ package baritone.utils.schematic; import baritone.api.schematic.AbstractSchematic; -import net.minecraft.block.BlockAir; +import baritone.api.schematic.IStaticSchematic; import net.minecraft.block.state.IBlockState; import java.util.List; -import java.util.OptionalInt; -import java.util.function.Predicate; /** + * Default implementation of {@link IStaticSchematic} + * * @author Brady * @since 12/23/2019 */ -public abstract class StaticSchematic extends AbstractSchematic { +public class StaticSchematic extends AbstractSchematic implements IStaticSchematic { - /** - * Block states for this schematic stored in [x, z, y] indexing order - */ protected IBlockState[][][] states; - /** - * The maximum height of a given block in this schematic, indexed as [x, z]. - * This is lazily initialized by {@link #getHeightMap()}. - */ - protected int[][] heightMap; - - public StaticSchematic() { - super(); - } - - public StaticSchematic(int x, int y, int z) { - super(x, y, z); - } - @Override public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { return this.states[x][z][y]; } - public final int[][] getHeightMap() { - if (this.heightMap == null) { - this.heightMap = new int[this.x][this.z]; - - for (int x = 0; x < this.x; x++) { - for (int z = 0; z < this.z; z++) { - IBlockState[] column = states[x][z]; - - OptionalInt lowestBlockY = lastIndexMatching(column, state -> !(state.getBlock() instanceof BlockAir)); - if (lowestBlockY.isPresent()) { - this.heightMap[x][z] = lowestBlockY.getAsInt(); - } else { - System.out.println("Column " + x + "," + z + " has no blocks, but it's apparently map art? wtf"); - System.out.println("Letting it be whatever"); - this.heightMap[x][z] = 256; - } - } - } - } - return this.heightMap; + @Override + public IBlockState getDirect(int x, int y, int z) { + return this.states[x][z][y]; } - private static OptionalInt lastIndexMatching(T[] arr, Predicate predicate) { - for (int y = arr.length - 1; y >= 0; y--) { - if (predicate.test(arr[y])) { - return OptionalInt.of(y); - } - } - return OptionalInt.empty(); + @Override + public IBlockState[] getColumn(int x, int z) { + return this.states[x][z]; } } diff --git a/src/main/java/baritone/utils/schematic/format/SchematicFormat.java b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java similarity index 68% rename from src/main/java/baritone/utils/schematic/format/SchematicFormat.java rename to src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java index 6c84273e..494d6ec8 100644 --- a/src/main/java/baritone/utils/schematic/format/SchematicFormat.java +++ b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java @@ -17,20 +17,21 @@ package baritone.utils.schematic.format; -import baritone.utils.schematic.parse.ISchematicParser; +import baritone.api.schematic.format.ISchematicFormat; +import baritone.api.schematic.parse.ISchematicParser; import baritone.utils.schematic.parse.MCEditParser; import baritone.utils.schematic.parse.SpongeParser; import org.apache.commons.io.FilenameUtils; import java.io.File; -import java.util.Optional; -import java.util.stream.Stream; /** + * Default implementations of {@link ISchematicFormat} + * * @author Brady * @since 12/13/2019 */ -public enum SchematicFormat { +public enum DefaultSchematicFormats implements ISchematicFormat { /** * The MCEdit schematic specification. Commonly denoted by the ".schematic" file extension. @@ -47,24 +48,18 @@ public enum SchematicFormat { private final String extension; private final ISchematicParser parser; - SchematicFormat(String extension, ISchematicParser parser) { + DefaultSchematicFormats(String extension, ISchematicParser parser) { this.extension = extension; this.parser = parser; } + @Override public final ISchematicParser getParser() { return this.parser; } - public static Optional getByFile(File schematic) { - // TODO: Better identification - // Maybe peek file contents and make a safe determination? - return getByExtension(FilenameUtils.getExtension(schematic.getAbsolutePath())); - } - - public static Optional getByExtension(String extension) { - return extension == null || extension.isEmpty() - ? Optional.empty() - : Stream.of(values()).filter(format -> format.extension.equalsIgnoreCase(extension)).findFirst(); + @Override + public boolean isFileType(File file) { + return this.extension.equalsIgnoreCase(FilenameUtils.getExtension(file.getAbsolutePath())); } } diff --git a/src/main/java/baritone/utils/schematic/parse/MCEditParser.java b/src/main/java/baritone/utils/schematic/parse/MCEditParser.java index 54d78201..3599b824 100644 --- a/src/main/java/baritone/utils/schematic/parse/MCEditParser.java +++ b/src/main/java/baritone/utils/schematic/parse/MCEditParser.java @@ -17,8 +17,9 @@ package baritone.utils.schematic.parse; +import baritone.api.schematic.parse.ISchematicParser; import baritone.utils.schematic.StaticSchematic; -import baritone.utils.schematic.format.SchematicFormat; +import baritone.utils.schematic.format.DefaultSchematicFormats; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.nbt.CompressedStreamTools; @@ -28,7 +29,7 @@ import java.io.IOException; import java.io.InputStream; /** - * An implementation of {@link ISchematicParser} for {@link SchematicFormat#MCEDIT} + * An implementation of {@link ISchematicParser} for {@link DefaultSchematicFormats#MCEDIT} * * @author Brady * @since 12/16/2019 diff --git a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java index 48cc60aa..255916d1 100644 --- a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java +++ b/src/main/java/baritone/utils/schematic/parse/SpongeParser.java @@ -17,8 +17,9 @@ package baritone.utils.schematic.parse; +import baritone.api.schematic.parse.ISchematicParser; import baritone.utils.schematic.StaticSchematic; -import baritone.utils.schematic.format.SchematicFormat; +import baritone.utils.schematic.format.DefaultSchematicFormats; import baritone.utils.type.VarInt; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import net.minecraft.block.Block; @@ -37,7 +38,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * An implementation of {@link ISchematicParser} for {@link SchematicFormat#SPONGE} + * An implementation of {@link ISchematicParser} for {@link DefaultSchematicFormats#SPONGE} * * @author Brady * @since 12/16/2019 From d712839c259a3be2df801e366140e0ae25ba73f0 Mon Sep 17 00:00:00 2001 From: Brady Date: Wed, 25 Dec 2019 01:35:10 -0600 Subject: [PATCH 10/14] Make Schematica respect mapArtMode setting --- src/main/java/baritone/process/BuilderProcess.java | 9 +++++++-- .../utils/schematic/schematica/SchematicAdapter.java | 11 ++++++++--- .../utils/schematic/schematica/SchematicaHelper.java | 4 ++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 55361602..5cbc3da7 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -141,9 +141,14 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil @Override public void buildOpenSchematic() { if (SchematicaHelper.isSchematicaPresent()) { - Optional> schematic = SchematicaHelper.getOpenSchematic(); + Optional> schematic = SchematicaHelper.getOpenSchematic(); if (schematic.isPresent()) { - this.build(schematic.get().getFirst().toString(), schematic.get().getFirst(), schematic.get().getSecond()); + IStaticSchematic s = schematic.get().getFirst(); + this.build( + schematic.get().getFirst().toString(), + Baritone.settings().mapArtMode.value ? new MapArtSchematic(s) : s, + schematic.get().getSecond() + ); } else { logDirect("No schematic currently open"); } diff --git a/src/main/java/baritone/utils/schematic/schematica/SchematicAdapter.java b/src/main/java/baritone/utils/schematic/schematica/SchematicAdapter.java index cd1e789f..0ae3edab 100644 --- a/src/main/java/baritone/utils/schematic/schematica/SchematicAdapter.java +++ b/src/main/java/baritone/utils/schematic/schematica/SchematicAdapter.java @@ -17,14 +17,14 @@ package baritone.utils.schematic.schematica; -import baritone.api.schematic.ISchematic; +import baritone.api.schematic.IStaticSchematic; import com.github.lunatrius.schematica.client.world.SchematicWorld; import net.minecraft.block.state.IBlockState; import net.minecraft.util.math.BlockPos; import java.util.List; -public final class SchematicAdapter implements ISchematic { +public final class SchematicAdapter implements IStaticSchematic { private final SchematicWorld schematic; @@ -34,7 +34,12 @@ public final class SchematicAdapter implements ISchematic { @Override public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { - return schematic.getSchematic().getBlockState(new BlockPos(x, y, z)); + return this.getDirect(x, y, z); + } + + @Override + public IBlockState getDirect(int x, int y, int z) { + return this.schematic.getSchematic().getBlockState(new BlockPos(x, y, z)); } @Override diff --git a/src/main/java/baritone/utils/schematic/schematica/SchematicaHelper.java b/src/main/java/baritone/utils/schematic/schematica/SchematicaHelper.java index 85b3967f..fab68845 100644 --- a/src/main/java/baritone/utils/schematic/schematica/SchematicaHelper.java +++ b/src/main/java/baritone/utils/schematic/schematica/SchematicaHelper.java @@ -17,7 +17,7 @@ package baritone.utils.schematic.schematica; -import baritone.api.schematic.ISchematic; +import baritone.api.schematic.IStaticSchematic; import com.github.lunatrius.schematica.Schematica; import com.github.lunatrius.schematica.proxy.ClientProxy; import net.minecraft.util.Tuple; @@ -37,7 +37,7 @@ public enum SchematicaHelper { } } - public static Optional> getOpenSchematic() { + public static Optional> getOpenSchematic() { return Optional.ofNullable(ClientProxy.schematic) .map(world -> new Tuple<>(new SchematicAdapter(world), world.position)); } From 812bc0d8c40ebe56cd637280e0d412190d1f4f7d Mon Sep 17 00:00:00 2001 From: Brady Date: Fri, 27 Dec 2019 01:14:31 -0600 Subject: [PATCH 11/14] Remove redundant parser layer --- .../schematic/format/ISchematicFormat.java | 6 +- .../api/schematic/parse/ISchematicParser.java | 32 ----- .../java/baritone/process/BuilderProcess.java | 2 +- .../format/DefaultSchematicFormats.java | 43 +++++-- .../format/defaults/MCEditSchematic.java | 69 ++++++++++ .../defaults/SpongeSchematic.java} | 119 +++++++----------- .../utils/schematic/parse/MCEditParser.java | 86 ------------- 7 files changed, 149 insertions(+), 208 deletions(-) delete mode 100644 src/api/java/baritone/api/schematic/parse/ISchematicParser.java create mode 100644 src/main/java/baritone/utils/schematic/format/defaults/MCEditSchematic.java rename src/main/java/baritone/utils/schematic/{parse/SpongeParser.java => format/defaults/SpongeSchematic.java} (53%) delete mode 100644 src/main/java/baritone/utils/schematic/parse/MCEditParser.java diff --git a/src/api/java/baritone/api/schematic/format/ISchematicFormat.java b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java index 260ab453..3fe045bc 100644 --- a/src/api/java/baritone/api/schematic/format/ISchematicFormat.java +++ b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java @@ -18,9 +18,11 @@ package baritone.api.schematic.format; import baritone.api.schematic.ISchematic; -import baritone.api.schematic.parse.ISchematicParser; +import baritone.api.schematic.IStaticSchematic; import java.io.File; +import java.io.IOException; +import java.io.InputStream; /** * The base of a {@link ISchematic} file format @@ -33,7 +35,7 @@ public interface ISchematicFormat { /** * @return The parser for creating schematics of this format */ - ISchematicParser getParser(); + IStaticSchematic parse(InputStream input) throws IOException; /** * @param file The file to check against diff --git a/src/api/java/baritone/api/schematic/parse/ISchematicParser.java b/src/api/java/baritone/api/schematic/parse/ISchematicParser.java deleted file mode 100644 index ab0f12f4..00000000 --- a/src/api/java/baritone/api/schematic/parse/ISchematicParser.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.parse; - -import baritone.api.schematic.IStaticSchematic; - -import java.io.IOException; -import java.io.InputStream; - -/** - * @author Brady - * @since 12/13/2019 - */ -public interface ISchematicParser { - - IStaticSchematic parse(InputStream input) throws IOException; -} diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 5cbc3da7..4efa2c95 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -124,7 +124,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil ISchematic parsed; try { - parsed = format.get().getParser().parse(new FileInputStream(schematic)); + parsed = format.get().parse(new FileInputStream(schematic)); } catch (Exception e) { e.printStackTrace(); return false; diff --git a/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java index 494d6ec8..942bd72a 100644 --- a/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java +++ b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java @@ -17,13 +17,17 @@ package baritone.utils.schematic.format; +import baritone.api.schematic.IStaticSchematic; import baritone.api.schematic.format.ISchematicFormat; -import baritone.api.schematic.parse.ISchematicParser; -import baritone.utils.schematic.parse.MCEditParser; -import baritone.utils.schematic.parse.SpongeParser; +import baritone.utils.schematic.format.defaults.MCEditSchematic; +import baritone.utils.schematic.format.defaults.SpongeSchematic; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; import org.apache.commons.io.FilenameUtils; import java.io.File; +import java.io.IOException; +import java.io.InputStream; /** * Default implementations of {@link ISchematicFormat} @@ -36,26 +40,39 @@ public enum DefaultSchematicFormats implements ISchematicFormat { /** * The MCEdit schematic specification. Commonly denoted by the ".schematic" file extension. */ - MCEDIT("schematic", MCEditParser.INSTANCE), + MCEDIT("schematic") { + + @Override + public IStaticSchematic parse(InputStream input) throws IOException { + return new MCEditSchematic(CompressedStreamTools.readCompressed(input)); + } + }, /** * The SpongePowered Schematic Specification. Commonly denoted by the ".schem" file extension. * * @see Sponge Schematic Specification */ - SPONGE("schem", SpongeParser.INSTANCE); + SPONGE("schem") { + + @Override + public IStaticSchematic parse(InputStream input) throws IOException { + NBTTagCompound nbt = CompressedStreamTools.readCompressed(input); + int version = nbt.getInteger("Version"); + switch (version) { + case 1: + case 2: + return new SpongeSchematic(nbt); + default: + throw new UnsupportedOperationException("Unsupported Version of a Sponge Schematic"); + } + } + }; private final String extension; - private final ISchematicParser parser; - DefaultSchematicFormats(String extension, ISchematicParser parser) { + DefaultSchematicFormats(String extension) { this.extension = extension; - this.parser = parser; - } - - @Override - public final ISchematicParser getParser() { - return this.parser; } @Override diff --git a/src/main/java/baritone/utils/schematic/format/defaults/MCEditSchematic.java b/src/main/java/baritone/utils/schematic/format/defaults/MCEditSchematic.java new file mode 100644 index 00000000..08e571c9 --- /dev/null +++ b/src/main/java/baritone/utils/schematic/format/defaults/MCEditSchematic.java @@ -0,0 +1,69 @@ +/* + * 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.utils.schematic.format.defaults; + +import baritone.utils.schematic.StaticSchematic; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.nbt.NBTTagCompound; + +/** + * @author Brady + * @since 12/27/2019 + */ +public final class MCEditSchematic extends StaticSchematic { + + public MCEditSchematic(NBTTagCompound schematic) { + String type = schematic.getString("Materials"); + if (!type.equals("Alpha")) { + throw new IllegalStateException("bad schematic " + type); + } + this.x = schematic.getInteger("Width"); + this.y = schematic.getInteger("Height"); + this.z = schematic.getInteger("Length"); + byte[] blocks = schematic.getByteArray("Blocks"); + byte[] metadata = schematic.getByteArray("Data"); + + byte[] additional = null; + if (schematic.hasKey("AddBlocks")) { + byte[] addBlocks = schematic.getByteArray("AddBlocks"); + additional = new byte[addBlocks.length * 2]; + for (int i = 0; i < addBlocks.length; i++) { + additional[i * 2 + 0] = (byte) ((addBlocks[i] >> 4) & 0xF); // lower nibble + additional[i * 2 + 1] = (byte) ((addBlocks[i] >> 0) & 0xF); // upper nibble + } + } + this.states = new IBlockState[this.x][this.z][this.y]; + for (int y = 0; y < this.y; y++) { + for (int z = 0; z < this.z; z++) { + for (int x = 0; x < this.x; x++) { + int blockInd = (y * this.z + z) * this.x + x; + + int blockID = blocks[blockInd] & 0xFF; + if (additional != null) { + // additional is 0 through 15 inclusive since it's & 0xF above + blockID |= additional[blockInd] << 8; + } + Block block = Block.REGISTRY.getObjectById(blockID); + int meta = metadata[blockInd] & 0xFF; + this.states[x][z][y] = block.getStateFromMeta(meta); + } + } + } + } +} diff --git a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java b/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java similarity index 53% rename from src/main/java/baritone/utils/schematic/parse/SpongeParser.java rename to src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java index 255916d1..0d03e5d8 100644 --- a/src/main/java/baritone/utils/schematic/parse/SpongeParser.java +++ b/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java @@ -15,22 +15,17 @@ * along with Baritone. If not, see . */ -package baritone.utils.schematic.parse; +package baritone.utils.schematic.format.defaults; -import baritone.api.schematic.parse.ISchematicParser; import baritone.utils.schematic.StaticSchematic; -import baritone.utils.schematic.format.DefaultSchematicFormats; import baritone.utils.type.VarInt; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import net.minecraft.block.Block; import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; -import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; -import java.io.IOException; -import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -38,83 +33,59 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * An implementation of {@link ISchematicParser} for {@link DefaultSchematicFormats#SPONGE} - * * @author Brady - * @since 12/16/2019 + * @since 12/27/2019 */ -public enum SpongeParser implements ISchematicParser { - INSTANCE; +public final class SpongeSchematic extends StaticSchematic { - @Override - public StaticSchematic parse(InputStream input) throws IOException { - NBTTagCompound nbt = CompressedStreamTools.readCompressed(input); - int version = nbt.getInteger("Version"); - switch (version) { - case 1: - case 2: - return new SpongeSchematic(nbt); - default: - throw new UnsupportedOperationException("Unsupported Version of a Sponge Schematic"); + public SpongeSchematic(NBTTagCompound nbt) { + this.x = nbt.getInteger("Width"); + this.y = nbt.getInteger("Height"); + this.z = nbt.getInteger("Length"); + this.states = new IBlockState[this.x][this.z][this.y]; + + Int2ObjectArrayMap palette = new Int2ObjectArrayMap<>(); + NBTTagCompound paletteTag = nbt.getCompoundTag("Palette"); + for (String tag : paletteTag.getKeySet()) { + int index = paletteTag.getInteger(tag); + + SerializedBlockState serializedState = SerializedBlockState.getFromString(tag); + if (serializedState == null) { + throw new IllegalArgumentException("Unable to parse palette tag"); + } + + IBlockState state = serializedState.deserialize(); + if (state == null) { + throw new IllegalArgumentException("Unable to deserialize palette tag"); + } + + palette.put(index, state); } - } - /** - * Implementation of the Sponge Schematic Format supporting both V1 and V2. (For the current - * use case, there is no difference between reading a V1 and V2 schematic). - */ - private static final class SpongeSchematic extends StaticSchematic { - - - SpongeSchematic(NBTTagCompound nbt) { - this.x = nbt.getInteger("Width"); - this.y = nbt.getInteger("Height"); - this.z = nbt.getInteger("Length"); - this.states = new IBlockState[this.x][this.z][this.y]; - - Int2ObjectArrayMap palette = new Int2ObjectArrayMap<>(); - NBTTagCompound paletteTag = nbt.getCompoundTag("Palette"); - for (String tag : paletteTag.getKeySet()) { - int index = paletteTag.getInteger(tag); - - SerializedBlockState serializedState = SerializedBlockState.getFromString(tag); - if (serializedState == null) { - throw new IllegalArgumentException("Unable to parse palette tag"); - } - - IBlockState state = serializedState.deserialize(); - if (state == null) { - throw new IllegalArgumentException("Unable to deserialize palette tag"); - } - - palette.put(index, state); + // BlockData is stored as an NBT byte[], however, the actual data that is represented is a varint[] + byte[] rawBlockData = nbt.getByteArray("BlockData"); + int[] blockData = new int[this.x * this.y * this.z]; + int offset = 0; + for (int i = 0; i < blockData.length; i++) { + if (offset >= rawBlockData.length) { + throw new IllegalArgumentException("No remaining bytes in BlockData for complete schematic"); } - // BlockData is stored as an NBT byte[], however, the actual data that is represented is a varint[] - byte[] rawBlockData = nbt.getByteArray("BlockData"); - int[] blockData = new int[this.x * this.y * this.z]; - int offset = 0; - for (int i = 0; i < blockData.length; i++) { - if (offset >= rawBlockData.length) { - throw new IllegalArgumentException("No remaining bytes in BlockData for complete schematic"); - } + VarInt varInt = VarInt.read(rawBlockData, offset); + blockData[i] = varInt.getValue(); + offset += varInt.getSize(); + } - VarInt varInt = VarInt.read(rawBlockData, offset); - blockData[i] = varInt.getValue(); - offset += varInt.getSize(); - } - - for (int y = 0; y < this.y; y++) { - for (int z = 0; z < this.z; z++) { - for (int x = 0; x < this.x; x++) { - int index = (y * this.z + z) * this.x + x; - IBlockState state = palette.get(blockData[index]); - if (state == null) { - throw new IllegalArgumentException("Invalid Palette Index " + index); - } - - this.states[x][z][y] = state; + for (int y = 0; y < this.y; y++) { + for (int z = 0; z < this.z; z++) { + for (int x = 0; x < this.x; x++) { + int index = (y * this.z + z) * this.x + x; + IBlockState state = palette.get(blockData[index]); + if (state == null) { + throw new IllegalArgumentException("Invalid Palette Index " + index); } + + this.states[x][z][y] = state; } } } diff --git a/src/main/java/baritone/utils/schematic/parse/MCEditParser.java b/src/main/java/baritone/utils/schematic/parse/MCEditParser.java deleted file mode 100644 index 3599b824..00000000 --- a/src/main/java/baritone/utils/schematic/parse/MCEditParser.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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.utils.schematic.parse; - -import baritone.api.schematic.parse.ISchematicParser; -import baritone.utils.schematic.StaticSchematic; -import baritone.utils.schematic.format.DefaultSchematicFormats; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.nbt.CompressedStreamTools; -import net.minecraft.nbt.NBTTagCompound; - -import java.io.IOException; -import java.io.InputStream; - -/** - * An implementation of {@link ISchematicParser} for {@link DefaultSchematicFormats#MCEDIT} - * - * @author Brady - * @since 12/16/2019 - */ -public enum MCEditParser implements ISchematicParser { - INSTANCE; - - @Override - public StaticSchematic parse(InputStream input) throws IOException { - return new MCEditSchematic(CompressedStreamTools.readCompressed(input)); - } - - private static final class MCEditSchematic extends StaticSchematic { - - MCEditSchematic(NBTTagCompound schematic) { - String type = schematic.getString("Materials"); - if (!type.equals("Alpha")) { - throw new IllegalStateException("bad schematic " + type); - } - this.x = schematic.getInteger("Width"); - this.y = schematic.getInteger("Height"); - this.z = schematic.getInteger("Length"); - byte[] blocks = schematic.getByteArray("Blocks"); - byte[] metadata = schematic.getByteArray("Data"); - - byte[] additional = null; - if (schematic.hasKey("AddBlocks")) { - byte[] addBlocks = schematic.getByteArray("AddBlocks"); - additional = new byte[addBlocks.length * 2]; - for (int i = 0; i < addBlocks.length; i++) { - additional[i * 2 + 0] = (byte) ((addBlocks[i] >> 4) & 0xF); // lower nibble - additional[i * 2 + 1] = (byte) ((addBlocks[i] >> 0) & 0xF); // upper nibble - } - } - this.states = new IBlockState[this.x][this.z][this.y]; - for (int y = 0; y < this.y; y++) { - for (int z = 0; z < this.z; z++) { - for (int x = 0; x < this.x; x++) { - int blockInd = (y * this.z + z) * this.x + x; - - int blockID = blocks[blockInd] & 0xFF; - if (additional != null) { - // additional is 0 through 15 inclusive since it's & 0xF above - blockID |= additional[blockInd] << 8; - } - Block block = Block.REGISTRY.getObjectById(blockID); - int meta = metadata[blockInd] & 0xFF; - this.states[x][z][y] = block.getStateFromMeta(meta); - } - } - } - } - } -} From 220ee30d35c8a5f9851903e7b4d791ae5253ffc3 Mon Sep 17 00:00:00 2001 From: Brady Date: Fri, 27 Dec 2019 21:28:05 -0600 Subject: [PATCH 12/14] Appease Codacy --- .../utils/schematic/format/defaults/SpongeSchematic.java | 4 ++-- src/main/java/baritone/utils/type/VarInt.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java b/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java index 0d03e5d8..8de038f5 100644 --- a/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java +++ b/src/main/java/baritone/utils/schematic/format/defaults/SpongeSchematic.java @@ -104,7 +104,7 @@ public final class SpongeSchematic extends StaticSchematic { this.properties = properties; } - IBlockState deserialize() { + private IBlockState deserialize() { if (this.blockState == null) { Block block = Block.REGISTRY.getObject(this.resourceLocation); this.blockState = block.getDefaultState(); @@ -119,7 +119,7 @@ public final class SpongeSchematic extends StaticSchematic { return this.blockState; } - static SerializedBlockState getFromString(String s) { + private static SerializedBlockState getFromString(String s) { Matcher m = REGEX.matcher(s); if (!m.matches()) { return null; diff --git a/src/main/java/baritone/utils/type/VarInt.java b/src/main/java/baritone/utils/type/VarInt.java index 45f83dda..93b3e425 100644 --- a/src/main/java/baritone/utils/type/VarInt.java +++ b/src/main/java/baritone/utils/type/VarInt.java @@ -54,9 +54,10 @@ public final class VarInt { return this.serialized; } - private static byte[] serialize0(int value) { + private static byte[] serialize0(int valueIn) { ByteList bytes = new ByteArrayList(); + int value = valueIn; while ((value & 0x80) != 0) { bytes.add((byte) (value & 0x7F | 0x80)); value >>>= 7; From fcfa022232f28627b9aebc78a8b3ddac63ea76aa Mon Sep 17 00:00:00 2001 From: Brady Date: Mon, 30 Dec 2019 02:27:20 -0600 Subject: [PATCH 13/14] Clean up BlockOptionalMeta comment and add behavioral clarification --- .../baritone/api/utils/BlockOptionalMeta.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/api/java/baritone/api/utils/BlockOptionalMeta.java b/src/api/java/baritone/api/utils/BlockOptionalMeta.java index 451d95eb..020df814 100644 --- a/src/api/java/baritone/api/utils/BlockOptionalMeta.java +++ b/src/api/java/baritone/api/utils/BlockOptionalMeta.java @@ -188,13 +188,20 @@ public final class BlockOptionalMeta { return (C) value; } + /** + * Normalizes the specified blockstate by setting meta-affecting properties which + * are not being targeted by the meta parameter to their default values. + *

+ * For example, block variant/color is the primary target for the meta value, so properties + * such as rotation/facing direction will be set to default values in order to nullify + * the effect that they have on the state's meta value. + * + * @param state The state to normalize + * @return The normalized block state + */ public static IBlockState normalize(IBlockState state) { IBlockState newState = state; - // TODO: Can the state not be normalized by simply doing...? - // return state.getBlock().getDefaultState(); - // ??? - for (IProperty property : state.getProperties().keySet()) { Class valueClass = property.getValueClass(); if (normalizations.containsKey(property)) { @@ -224,6 +231,15 @@ public final class BlockOptionalMeta { return newState; } + /** + * Evaluate the target meta value for the specified state. The target meta value is + * most often that which is influenced by the variant/color property of the block state. + * + * @see #normalize(IBlockState) + * + * @param state The state to check + * @return The target meta of the state + */ public static int stateMeta(IBlockState state) { return state.getBlock().getMetaFromState(normalize(state)); } From 4a05837b01cb04e28a73b114f6c035033d218454 Mon Sep 17 00:00:00 2001 From: Brady Date: Tue, 31 Dec 2019 17:44:20 -0600 Subject: [PATCH 14/14] Requested changes --- src/main/java/baritone/utils/type/VarInt.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/baritone/utils/type/VarInt.java b/src/main/java/baritone/utils/type/VarInt.java index 93b3e425..7cc005bd 100644 --- a/src/main/java/baritone/utils/type/VarInt.java +++ b/src/main/java/baritone/utils/type/VarInt.java @@ -85,7 +85,7 @@ public final class VarInt { } // Most significant bit denotes another byte is to be read. - if ((b & 0x80) != 0x80) { + if ((b & 0x80) == 0) { break; } }