Take data directly from Litematica

This commit is contained in:
ZacSharp
2024-07-28 23:50:03 +02:00
parent b12c4e9f8c
commit b87a1fa420
9 changed files with 452 additions and 59 deletions

View File

@@ -39,14 +39,12 @@ import java.util.Optional;
* @since 22.09.2022
*/
public final class LitematicaSchematic extends StaticSchematic {
private final Vec3i offsetMinCorner;
/**
* @param nbtTagCompound a decompressed file stream aka nbt data.
* @param rotated if the schematic is rotated by 90°.
*/
public LitematicaSchematic(CompoundTag nbt) {
this.offsetMinCorner = new Vec3i(getMinOfSchematic(nbt, "x"), getMinOfSchematic(nbt, "y"), getMinOfSchematic(nbt, "z"));
CompoundTag size = nbt.getCompound("Metadata").getCompound("EnclosingSize");
this.x = Math.abs(size.getInt("x"));
this.y = Math.abs(size.getInt("y"));
@@ -173,6 +171,7 @@ public final class LitematicaSchematic extends StaticSchematic {
* reads the file data.
*/
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);
@@ -182,7 +181,7 @@ public final class LitematicaSchematic extends StaticSchematic {
long[] blockStateArray = subReg.getLongArray("BlockStates");
LitematicaBitArray bitArray = new LitematicaBitArray(bitsPerBlock, regionVolume, blockStateArray);
writeSubregionIntoSchematic(subReg, blockList, bitArray);
writeSubregionIntoSchematic(subReg, offsetMinCorner, blockList, bitArray);
}
}
@@ -192,7 +191,7 @@ public final class LitematicaSchematic extends StaticSchematic {
* @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 subReg, BlockState[] blockList, LitematicaBitArray bitArray) {
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();
@@ -209,13 +208,6 @@ public final class LitematicaSchematic extends StaticSchematic {
}
}
/**
* @return offset from the schematic origin to the minimum Corner as a Vec3i.
*/
public Vec3i getOffsetMinCorner() {
return offsetMinCorner;
}
/**
* @author maruohon
* Class from the Litematica mod by maruohon

View File

@@ -17,21 +17,27 @@
package baritone.utils.schematic.litematica;
import baritone.api.schematic.AbstractSchematic;
import baritone.api.schematic.IStaticSchematic;
import baritone.api.schematic.ISchematic;
import baritone.api.schematic.CompositeSchematic;
import baritone.api.schematic.MirroredSchematic;
import baritone.api.schematic.RotatedSchematic;
import baritone.utils.schematic.StaticSchematic;
import baritone.utils.schematic.format.defaults.LitematicaSchematic;
import fi.dy.masa.litematica.Litematica;
import fi.dy.masa.litematica.data.DataManager;
import fi.dy.masa.litematica.schematic.container.LitematicaBlockStateContainer;
import fi.dy.masa.litematica.schematic.placement.SchematicPlacement;
import fi.dy.masa.litematica.schematic.placement.SubRegionPlacement;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.NbtIo;
import net.minecraft.util.Tuple;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Collections;
import java.util.Map;
/**
* Helper class that provides access or processes data related to Litmatica schematics.
@@ -72,23 +78,6 @@ public final class LitematicaHelper {
return getPlacement(i).getName();
}
/**
* @param schematic original schematic.
* @param i index of the Schematic in the schematic placement list.
* @return the minimum corner coordinates of the schematic, after the original schematic got rotated and mirrored.
*/
private static Vec3i getCorrectedOrigin(SchematicPlacement placement, LitematicaSchematic schematic) {
Vec3i origin = placement.getOrigin();
Vec3i minCorner = schematic.getOffsetMinCorner();
int sx = 2 - schematic.widthX(); // this is because the position needs to be adjusted
int sz = 2 - schematic.lengthZ(); // by widthX/lengthZ after every transformation
Mirror mirror = placement.getMirror();
Rotation rotation = placement.getRotation();
return origin.offset(rotate(doMirroring(minCorner, sx, sz, mirror), sx, sz, rotation));
}
/**
* @param in the xyz offsets of the block relative to the schematic minimum corner.
* @param sizeX size of the schematic in the x-axis direction.
@@ -96,7 +85,7 @@ public final class LitematicaHelper {
* @param mirror the mirroring of the schematic placement.
* @return the corresponding xyz coordinates after mirroring them according to the given mirroring.
*/
private static Vec3i doMirroring(Vec3i in, int sizeX, int sizeZ, Mirror mirror) {
static Vec3i doMirroring(Vec3i in, int sizeX, int sizeZ, Mirror mirror) {
int xOut = in.getX();
int zOut = in.getZ();
if (mirror == Mirror.LEFT_RIGHT) {
@@ -114,7 +103,7 @@ public final class LitematicaHelper {
* @param rotation the rotation to apply
* @return the corresponding xyz coordinates after applying {@code rotation}.
*/
private static Vec3i rotate(Vec3i in, int sizeX, int sizeZ, Rotation rotation) {
static Vec3i rotate(Vec3i in, int sizeX, int sizeZ, Rotation rotation) {
switch (rotation) {
case CLOCKWISE_90:
return new Vec3i(sizeZ - 1 - in.getZ(), in.getY(), in.getX());
@@ -132,26 +121,91 @@ public final class LitematicaHelper {
* @param i index of the Schematic in the schematic placement list.
* @return get it out rotated and mirrored.
*/
public static Tuple<IStaticSchematic, Vec3i> getSchematic(int i) throws IOException {
public static Tuple<IStaticSchematic, Vec3i> getSchematic(int i) {
// annoying fun fact: you can't just work in placement coordinates and then apply
// the placement rotation/mirror to the result because litematica applies the
// global transforms *before* applying the local transforms
SchematicPlacement placement = getPlacement(i);
Rotation rotation = placement.getRotation();
Mirror mirror = placement.getMirror();
LitematicaSchematic schemIn = new LitematicaSchematic(NbtIo.readCompressed(Files.newInputStream(placement.getSchematicFile().toPath())));
Vec3i origin = getCorrectedOrigin(placement, schemIn);
boolean flip = rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90;
BlockState[][][] states = new BlockState[flip ? schemIn.lengthZ() : schemIn.widthX()][flip ? schemIn.widthX() : schemIn.lengthZ()][schemIn.heightY()];
for (int yCounter = 0; yCounter < schemIn.heightY(); yCounter++) {
for (int zCounter = 0; zCounter < schemIn.lengthZ(); zCounter++) {
for (int xCounter = 0; xCounter < schemIn.widthX(); xCounter++) {
Vec3i xyzHolder = new Vec3i(xCounter, yCounter, zCounter);
xyzHolder = LitematicaHelper.doMirroring(xyzHolder, schemIn.widthX(), schemIn.lengthZ(), mirror);
xyzHolder = rotate(xyzHolder, schemIn.widthX(), schemIn.lengthZ(), rotation);
BlockState state = schemIn.getDirect(xCounter, yCounter, zCounter);
state = state == null ? null : state.mirror(mirror).rotate(rotation);
states[xyzHolder.getX()][xyzHolder.getZ()][xyzHolder.getY()] = state;
CompositeSchematic composite = new CompositeSchematic(0, 0, 0);
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int minZ = Integer.MAX_VALUE;
for (Map.Entry<String, SubRegionPlacement> entry : placement.getEnabledRelativeSubRegionPlacements().entrySet()) {
SubRegionPlacement subPlacement = entry.getValue();
Vec3i pos = subPlacement.getPos();
Vec3i size = placement.getSchematic().getAreaSize(entry.getKey());
minX = Math.min(pos.getX() + Math.min(size.getX() + 1, 0), minX);
minY = Math.min(pos.getY() + Math.min(size.getY() + 1, 0), minY);
minZ = Math.min(pos.getZ() + Math.min(size.getZ() + 1, 0), minZ);
}
for (Map.Entry<String, SubRegionPlacement> entry : placement.getEnabledRelativeSubRegionPlacements().entrySet()) {
SubRegionPlacement subPlacement = entry.getValue();
Vec3i size = placement.getSchematic().getAreaSize(entry.getKey());
LitematicaBlockStateContainer container = placement.getSchematic().getSubRegionContainer(entry.getKey());
BlockState[][][] states = new BlockState[Math.abs(size.getX())][Math.abs(size.getZ())][Math.abs(size.getY())];
for (int x = 0; x < states.length; x++) {
for (int z = 0; z < states[x].length; z++) {
for (int y = 0; y < states[x][z].length; y++) {
states[x][z][y] = container.get(x, y, z);
}
}
}
ISchematic schematic = new StaticSchematic(states);
Mirror mirror = subPlacement.getMirror();
Rotation rotation = subPlacement.getRotation();
if (placement.getRotation() == Rotation.CLOCKWISE_90 || placement.getRotation() == Rotation.COUNTERCLOCKWISE_90) {
mirror = mirror == Mirror.LEFT_RIGHT ? Mirror.FRONT_BACK : Mirror.LEFT_RIGHT;
}
if (placement.getMirror() != Mirror.NONE) {
rotation = rotation.getRotated(rotation).getRotated(rotation); // inverse rotation
}
schematic = new MirroredSchematic(schematic, mirror);
schematic = new RotatedSchematic(schematic, rotation);
int mx = Math.min(size.getX() + 1, 0);
int my = Math.min(size.getY() + 1, 0);
int mz = Math.min(size.getZ() + 1, 0);
int sx = 2 - Math.abs(size.getX()); // this is because the position needs to be adjusted
int sz = 2 - Math.abs(size.getZ()); // by widthX/lengthZ after every transformation
Vec3i minCorner = new Vec3i(mx, my, mz);
minCorner = rotate(doMirroring(minCorner, sx, sz, mirror), sx, sz, rotation);
Vec3i pos = subPlacement.getPos().offset(minCorner).offset(-minX, -minY, -minZ);
composite.put(schematic, pos.getX(), pos.getY(), pos.getZ());
}
int sx = 2 - composite.widthX(); // this is because the position needs to be adjusted
int sz = 2 - composite.lengthZ(); // by widthX/lengthZ after every transformation
Vec3i minCorner = new Vec3i(minX, minY, minZ);
Mirror mirror = placement.getMirror();
Rotation rotation = placement.getRotation();
minCorner = rotate(doMirroring(minCorner, sx, sz, mirror), sx, sz, rotation);
ISchematic schematic = new MirroredSchematic(composite, mirror);
schematic = new RotatedSchematic(schematic, rotation);
return new Tuple<>(new LitematicaPlacementSchematic(schematic), placement.getOrigin().offset(minCorner));
}
private static class LitematicaPlacementSchematic extends AbstractSchematic implements IStaticSchematic {
private final ISchematic schematic;
public LitematicaPlacementSchematic(ISchematic schematic) {
super(schematic.widthX(), schematic.heightY(), schematic.lengthZ());
this.schematic = schematic;
}
@Override
public BlockState getDirect(int x, int y, int z) {
if (inSchematic(x, y, z, null)) {
return desiredState(x, y, z, null, Collections.emptyList());
}
return null;
}
@Override
public BlockState desiredState(int x, int y, int z, BlockState current, List<BlockState> approxPlaceable) {
return schematic.desiredState(x, y, z, current, approxPlaceable);
}
@Override
public boolean inSchematic(int x, int y, int z, BlockState current) {
return schematic.inSchematic(x, y, z, current);
}
return new Tuple<>(new StaticSchematic(states), origin);
}
}