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 super T> 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 super T> 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