preliminary schematic stuff
This commit is contained in:
parent
8ed2431f37
commit
702b916948
@ -28,9 +28,9 @@ import net.minecraft.util.math.BlockPos;
|
||||
*/
|
||||
public class GoalGetToBlock implements Goal, IGoalRenderPos {
|
||||
|
||||
private final int x;
|
||||
private final int y;
|
||||
private final int z;
|
||||
public final int x;
|
||||
public final int y;
|
||||
public final int z;
|
||||
|
||||
public GoalGetToBlock(BlockPos pos) {
|
||||
this.x = pos.getX();
|
||||
|
@ -57,6 +57,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
|
||||
private boolean safeToCancel;
|
||||
private boolean pauseRequestedLastTick;
|
||||
private boolean unpausedLastTick;
|
||||
private boolean cancelRequested;
|
||||
private boolean calcFailedLastTick;
|
||||
|
||||
@ -102,10 +103,14 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
private void tickPath() {
|
||||
if (pauseRequestedLastTick && safeToCancel) {
|
||||
pauseRequestedLastTick = false;
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock();
|
||||
if (unpausedLastTick) {
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock();
|
||||
}
|
||||
unpausedLastTick = false;
|
||||
return;
|
||||
}
|
||||
unpausedLastTick = true;
|
||||
if (cancelRequested) {
|
||||
cancelRequested = false;
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
|
@ -142,11 +142,14 @@ public class CalculationContext {
|
||||
return placeBlockCost;
|
||||
}
|
||||
|
||||
public boolean canBreakAt(int x, int y, int z) {
|
||||
public double breakCostMultiplierAt(int x, int y, int z) {
|
||||
if (!allowBreak) {
|
||||
return false;
|
||||
return COST_INF;
|
||||
}
|
||||
return !isPossiblyProtected(x, y, z);
|
||||
if (isPossiblyProtected(x, y, z)) {
|
||||
return COST_INF;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public double placeBucketCost() {
|
||||
|
@ -341,7 +341,8 @@ public interface MovementHelper extends ActionCosts, Helper {
|
||||
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) {
|
||||
Block block = state.getBlock();
|
||||
if (!canWalkThrough(context.bsi, x, y, z, state)) {
|
||||
if (!context.canBreakAt(x, y, z)) {
|
||||
double mult = context.breakCostMultiplierAt(x, y, z);
|
||||
if (mult >= COST_INF) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (avoidBreaking(context.bsi, x, y, z, state)) {
|
||||
@ -358,6 +359,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
||||
|
||||
double result = m / strVsBlock;
|
||||
result += context.breakBlockAdditionalCost;
|
||||
result *= mult;
|
||||
if (includeFalling) {
|
||||
IBlockState above = context.get(x, y + 1, z);
|
||||
if (above.getBlock() instanceof BlockFalling) {
|
||||
|
@ -240,4 +240,10 @@ public class MovementAscend extends Movement {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean safeToCancel(MovementState state) {
|
||||
// if we had to place, don't allow pause
|
||||
return state.getStatus() != MovementStatus.RUNNING || ticksWithoutPlacement == 0;
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MovementPillar extends Movement {
|
||||
|
||||
public MovementPillar(IBaritone baritone, BetterBlockPos start, BetterBlockPos end) {
|
||||
@ -229,7 +231,7 @@ public class MovementPillar extends Movement {
|
||||
if (!(fr instanceof BlockAir || fr.isReplaceable(ctx.world(), src))) {
|
||||
state.setInput(Input.CLICK_LEFT, true);
|
||||
blockIsThere = false;
|
||||
} else if (ctx.player().isSneaking()) { // 1 tick after we're able to place
|
||||
} else if (ctx.player().isSneaking() && (Objects.equals(src.down(), ctx.objectMouseOver().getBlockPos()) || Objects.equals(src, ctx.objectMouseOver().getBlockPos()))) { // 1 tick after we're able to place
|
||||
state.setInput(Input.CLICK_RIGHT, true);
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,15 @@ import baritone.api.pathing.goals.GoalGetToBlock;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.api.utils.RotationUtils;
|
||||
import baritone.api.utils.input.Input;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.ISchematic;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
import baritone.utils.Schematic;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.init.Blocks;
|
||||
@ -38,14 +42,15 @@ 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.BlockPos;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
||||
|
||||
@ -80,7 +85,7 @@ public class BuilderProcess extends BaritoneProcessHelper {
|
||||
}
|
||||
|
||||
private static ISchematic parse(NBTTagCompound schematic) {
|
||||
throw new UnsupportedOperationException("would rather die than parse " + schematic);
|
||||
return new Schematic(schematic);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,6 +93,32 @@ public class BuilderProcess extends BaritoneProcessHelper {
|
||||
return schematic != null;
|
||||
}
|
||||
|
||||
public Optional<Tuple<BetterBlockPos, Rotation>> toBreakNearPlayer(BuilderCalculationContext bcc) {
|
||||
BetterBlockPos center = ctx.playerFeet();
|
||||
for (int dx = -5; dx <= 5; dx++) {
|
||||
for (int dy = 0; dy <= 5; dy++) {
|
||||
for (int dz = -5; dz <= 5; dz++) {
|
||||
int x = center.x + dx;
|
||||
int y = center.y + dy;
|
||||
int z = center.z + dz;
|
||||
IBlockState desired = bcc.getSchematic(x, y, z);
|
||||
if (desired == null) {
|
||||
continue; // irrelevant
|
||||
}
|
||||
IBlockState curr = bcc.bsi.get0(x, y, z);
|
||||
if (curr.getBlock() != Blocks.AIR && !valid(curr, desired)) {
|
||||
BetterBlockPos pos = new BetterBlockPos(x, y, z);
|
||||
Optional<Rotation> rot = RotationUtils.reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
|
||||
if (rot.isPresent()) {
|
||||
return Optional.of(new Tuple<>(pos, rot.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
// TODO somehow tell inventorybehavior what we'd like to have on the hotbar
|
||||
@ -97,22 +128,113 @@ public class BuilderProcess extends BaritoneProcessHelper {
|
||||
// this will work as is, but it'll be trashy
|
||||
// need to iterate over incorrectPositions and see which ones we can "correct" from our current standing position
|
||||
|
||||
// considerations:
|
||||
// shouldn't break blocks that are supporting our current path segment, maybe?
|
||||
//
|
||||
return new PathingCommandContext(new GoalComposite(assemble()), PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH, new BuilderCalculationContext(schematic, origin));
|
||||
|
||||
BuilderCalculationContext bcc = new BuilderCalculationContext(schematic, origin);
|
||||
if (!recalc(bcc)) {
|
||||
logDirect("Done building");
|
||||
onLostControl();
|
||||
return null;
|
||||
}
|
||||
Optional<Tuple<BetterBlockPos, Rotation>> toBreak = toBreakNearPlayer(bcc);
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
if (toBreak.isPresent() && isSafeToCancel && ctx.player().onGround) {
|
||||
// we'd like to pause to break this block
|
||||
// only change look direction if it's safe (don't want to fuck up an in progress parkour for example
|
||||
Rotation rot = toBreak.get().getSecond();
|
||||
BetterBlockPos pos = toBreak.get().getFirst();
|
||||
baritone.getLookBehavior().updateTarget(rot, true);
|
||||
MovementHelper.switchToBestToolFor(ctx, bcc.get(pos));
|
||||
if (Objects.equals(ctx.objectMouseOver().getBlockPos(), rot) || ctx.playerRotations().isReallyCloseTo(rot)) {
|
||||
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_LEFT, true);
|
||||
}
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
|
||||
Goal[] goals = assemble(bcc);
|
||||
if (goals.length == 0) {
|
||||
logDirect("Unable to do it =(");
|
||||
onLostControl();
|
||||
return null;
|
||||
}
|
||||
return new PathingCommandContext(new GoalComposite(goals), PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH, bcc);
|
||||
}
|
||||
|
||||
private Goal[] assemble() {
|
||||
BlockStateInterface bsi = new CalculationContext(baritone).bsi;
|
||||
return incorrectPositions.stream().map(pos ->
|
||||
bsi.get0(pos).getBlock() == Blocks.AIR ?
|
||||
// it's air and it shouldn't be
|
||||
new GoalBlock(pos.up())
|
||||
// it's a block and it shouldn't be
|
||||
// todo disallow right above
|
||||
: new GoalGetToBlock(pos) // replace with GoalTwoBlocks to mine using pathfinding system only
|
||||
).toArray(Goal[]::new);
|
||||
public boolean recalc(BuilderCalculationContext bcc) {
|
||||
if (incorrectPositions == null) {
|
||||
incorrectPositions = new HashSet<>();
|
||||
fullRecalc(bcc);
|
||||
if (incorrectPositions.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
recalcNearby(bcc);
|
||||
if (incorrectPositions.isEmpty()) {
|
||||
fullRecalc(bcc);
|
||||
}
|
||||
return !incorrectPositions.isEmpty();
|
||||
}
|
||||
|
||||
public void recalcNearby(BuilderCalculationContext bcc) {
|
||||
BetterBlockPos center = ctx.playerFeet();
|
||||
for (int dx = -5; dx <= 5; dx++) {
|
||||
for (int dy = -5; dy <= 5; dy++) {
|
||||
for (int dz = -5; dz <= 5; dz++) {
|
||||
int x = center.x + dx;
|
||||
int y = center.y + dy;
|
||||
int z = center.z + dz;
|
||||
IBlockState desired = bcc.getSchematic(x, y, z);
|
||||
if (desired != null) {
|
||||
// we care about this position
|
||||
if (valid(bcc.bsi.get0(x, y, z), desired)) {
|
||||
incorrectPositions.remove(new BetterBlockPos(x, y, z));
|
||||
} else {
|
||||
incorrectPositions.add(new BetterBlockPos(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void fullRecalc(BuilderCalculationContext bcc) {
|
||||
incorrectPositions = new HashSet<>();
|
||||
for (int y = 0; y < schematic.heightY(); y++) {
|
||||
for (int z = 0; z < schematic.lengthZ(); z++) {
|
||||
for (int x = 0; x < schematic.widthX(); x++) {
|
||||
if (schematic.inSchematic(x, y, z)) {
|
||||
if (!valid(bcc.bsi.get0(x + origin.getX(), y + origin.getY(), z + origin.getZ()), schematic.desiredState(x, y, z))) {
|
||||
incorrectPositions.add(new BetterBlockPos(x + origin.getX(), y + origin.getY(), z + origin.getZ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Goal[] assemble(BuilderCalculationContext bcc) {
|
||||
List<IBlockState> approxPlacable = placable();
|
||||
List<BetterBlockPos> placable = incorrectPositions.stream().filter(pos -> bcc.bsi.get0(pos).getBlock() == Blocks.AIR && approxPlacable.contains(bcc.getSchematic(pos.x, pos.y, pos.z))).collect(Collectors.toList());
|
||||
if (!placable.isEmpty()) {
|
||||
return placable.stream().filter(pos -> !placable.contains(pos.down()) && !placable.contains(pos.down(2))).map(BetterBlockPos::up).map(GoalBlock::new).toArray(Goal[]::new);
|
||||
}
|
||||
return incorrectPositions.stream().filter(pos -> bcc.bsi.get0(pos).getBlock() != Blocks.AIR).map(GoalBreak::new).toArray(Goal[]::new);
|
||||
}
|
||||
|
||||
public static class GoalBreak extends GoalGetToBlock {
|
||||
|
||||
public GoalBreak(BlockPos pos) {
|
||||
super(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGoal(int x, int y, int z) {
|
||||
// can't stand right on top of a block, that might not work (what if it's unsupported, can't break then)
|
||||
if (x == this.x && y == this.y + 1 && z == this.z) {
|
||||
return false;
|
||||
}
|
||||
// but any other adjacent works for breaking, including inside or below
|
||||
return super.isInGoal(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,6 +271,11 @@ public class BuilderProcess extends BaritoneProcessHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean valid(IBlockState current, IBlockState desired) {
|
||||
// TODO more complicated comparison logic I guess
|
||||
return desired == null || current.equals(desired);
|
||||
}
|
||||
|
||||
public class BuilderCalculationContext extends CalculationContext {
|
||||
private final List<IBlockState> placable;
|
||||
private final ISchematic schematic;
|
||||
@ -181,6 +308,11 @@ public class BuilderProcess extends BaritoneProcessHelper {
|
||||
IBlockState sch = getSchematic(x, y, z);
|
||||
if (sch != null) {
|
||||
// TODO this can return true even when allowPlace is off.... is that an issue?
|
||||
if (sch.getBlock() == Blocks.AIR) {
|
||||
// we want this to be air, but they're asking if they can place here
|
||||
// this won't be a schematic block, this will be a throwaway
|
||||
return placeBlockCost * 2; // we're going to have to break it eventually
|
||||
}
|
||||
if (placable.contains(sch)) {
|
||||
return 0; // thats right we gonna make it FREE to place a block where it should go in a structure
|
||||
// no place block penalty at all 😎
|
||||
@ -190,15 +322,9 @@ public class BuilderProcess extends BaritoneProcessHelper {
|
||||
if (!hasThrowaway) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (sch.getBlock() == Blocks.AIR) {
|
||||
// we want this to be air, but they're asking if they can place here
|
||||
// this won't be a schematic block, this will be a throwaway
|
||||
return placeBlockCost * 2; // we're going to have to break it eventually
|
||||
} else {
|
||||
// we want it to be something that we don't have
|
||||
// even more of a pain to place something wrong
|
||||
return placeBlockCost * 3;
|
||||
}
|
||||
// we want it to be something that we don't have
|
||||
// even more of a pain to place something wrong
|
||||
return placeBlockCost * 3;
|
||||
} else {
|
||||
if (hasThrowaway) {
|
||||
return placeBlockCost;
|
||||
@ -209,24 +335,32 @@ public class BuilderProcess extends BaritoneProcessHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBreakAt(int x, int y, int z) {
|
||||
public double breakCostMultiplierAt(int x, int y, int z) {
|
||||
if (!allowBreak || isPossiblyProtected(x, y, z)) {
|
||||
return false;
|
||||
return COST_INF;
|
||||
}
|
||||
IBlockState sch = getSchematic(x, y, z);
|
||||
if (sch != null) {
|
||||
if (sch.getBlock() == Blocks.AIR) {
|
||||
// it should be air
|
||||
// regardless of current contents, we can break it
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
// it should be a real block
|
||||
// is it already that block?
|
||||
return !bsi.get0(x, y, z).equals(sch); // can break if it's wrong
|
||||
if (valid(bsi.get0(x, y, z), sch)) {
|
||||
return 3;
|
||||
} else {
|
||||
// can break if it's wrong
|
||||
// would be great to return less than 1 here, but that would actually make the cost calculation messed up
|
||||
// since we're breaking a block, if we underestimate the cost, then it'll fail when it really takes the correct amount of time
|
||||
return 1;
|
||||
|
||||
}
|
||||
// TODO do blocks in render distace only?
|
||||
// TODO allow breaking blocks that we have a tool to harvest and immediately place back?
|
||||
} else {
|
||||
return true; // why not lol
|
||||
return 1; // why not lol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,4 +36,10 @@ public interface ISchematic {
|
||||
boolean inSchematic(int x, int y, int z);
|
||||
|
||||
IBlockState desiredState(int x, int y, int z);
|
||||
|
||||
int widthX();
|
||||
|
||||
int heightY();
|
||||
|
||||
int lengthZ();
|
||||
}
|
52
src/main/java/baritone/utils/MapArtSchematic.java
Normal file
52
src/main/java/baritone/utils/MapArtSchematic.java
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.utils;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public class MapArtSchematic extends Schematic {
|
||||
private final int[][] heightMap;
|
||||
|
||||
public MapArtSchematic(NBTTagCompound schematic) {
|
||||
super(schematic);
|
||||
heightMap = new int[widthX][lengthZ];
|
||||
for (int x = 0; x < widthX; x++) {
|
||||
https:
|
||||
for (int z = 0; z < lengthZ; z++) {
|
||||
IBlockState[] column = states[x][z];
|
||||
for (int y = heightY - 1; y >= 0; y--) {
|
||||
if (column[y].getBlock() != Blocks.AIR) {
|
||||
heightMap[x][z] = y;
|
||||
continue https;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inSchematic(int x, int y, int z) {
|
||||
// in map art, we only care about coordinates in or above the art
|
||||
return super.inSchematic(x, y, z) && y >= heightMap[x][z];
|
||||
}
|
||||
}
|
93
src/main/java/baritone/utils/Schematic.java
Normal file
93
src/main/java/baritone/utils/Schematic.java
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.utils;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
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 boolean inSchematic(int x, int y, int z) {
|
||||
return x >= 0 && x < widthX && y >= 0 && y < heightY && z >= 0 && z < lengthZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState desiredState(int x, int y, int z) {
|
||||
return states[x][z][y];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int widthX() {
|
||||
return widthX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int heightY() {
|
||||
return heightY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lengthZ() {
|
||||
return lengthZ;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user