Skip to content

Commit

Permalink
Merge pull request #4453 from ZacSharp/pr/1.19.4/schematics/litematic…
Browse files Browse the repository at this point in the history
…aRework

Almost rewrite litematic handling
  • Loading branch information
leijurv authored Aug 22, 2024
2 parents f6045b7 + 6b6931c commit ef72c56
Show file tree
Hide file tree
Showing 14 changed files with 268 additions and 330 deletions.
15 changes: 3 additions & 12 deletions src/main/java/baritone/command/defaults/LitematicaCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,9 @@ public LitematicaCommand(IBaritone baritone) {

@Override
public void execute(String label, IArgConsumer args) throws CommandException {
int schematic = 0;
if (args.hasAny()) {
args.requireMax(1);
if (args.is(Integer.class)) {
schematic = args.getAs(Integer.class) - 1;
}
}
try {
baritone.getBuilderProcess().buildOpenLitematic(schematic);
} catch (IndexOutOfBoundsException e) {
logDirect("Pleas provide a valid index.");
}
args.requireMax(1);
int schematic = args.hasAny() ? args.getAs(Integer.class) - 1 : 0;
baritone.getBuilderProcess().buildOpenLitematic(schematic);
}

@Override
Expand Down
7 changes: 1 addition & 6 deletions src/main/java/baritone/command/defaults/SelCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,7 @@ public void execute(String label, IArgConsumer args) throws CommandException {
}
}
}
ISchematic schematic = new StaticSchematic() {{
states = blockstates;
x = size.getX();
y = size.getY();
z = size.getZ();
}};
ISchematic schematic = new StaticSchematic(blockstates);
composite.put(schematic, min.x - origin.x, min.y - origin.y, min.z - origin.z);
}
clipboard = composite;
Expand Down
19 changes: 6 additions & 13 deletions src/main/java/baritone/process/BuilderProcess.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.NbtIo;
import net.minecraft.util.Tuple;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.BlockItem;
Expand Down Expand Up @@ -229,19 +228,13 @@ public void buildOpenSchematic() {
public void buildOpenLitematic(int i) {
if (LitematicaHelper.isLitematicaPresent()) {
//if java.lang.NoSuchMethodError is thrown see comment in SchematicPlacementManager
if (LitematicaHelper.hasLoadedSchematic()) {
String name = LitematicaHelper.getName(i);
try {
LitematicaSchematic schematic1 = new LitematicaSchematic(NbtIo.readCompressed(Files.newInputStream(LitematicaHelper.getSchematicFile(i).toPath())), false);
Vec3i correctedOrigin = LitematicaHelper.getCorrectedOrigin(schematic1, i);
ISchematic schematic2 = LitematicaHelper.blackMagicFuckery(schematic1, i);
schematic2 = applyMapArtAndSelection(origin, (IStaticSchematic) schematic2);
build(name, schematic2, correctedOrigin);
} catch (Exception e) {
logDirect("Schematic File could not be loaded.");
}
if (LitematicaHelper.hasLoadedSchematic(i)) {
Tuple<IStaticSchematic, Vec3i> schematic = LitematicaHelper.getSchematic(i);
Vec3i correctedOrigin = schematic.getB();
ISchematic schematic2 = applyMapArtAndSelection(correctedOrigin, schematic.getA());
build(schematic.getA().toString(), schematic2, correctedOrigin);
} else {
logDirect("No schematic currently loaded");
logDirect(String.format("List of placements has no entry %s", i + 1));
}
} else {
logDirect("Litematica is not present");
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/baritone/utils/schematic/StaticSchematic.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ public class StaticSchematic extends AbstractSchematic implements IStaticSchemat

protected BlockState[][][] states;

public StaticSchematic() {}

public StaticSchematic(BlockState[][][] states) {
this.states = states;
boolean empty = states.length == 0 || states[0].length == 0 || states[0][0].length == 0;
this.x = empty ? 0 : states.length;
this.z = empty ? 0 : states[0].length;
this.y = empty ? 0 : states[0][0].length;
}

@Override
public BlockState desiredState(int x, int y, int z, BlockState current, List<BlockState> approxPlaceable) {
return this.states[x][z][y];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public IStaticSchematic parse(InputStream input) throws IOException {
case 5: //1.13-1.17
throw new UnsupportedOperationException("This litematic Version is too old.");
case 6: //1.18+
return new LitematicaSchematic(nbt, false);
return new LitematicaSchematic(nbt);
default:
throw new UnsupportedOperationException("Unsuported Version of a Litematica Schematic");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@

package baritone.utils.schematic.format.defaults;

import baritone.api.schematic.CompositeSchematic;
import baritone.api.schematic.IStaticSchematic;
import baritone.utils.schematic.StaticSchematic;
import net.minecraft.core.Registry;
import net.minecraft.core.Vec3i;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
Expand All @@ -30,6 +31,7 @@
import org.apache.commons.lang3.Validate;

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Optional;

/**
Expand All @@ -39,35 +41,24 @@
* @author rycbar
* @since 22.09.2022
*/
public final class LitematicaSchematic extends StaticSchematic {
private final Vec3i offsetMinCorner;
private final CompoundTag nbt;
public final class LitematicaSchematic extends CompositeSchematic implements IStaticSchematic {

/**
* @param nbtTagCompound a decompressed file stream aka nbt data.
* @param rotated if the schematic is rotated by 90°.
*/
public LitematicaSchematic(CompoundTag nbtTagCompound, boolean rotated) {
this.nbt = nbtTagCompound;
this.offsetMinCorner = new Vec3i(getMinOfSchematic("x"), getMinOfSchematic("y"), getMinOfSchematic("z"));
this.y = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("y"));

if (rotated) {
this.x = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("z"));
this.z = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("x"));
} else {
this.x = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("x"));
this.z = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("z"));
}
this.states = new BlockState[this.x][this.z][this.y];
fillInSchematic();
public LitematicaSchematic(CompoundTag nbt) {
super(0, 0, 0);
fillInSchematic(nbt);
}

/**
* @return Array of subregion names.
* @return Array of subregion tags.
*/
private static String[] getRegions(CompoundTag nbt) {
return nbt.getCompound("Regions").getAllKeys().toArray(new String[0]);
private static CompoundTag[] getRegions(CompoundTag nbt) {
return nbt.getCompound("Regions").getAllKeys().stream()
.map(nbt.getCompound("Regions")::getCompound)
.toArray(CompoundTag[]::new);
}

/**
Expand All @@ -76,14 +67,10 @@ private static String[] getRegions(CompoundTag nbt) {
* @param s axis that should be read.
* @return the lower coord of the requested axis.
*/
private static int getMinOfSubregion(CompoundTag nbt, String subReg, String s) {
int a = nbt.getCompound("Regions").getCompound(subReg).getCompound("Position").getInt(s);
int b = nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt(s);
if (b < 0) {
b++;
}
return Math.min(a, a + b);

private static int getMinOfSubregion(CompoundTag subReg, String s) {
int a = subReg.getCompound("Position").getInt(s);
int b = subReg.getCompound("Size").getInt(s);
return Math.min(a, a + b + 1);
}

/**
Expand All @@ -110,7 +97,7 @@ private static BlockState[] getBlockList(ListTag blockStatePalette) {
private static BlockState getBlockState(Block block, CompoundTag properties) {
BlockState blockState = block.defaultBlockState();

for (Object key : properties.getAllKeys().toArray()) {
for (Object key : properties.getAllKeys()) {
Property<?> property = block.getStateDefinition().getProperty((String) key);
String propertyValue = properties.getString((String) key);
if (property != null) {
Expand Down Expand Up @@ -146,62 +133,38 @@ private static int getBitsPerBlock(int amountOfBlockTypes) {
*
* @return the volume of the subregion.
*/
private static long getVolume(CompoundTag nbt, String subReg) {
return Math.abs(
nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("x") *
nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("y") *
nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("z"));
}

/**
* @return array of Long values.
*/
private static long[] getBlockStates(CompoundTag nbt, String subReg) {
return nbt.getCompound("Regions").getCompound(subReg).getLongArray("BlockStates");
}

/**
* Subregion don't have to be the same size as the enclosing size of the schematic. If they are smaller we check here if the current block is part of the subregion.
*
* @param x coord of the block relative to the minimum corner.
* @param y coord of the block relative to the minimum corner.
* @param z coord of the block relative to the minimum corner.
* @return if the current block is part of the subregion.
*/
private static boolean inSubregion(CompoundTag nbt, String subReg, int x, int y, int z) {
return x >= 0 && y >= 0 && z >= 0 &&
x < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("x")) &&
y < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("y")) &&
z < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("z"));
private static long getVolume(CompoundTag subReg) {
CompoundTag size = subReg.getCompound("Size");
return Math.abs(size.getInt("x") * size.getInt("y") * size.getInt("z"));
}

/**
* @param s axis.
* @return the lowest coordinate of that axis of the schematic.
*/
private int getMinOfSchematic(String s) {
private static int getMinOfSchematic(CompoundTag nbt, String s) {
int n = Integer.MAX_VALUE;
for (String subReg : getRegions(nbt)) {
n = Math.min(n, getMinOfSubregion(nbt, subReg, s));
for (CompoundTag subReg : getRegions(nbt)) {
n = Math.min(n, getMinOfSubregion(subReg, s));
}
return n;
}

/**
* reads the file data.
*/
private void fillInSchematic() {
for (String subReg : getRegions(nbt)) {
ListTag usedBlockTypes = nbt.getCompound("Regions").getCompound(subReg).getList("BlockStatePalette", 10);
private void fillInSchematic(CompoundTag nbt) {
Vec3i offsetMinCorner = new Vec3i(getMinOfSchematic(nbt, "x"), getMinOfSchematic(nbt, "y"), getMinOfSchematic(nbt, "z"));
for (CompoundTag subReg : getRegions(nbt)) {
ListTag usedBlockTypes = subReg.getList("BlockStatePalette", 10);
BlockState[] blockList = getBlockList(usedBlockTypes);

int bitsPerBlock = getBitsPerBlock(usedBlockTypes.size());
long regionVolume = getVolume(nbt, subReg);
long[] blockStateArray = getBlockStates(nbt, subReg);
long regionVolume = getVolume(subReg);
long[] blockStateArray = subReg.getLongArray("BlockStates");

LitematicaBitArray bitArray = new LitematicaBitArray(bitsPerBlock, regionVolume, blockStateArray);

writeSubregionIntoSchematic(nbt, subReg, blockList, bitArray);
writeSubregionIntoSchematic(subReg, offsetMinCorner, blockList, bitArray);
}
}

Expand All @@ -211,65 +174,30 @@ private void fillInSchematic() {
* @param blockList list with the different block types used in the schematic.
* @param bitArray bit array that holds the placement pattern.
*/
private void writeSubregionIntoSchematic(CompoundTag nbt, String subReg, BlockState[] blockList, LitematicaBitArray bitArray) {
Vec3i offsetSubregion = new Vec3i(getMinOfSubregion(nbt, subReg, "x"), getMinOfSubregion(nbt, subReg, "y"), getMinOfSubregion(nbt, subReg, "z"));
private void writeSubregionIntoSchematic(CompoundTag subReg, Vec3i offsetMinCorner, BlockState[] blockList, LitematicaBitArray bitArray) {
int offsetX = getMinOfSubregion(subReg, "x") - offsetMinCorner.getX();
int offsetY = getMinOfSubregion(subReg, "y") - offsetMinCorner.getY();
int offsetZ = getMinOfSubregion(subReg, "z") - offsetMinCorner.getZ();
CompoundTag size = subReg.getCompound("Size");
int sizeX = Math.abs(size.getInt("x"));
int sizeY = Math.abs(size.getInt("y"));
int sizeZ = Math.abs(size.getInt("z"));
BlockState[][][] states = new BlockState[sizeX][sizeZ][sizeY];
int index = 0;
for (int y = 0; y < this.y; y++) {
for (int z = 0; z < this.z; z++) {
for (int x = 0; x < this.x; x++) {
if (inSubregion(nbt, subReg, x, y, z)) {
this.states[x - (offsetMinCorner.getX() - offsetSubregion.getX())][z - (offsetMinCorner.getZ() - offsetSubregion.getZ())][y - (offsetMinCorner.getY() - offsetSubregion.getY())] = blockList[bitArray.getAt(index)];
index++;
}
for (int y = 0; y < sizeY; y++) {
for (int z = 0; z < sizeZ; z++) {
for (int x = 0; x < sizeX; x++) {
states[x][z][y] = blockList[bitArray.getAt(index)];
index++;
}
}
}
this.put(new StaticSchematic(states), offsetX, offsetY, offsetZ);
}

/**
* @return offset from the schematic origin to the minimum Corner as a Vec3i.
*/
public Vec3i getOffsetMinCorner() {
return offsetMinCorner;
}

/**
* @return x size of the schematic.
*/
public int getX() {
return this.x;
}

/**
* @return y size of the schematic.
*/
public int getY() {
return this.y;
}

/**
* @return z size of the schematic.
*/
public int getZ() {
return this.z;
}

/**
* @param x position relative to the minimum corner of the schematic.
* @param y position relative to the minimum corner of the schematic.
* @param z position relative to the minimum corner of the schematic.
* @param blockState new blockstate of the block at this position.
*/
public void setDirect(int x, int y, int z, BlockState blockState) {
this.states[x][z][y] = blockState;
}

/**
* @param rotated if the schematic is rotated by 90°.
* @return a copy of the schematic.
*/
public LitematicaSchematic getCopy(boolean rotated) {
return new LitematicaSchematic(nbt, rotated);
@Override
public BlockState getDirect(int x, int y, int z) {
return desiredState(x, y, z, null, Collections.emptyList());
}

/**
Expand Down
Loading

0 comments on commit ef72c56

Please sign in to comment.