Merge branch '1.13.2' into 1.14.4

This commit is contained in:
Brady
2019-12-31 21:57:55 -06:00
46 changed files with 1015 additions and 463 deletions

View File

@@ -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;
}
}

View File

@@ -27,8 +27,10 @@ import net.minecraft.block.BlockState;
import net.minecraft.client.multiplayer.ClientChunkProvider;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.AbstractChunkProvider;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.chunk.IChunk;
import java.util.*;
import java.util.stream.IntStream;
@@ -109,6 +111,41 @@ public enum WorldScanner implements IWorldScanner {
return res;
}
@Override
public int repack(IPlayerContext ctx) {
return this.repack(ctx, 40);
}
@Override
public int repack(IPlayerContext ctx, int range) {
AbstractChunkProvider chunkProvider = ctx.world().getChunkProvider();
ICachedWorld cachedWorld = ctx.worldData().getCachedWorld();
BetterBlockPos playerPos = ctx.playerFeet();
int playerChunkX = playerPos.getX() >> 4;
int playerChunkZ = playerPos.getZ() >> 4;
int minX = playerChunkX - range;
int minZ = playerChunkZ - range;
int maxX = playerChunkX + range;
int maxZ = playerChunkZ + range;
int queued = 0;
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
Chunk chunk = chunkProvider.getChunk(x, z, false);
if (chunk != null && !chunk.isEmpty()) {
queued++;
cachedWorld.queueForPacking(chunk);
}
}
}
return queued;
}
private boolean scanChunkInto(int chunkX, int chunkZ, Chunk chunk, BlockOptionalMetaLookup filter, Collection<BlockPos> result, int max, int yLevelThreshold, int playerY, int[] coordinateIterationOrder) {
ChunkSection[] chunkInternalStorageArray = chunk.getSections();
boolean foundWithinY = false;
@@ -145,26 +182,4 @@ public enum WorldScanner implements IWorldScanner {
}
return foundWithinY;
}
public int repack(IPlayerContext ctx) {
ClientChunkProvider chunkProvider = (ClientChunkProvider) ctx.world().getChunkProvider();
ICachedWorld cachedWorld = ctx.worldData().getCachedWorld();
BetterBlockPos playerPos = ctx.playerFeet();
int playerChunkX = playerPos.getX() >> 4;
int playerChunkZ = playerPos.getZ() >> 4;
int queued = 0;
for (int x = playerChunkX - 40; x <= playerChunkX + 40; x++) {
for (int z = playerChunkZ - 40; z <= playerChunkZ + 40; z++) {
Chunk chunk = chunkProvider.getChunk(x, z, null, false);
if (chunk != null && !chunk.isEmpty()) {
queued++;
cachedWorld.queueForPacking(chunk);
}
}
}
return queued;
}
}

View File

@@ -316,8 +316,7 @@ public class ArgConsumer implements IArgConsumer {
try {
return datatype.apply(this.context, original);
} catch (Exception e) {
e.printStackTrace();
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName());
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName(), e);
}
}
@@ -346,7 +345,7 @@ public class ArgConsumer implements IArgConsumer {
try {
return datatype.get(this.context);
} catch (Exception e) {
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName());
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName(), e);
}
}

View File

@@ -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;

View File

@@ -1,61 +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 <https://www.gnu.org/licenses/>.
*/
package baritone.command.defaults;
import baritone.api.IBaritone;
import baritone.api.command.Command;
import baritone.api.command.exception.CommandException;
import baritone.api.command.argument.IArgConsumer;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class CancelCommand extends Command {
public CancelCommand(IBaritone baritone) {
super(baritone, "cancel", "stop");
}
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
args.requireMax(0);
baritone.getPathingBehavior().cancelEverything();
logDirect("ok canceled");
}
@Override
public Stream<String> tabComplete(String label, IArgConsumer args) {
return Stream.empty();
}
@Override
public String getShortDesc() {
return "Cancel what Baritone is currently doing";
}
@Override
public List<String> getLongDesc() {
return Arrays.asList(
"The cancel command tells Baritone to stop whatever it's currently doing.",
"",
"Usage:",
"> cancel"
);
}
}

View File

@@ -24,52 +24,53 @@ import java.util.*;
public final class DefaultCommands {
private DefaultCommands() {}
private DefaultCommands() {
}
public static List<ICommand> createAll(IBaritone baritone) {
Objects.requireNonNull(baritone);
List<ICommand> commands = new ArrayList<>(Arrays.asList(
new HelpCommand(baritone),
new SetCommand(baritone),
new CommandAlias(baritone, Arrays.asList("modified", "mod", "baritone", "modifiedsettings"), "List modified settings", "set modified"),
new CommandAlias(baritone, "reset", "Reset all settings or just one", "set reset"),
new GoalCommand(baritone),
new GotoCommand(baritone),
new PathCommand(baritone),
new ProcCommand(baritone),
new VersionCommand(baritone),
new RepackCommand(baritone),
new BuildCommand(baritone),
new SchematicaCommand(baritone),
new ComeCommand(baritone),
new AxisCommand(baritone),
new CancelCommand(baritone),
new ForceCancelCommand(baritone),
new GcCommand(baritone),
new InvertCommand(baritone),
new TunnelCommand(baritone),
new RenderCommand(baritone),
new FarmCommand(baritone),
new ChestsCommand(baritone),
new FollowCommand(baritone),
new ExploreFilterCommand(baritone),
new ReloadAllCommand(baritone),
new SaveAllCommand(baritone),
new ExploreCommand(baritone),
new BlacklistCommand(baritone),
new FindCommand(baritone),
new MineCommand(baritone),
new ClickCommand(baritone),
new ThisWayCommand(baritone),
new WaypointsCommand(baritone),
new CommandAlias(baritone, "sethome", "Sets your home waypoint", "waypoints save home"),
new CommandAlias(baritone, "home", "Set goal to your home waypoint", "waypoints goal home"),
new SelCommand(baritone)
new HelpCommand(baritone),
new SetCommand(baritone),
new CommandAlias(baritone, Arrays.asList("modified", "mod", "baritone", "modifiedsettings"), "List modified settings", "set modified"),
new CommandAlias(baritone, "reset", "Reset all settings or just one", "set reset"),
new GoalCommand(baritone),
new GotoCommand(baritone),
new PathCommand(baritone),
new ProcCommand(baritone),
new VersionCommand(baritone),
new RepackCommand(baritone),
new BuildCommand(baritone),
new SchematicaCommand(baritone),
new ComeCommand(baritone),
new AxisCommand(baritone),
new ForceCancelCommand(baritone),
new GcCommand(baritone),
new InvertCommand(baritone),
new TunnelCommand(baritone),
new RenderCommand(baritone),
new FarmCommand(baritone),
new ChestsCommand(baritone),
new FollowCommand(baritone),
new ExploreFilterCommand(baritone),
new ReloadAllCommand(baritone),
new SaveAllCommand(baritone),
new ExploreCommand(baritone),
new BlacklistCommand(baritone),
new FindCommand(baritone),
new MineCommand(baritone),
new ClickCommand(baritone),
new ThisWayCommand(baritone),
new WaypointsCommand(baritone),
new CommandAlias(baritone, "sethome", "Sets your home waypoint", "waypoints save home"),
new CommandAlias(baritone, "home", "Set goal to your home waypoint", "waypoints goal home"),
new SelCommand(baritone)
));
PauseResumeCommands prc = new PauseResumeCommands(baritone);
ExecutionControlCommands prc = new ExecutionControlCommands(baritone);
commands.add(prc.pauseCommand);
commands.add(prc.resumeCommand);
commands.add(prc.pausedCommand);
commands.add(prc.cancelCommand);
return Collections.unmodifiableList(commands);
}
}

View File

@@ -18,13 +18,13 @@
package baritone.command.defaults;
import baritone.api.IBaritone;
import baritone.api.command.Command;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
import baritone.api.command.exception.CommandInvalidStateException;
import baritone.api.process.IBaritoneProcess;
import baritone.api.process.PathingCommand;
import baritone.api.process.PathingCommandType;
import baritone.api.command.Command;
import baritone.api.command.exception.CommandException;
import baritone.api.command.exception.CommandInvalidStateException;
import baritone.api.command.argument.IArgConsumer;
import java.util.Arrays;
import java.util.List;
@@ -37,13 +37,14 @@ import java.util.stream.Stream;
* TO USE THIS to pause and resume Baritone. Make your own process that returns {@link PathingCommandType#REQUEST_PAUSE
* REQUEST_PAUSE} as needed.
*/
public class PauseResumeCommands {
public class ExecutionControlCommands {
Command pauseCommand;
Command resumeCommand;
Command pausedCommand;
Command cancelCommand;
public PauseResumeCommands(IBaritone baritone) {
public ExecutionControlCommands(IBaritone baritone) {
// array for mutability, non-field so reflection can't touch it
final boolean[] paused = {false};
baritone.getPathingControlManager().registerProcess(
@@ -64,7 +65,8 @@ public class PauseResumeCommands {
}
@Override
public void onLostControl() {}
public void onLostControl() {
}
@Override
public double priority() {
@@ -169,5 +171,36 @@ public class PauseResumeCommands {
);
}
};
cancelCommand = new Command(baritone, "cancel", "stop") {
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
args.requireMax(0);
if (paused[0]) {
paused[0] = false;
}
baritone.getPathingBehavior().cancelEverything();
logDirect("ok canceled");
}
@Override
public Stream<String> tabComplete(String label, IArgConsumer args) {
return Stream.empty();
}
@Override
public String getShortDesc() {
return "Cancel what Baritone is currently doing";
}
@Override
public List<String> getLongDesc() {
return Arrays.asList(
"The cancel command tells Baritone to stop whatever it's currently doing.",
"",
"Usage:",
"> cancel"
);
}
};
}
}

View File

@@ -41,9 +41,13 @@ public class GotoCommand extends Command {
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
if (args.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) { // if we have a numeric first argument...
// If we have a numeric first argument, then parse arguments as coordinates.
// Note: There is no reason to want to go where you're already at so there
// is no need to handle the case of empty arguments.
if (args.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) {
args.requireMax(3);
BetterBlockPos origin = baritone.getPlayerContext().playerFeet();
Goal goal = args.getDatatypePostOrNull(RelativeGoal.INSTANCE, origin);
Goal goal = args.getDatatypePost(RelativeGoal.INSTANCE, origin);
logDirect(String.format("Going to: %s", goal.toString()));
baritone.getCustomGoalProcess().setGoalAndPath(goal);
return;

View File

@@ -37,6 +37,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockReader;
import java.util.Optional;
@@ -138,7 +139,7 @@ public interface MovementHelper extends ActionCosts, Helper {
// every block that overrides isPassable with anything more complicated than a "return true;" or "return false;"
// has already been accounted for above
// therefore it's safe to not construct a blockpos from our x, y, z ints and instead just pass null
return state.allowsMovement(null, BlockPos.ZERO, PathType.LAND); // workaround for future compatibility =P
return state.allowsMovement(bsi.access, BlockPos.ZERO, PathType.LAND); // workaround for future compatibility =P
}
/**
@@ -152,10 +153,18 @@ public interface MovementHelper extends ActionCosts, Helper {
* @return Whether or not the block at the specified position
*/
static boolean fullyPassable(CalculationContext context, int x, int y, int z) {
return fullyPassable(context.get(x, y, z));
return fullyPassable(
context.bsi.access,
context.bsi.isPassableBlockPos.setPos(x, y, z),
context.bsi.get0(x, y, z)
);
}
static boolean fullyPassable(BlockState state) {
static boolean fullyPassable(IPlayerContext ctx, BlockPos pos) {
return fullyPassable(ctx.world(), pos, ctx.world().getBlockState(pos));
}
static boolean fullyPassable(IBlockReader access, BlockPos pos, BlockState state) {
Block block = state.getBlock();
if (block instanceof AirBlock) { // early return for most common case
return true;
@@ -178,7 +187,7 @@ public interface MovementHelper extends ActionCosts, Helper {
return false;
}
// door, fence gate, liquid, trapdoor have been accounted for, nothing else uses the world or pos parameters
return state.allowsMovement(null, null, PathType.LAND);
return state.allowsMovement(access, pos, PathType.LAND);
}
static boolean isReplaceable(int x, int y, int z, BlockState state, BlockStateInterface bsi) {

View File

@@ -115,7 +115,7 @@ public class MovementParkour extends Movement {
return;
}
BlockState destInto = context.bsi.get0(destX, y, destZ);
if (!MovementHelper.fullyPassable(destInto)) {
if (!MovementHelper.fullyPassable(context.bsi.access, context.bsi.isPassableBlockPos.setPos(destX, y, destZ), destInto)) {
if (i <= 3 && context.allowParkourAscend && context.canSprint && MovementHelper.canWalkOn(context.bsi, destX, y, destZ, destInto) && checkOvershootSafety(context.bsi, destX + xDiff, y + 1, destZ + zDiff)) {
res.x = destX;
res.y = y + 1;

View File

@@ -466,7 +466,7 @@ public class PathExecutor implements IPathExecutor, Helper {
}
for (int y = next.getDest().y; y <= movement.getSrc().y + 1; y++) {
BlockPos chk = new BlockPos(next.getDest().x, y, next.getDest().z);
if (!MovementHelper.fullyPassable(ctx.world().getBlockState(chk))) {
if (!MovementHelper.fullyPassable(ctx, chk)) {
break outer;
}
}
@@ -491,7 +491,7 @@ public class PathExecutor implements IPathExecutor, Helper {
}
// we are centered
BlockPos headBonk = current.getSrc().subtract(current.getDirection()).up(2);
if (MovementHelper.fullyPassable(ctx.world().getBlockState(headBonk))) {
if (MovementHelper.fullyPassable(ctx, headBonk)) {
return true;
}
// wait 0.3
@@ -524,7 +524,7 @@ public class PathExecutor implements IPathExecutor, Helper {
if (x == 1) {
chk = chk.add(current.getDirection());
}
if (!MovementHelper.fullyPassable(ctx.world().getBlockState(chk))) {
if (!MovementHelper.fullyPassable(ctx, chk)) {
return false;
}
}

View File

@@ -25,8 +25,14 @@ 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.*;
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;
import baritone.api.utils.RotationUtils;
import baritone.api.utils.input.Input;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
@@ -34,9 +40,8 @@ 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.Schematic;
import baritone.utils.schematic.SchematicSystem;
import baritone.utils.schematic.schematica.SchematicaHelper;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.minecraft.block.AirBlock;
@@ -57,7 +62,6 @@ import net.minecraft.util.math.shapes.VoxelShape;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
@@ -73,6 +77,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
private int ticks;
private boolean paused;
private int layer;
private int numRepeats;
private List<BlockState> approxPlaceable;
public BuilderProcess(Baritone baritone) {
@@ -99,6 +104,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
this.origin = new Vec3i(x, y, z);
this.paused = false;
this.layer = 0;
this.numRepeats = 0;
this.observedCompleted = new LongOpenHashSet();
}
@@ -117,27 +123,38 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
@Override
public boolean build(String name, File schematic, Vec3i origin) {
CompoundNBT tag;
try (FileInputStream fileIn = new FileInputStream(schematic)) {
tag = CompressedStreamTools.readCompressed(fileIn);
} catch (IOException e) {
Optional<ISchematicFormat> format = SchematicSystem.INSTANCE.getByFile(schematic);
if (!format.isPresent()) {
return false;
}
ISchematic parsed;
try {
parsed = format.get().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((IStaticSchematic) parsed);
}
build(name, parse(tag), origin);
build(name, parsed, origin);
return true;
}
@Override
public void buildOpenSchematic() {
if (SchematicaHelper.isSchematicaPresent()) {
Optional<Tuple<ISchematic, BlockPos>> schematic = SchematicaHelper.getOpenSchematic();
Optional<Tuple<IStaticSchematic, BlockPos>> schematic = SchematicaHelper.getOpenSchematic();
if (schematic.isPresent()) {
this.build(schematic.get().getA().toString(), schematic.get().getA(), schematic.get().getB());
IStaticSchematic s = schematic.get().getA();
this.build(
schematic.get().getA().toString(),
Baritone.settings().mapArtMode.value ? new MapArtSchematic(s) : s,
schematic.get().getB()
);
} else {
logDirect("No schematic currently open");
}
@@ -159,10 +176,6 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return new ArrayList<>(approxPlaceable);
}
private static ISchematic parse(CompoundNBT schematic) {
return Baritone.settings().mapArtMode.value ? new MapArtSchematic(schematic) : new Schematic(schematic);
}
@Override
public boolean isActive() {
return schematic != null;
@@ -407,7 +420,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return onTick(calcFailed, isSafeToCancel);
}
Vec3i repeat = Baritone.settings().buildRepeat.value;
if (repeat.equals(new Vec3i(0, 0, 0))) {
int max = Baritone.settings().buildRepeatCount.value;
numRepeats++;
if (repeat.equals(new Vec3i(0, 0, 0)) || (max != -1 && numRepeats >= max)) {
logDirect("Done building");
onLostControl();
return null;
@@ -747,6 +762,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
schematic = null;
realSchematic = null;
layer = 0;
numRepeats = 0;
paused = false;
observedCompleted = null;
}
@@ -782,6 +798,12 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return true;
}
// TODO more complicated comparison logic I guess
if (desired.getBlock() instanceof AirBlock && Baritone.settings().buildIgnoreBlocks.value.contains(current.getBlock())) {
return true;
}
if (!(current.getBlock() instanceof AirBlock) && Baritone.settings().buildIgnoreExisting.value) {
return true;
}
return current.equals(desired);
}

View File

@@ -31,13 +31,13 @@ import net.minecraft.client.settings.AmbientOcclusionStatus;
import net.minecraft.client.settings.CloudOption;
import net.minecraft.client.settings.ParticleStatus;
import net.minecraft.client.tutorial.TutorialSteps;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.util.HTTPUtil;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.GameType;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.WorldType;
import net.minecraft.world.*;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.server.ServerWorld;
import java.io.File;
import java.io.IOException;
@@ -95,7 +95,7 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper {
if (mc.currentScreen instanceof MainMenuScreen) {
System.out.println("Beginning Baritone automatic test routine");
mc.displayGuiScreen(null);
WorldSettings worldsettings = new WorldSettings(TEST_SEED, GameType.getByName("survival"), true, false, WorldType.DEFAULT);
WorldSettings worldsettings = new WorldSettings(TEST_SEED, GameType.SURVIVAL, true, false, WorldType.DEFAULT);
mc.launchIntegratedServer("BaritoneAutoTest", "BaritoneAutoTest", worldsettings);
}
@@ -104,6 +104,7 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper {
// If the integrated server is launched and the world has initialized, set the spawn point
// to our defined starting position
if (server != null && server.getWorld(DimensionType.OVERWORLD) != null) {
server.setDifficultyForAllWorlds(Difficulty.PEACEFUL, true);
if (mc.player == null) {
server.execute(() -> {
server.getWorld(DimensionType.OVERWORLD).setSpawnPoint(STARTING_POSITION);
@@ -113,6 +114,17 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper {
throw new IllegalStateException(result + "");
}
});
for (final ServerWorld world : mc.getIntegratedServer().getWorlds()) {
// If the world has initialized, set the spawn point to our defined starting position
if (world != null) {
// I would rather do this than try to mess with poz
CompoundNBT nbt = world.getGameRules().write();
nbt.putString("spawnRadius", "0");
world.getGameRules().read(nbt);
world.setSpawnPoint(STARTING_POSITION);
}
}
}
}
@@ -121,7 +133,7 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper {
// Force the integrated server to share the world to LAN so that
// the ingame pause menu gui doesn't actually pause our game
if (mc.isSingleplayer() && !mc.getIntegratedServer().getPublic()) {
mc.getIntegratedServer().shareToLAN(GameType.getByName("survival"), false, HTTPUtil.getSuitableLanPort());
mc.getIntegratedServer().shareToLAN(GameType.SURVIVAL, false, HTTPUtil.getSuitableLanPort());
}
// For the first 200 ticks, wait for the world to generate
@@ -163,5 +175,6 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper {
}
}
private BaritoneAutoTest() {}
private BaritoneAutoTest() {
}
}

View File

@@ -28,6 +28,7 @@ import net.minecraft.block.Blocks;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientChunkProvider;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
@@ -42,6 +43,9 @@ public class BlockStateInterface {
private final ClientChunkProvider provider;
private final WorldData worldData;
protected final IBlockReader world;
public final BlockPos.MutableBlockPos isPassableBlockPos;
public final IBlockReader access;
private Chunk prev = null;
private CachedRegion prevCached = null;
@@ -59,6 +63,7 @@ public class BlockStateInterface {
}
public BlockStateInterface(World world, WorldData worldData, boolean copyLoadedChunks) {
this.world = world;
this.worldData = worldData;
if (copyLoadedChunks) {
this.provider = ((IClientChunkProvider) world.getChunkProvider()).createThreadSafeCopy();
@@ -69,6 +74,8 @@ public class BlockStateInterface {
if (!Minecraft.getInstance().isOnExecutionThread()) {
throw new IllegalStateException();
}
this.isPassableBlockPos = new BlockPos.MutableBlockPos();
this.access = new BlockStateInterfaceAccessWrapper(this);
}
public boolean worldContainsLoadedChunk(int blockX, int blockZ) {

View File

@@ -0,0 +1,57 @@
/*
* 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.BlockState;
import net.minecraft.fluid.IFluidState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import javax.annotation.Nullable;
/**
* @author Brady
* @since 11/5/2019
*/
@SuppressWarnings("NullableProblems")
public final class BlockStateInterfaceAccessWrapper implements IBlockReader {
private final BlockStateInterface bsi;
BlockStateInterfaceAccessWrapper(BlockStateInterface bsi) {
this.bsi = bsi;
}
@Nullable
@Override
public TileEntity getTileEntity(BlockPos pos) {
throw new UnsupportedOperationException("getTileEntity not supported by BlockStateInterfaceAccessWrapper");
}
@Override
public BlockState getBlockState(BlockPos pos) {
// BlockStateInterface#get0(BlockPos) btfo!
return this.bsi.get0(pos.getX(), pos.getY(), pos.getZ());
}
@Override
public IFluidState getFluidState(BlockPos blockPos) {
return getBlockState(blockPos).getFluidState();
}
}

View File

@@ -19,23 +19,32 @@ package baritone.utils.schematic;
import net.minecraft.block.AirBlock;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import baritone.api.schematic.IStaticSchematic;
import baritone.api.schematic.MaskSchematic;
import java.util.OptionalInt;
import java.util.function.Predicate;
public class MapArtSchematic extends Schematic {
public class MapArtSchematic extends MaskSchematic {
private final int[][] heightMap;
public MapArtSchematic(CompoundNBT schematic) {
public MapArtSchematic(IStaticSchematic schematic) {
super(schematic);
heightMap = new int[widthX][lengthZ];
this.heightMap = generateHeightMap(schematic);
}
for (int x = 0; x < widthX; x++) {
for (int z = 0; z < lengthZ; z++) {
BlockState[] column = states[x][z];
@Override
protected boolean partOfMask(int x, int y, int z, BlockState currentState) {
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++) {
BlockState[] column = schematic.getColumn(x, z);
OptionalInt lowestBlockY = lastIndexMatching(column, state -> !(state.getBlock() instanceof AirBlock));
if (lowestBlockY.isPresent()) {
heightMap[x][z] = lowestBlockY.getAsInt();
@@ -44,9 +53,9 @@ public class MapArtSchematic extends Schematic {
System.out.println("Letting it be whatever");
heightMap[x][z] = 256;
}
}
}
return heightMap;
}
private static <T> OptionalInt lastIndexMatching(T[] arr, Predicate<? super T> predicate) {
@@ -57,10 +66,4 @@ public class MapArtSchematic extends Schematic {
}
return OptionalInt.empty();
}
@Override
public boolean inSchematic(int x, int y, int z, BlockState 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];
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<ISchematicFormat> registry = new Registry<>();
SchematicSystem() {
Arrays.stream(DefaultSchematicFormats.values()).forEach(this.registry::register);
}
@Override
public Registry<ISchematicFormat> getRegistry() {
return this.registry;
}
@Override
public Optional<ISchematicFormat> getByFile(File file) {
return this.registry.stream().filter(format -> format.isFileType(file)).findFirst();
}
}

View File

@@ -17,42 +17,34 @@
package baritone.utils.schematic;
import baritone.api.schematic.ISchematic;
import baritone.api.schematic.AbstractSchematic;
import baritone.api.schematic.IStaticSchematic;
import net.minecraft.block.BlockState;
import java.util.List;
public class FillSchematic implements ISchematic {
/**
* Default implementation of {@link IStaticSchematic}
*
* @author Brady
* @since 12/23/2019
*/
public class StaticSchematic extends AbstractSchematic implements IStaticSchematic {
private final int widthX;
private final int heightY;
private final int lengthZ;
private final BlockState state;
public FillSchematic(int widthX, int heightY, int lengthZ, BlockState state) {
this.widthX = widthX;
this.heightY = heightY;
this.lengthZ = lengthZ;
this.state = state;
}
protected BlockState[][][] states;
@Override
public BlockState desiredState(int x, int y, int z, BlockState current, List<BlockState> approxPlaceable) {
return state;
return this.states[x][z][y];
}
@Override
public int widthX() {
return widthX;
public BlockState getDirect(int x, int y, int z) {
return this.states[x][z][y];
}
@Override
public int heightY() {
return heightY;
}
@Override
public int lengthZ() {
return lengthZ;
public BlockState[] getColumn(int x, int z) {
return this.states[x][z];
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.schematic.format;
import baritone.api.schematic.IStaticSchematic;
import baritone.api.schematic.format.ISchematicFormat;
import baritone.utils.schematic.format.defaults.MCEditSchematic;
import baritone.utils.schematic.format.defaults.SpongeSchematic;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.CompressedStreamTools;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
* Default implementations of {@link ISchematicFormat}
*
* @author Brady
* @since 12/13/2019
*/
public enum DefaultSchematicFormats implements ISchematicFormat {
/**
* The MCEdit schematic specification. Commonly denoted by the ".schematic" file extension.
*/
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 <a href="https://github.com/SpongePowered/Schematic-Specification">Sponge Schematic Specification</a>
*/
SPONGE("schem") {
@Override
public IStaticSchematic parse(InputStream input) throws IOException {
CompoundNBT nbt = CompressedStreamTools.readCompressed(input);
int version = nbt.getInt("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;
DefaultSchematicFormats(String extension) {
this.extension = extension;
}
@Override
public boolean isFileType(File file) {
return this.extension.equalsIgnoreCase(FilenameUtils.getExtension(file.getAbsolutePath()));
}
}

View File

@@ -15,34 +15,35 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.schematic;
package baritone.utils.schematic.format.defaults;
import baritone.api.schematic.ISchematic;
import baritone.utils.schematic.StaticSchematic;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.datafix.fixes.ItemIntIDToString;
import net.minecraft.util.registry.Registry;
import java.util.List;
/**
* @author Brady
* @since 12/27/2019
*/
public final class MCEditSchematic extends StaticSchematic {
public class Schematic implements ISchematic {
public final int widthX;
public final int heightY;
public final int lengthZ;
protected final BlockState[][][] states;
public Schematic(CompoundNBT schematic) {
/*String type = schematic.getString("Materials");
public MCEditSchematic(CompoundNBT 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");
this.x = schematic.getInt("Width");
this.y = schematic.getInt("Height");
this.z = schematic.getInt("Length");
byte[] blocks = schematic.getByteArray("Blocks");
byte[] metadata = schematic.getByteArray("Data");
// byte[] metadata = schematic.getByteArray("Data");
byte[] additional = null;
if (schematic.hasKey("AddBlocks")) {
if (schematic.contains("AddBlocks")) {
byte[] addBlocks = schematic.getByteArray("AddBlocks");
additional = new byte[addBlocks.length * 2];
for (int i = 0; i < addBlocks.length; i++) {
@@ -50,43 +51,23 @@ public class Schematic implements ISchematic {
additional[i * 2 + 1] = (byte) ((addBlocks[i] >> 0) & 0xF); // upper nibble
}
}
states = new BlockState[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;
this.states = new BlockState[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;
states[x][z][y] = block.getStateFromMeta(meta);
Block block = Registry.BLOCK.getOrDefault(ResourceLocation.tryCreate(ItemIntIDToString.getItem(blockID)));
// int meta = metadata[blockInd] & 0xFF;
// this.states[x][z][y] = block.getStateFromMeta(meta);
this.states[x][z][y] = block.getDefaultState();
}
}
}*/
throw new UnsupportedOperationException("1.13 be like: numeric IDs btfo");
}
}
@Override
public BlockState desiredState(int x, int y, int z, BlockState current, List<BlockState> approxPlaceable) {
return states[x][z][y];
}
@Override
public int widthX() {
return widthX;
}
@Override
public int heightY() {
return heightY;
}
@Override
public int lengthZ() {
return lengthZ;
}
}
}

View File

@@ -0,0 +1,158 @@
/*
* 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.schematic.format.defaults;
import baritone.utils.schematic.StaticSchematic;
import baritone.utils.type.VarInt;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.IProperty;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Brady
* @since 12/27/2019
*/
public final class SpongeSchematic extends StaticSchematic {
public SpongeSchematic(CompoundNBT nbt) {
this.x = nbt.getInt("Width");
this.y = nbt.getInt("Height");
this.z = nbt.getInt("Length");
this.states = new BlockState[this.x][this.z][this.y];
Int2ObjectArrayMap<BlockState> palette = new Int2ObjectArrayMap<>();
CompoundNBT paletteTag = nbt.getCompound("Palette");
for (String tag : paletteTag.keySet()) {
int index = paletteTag.getInt(tag);
SerializedBlockState serializedState = SerializedBlockState.getFromString(tag);
if (serializedState == null) {
throw new IllegalArgumentException("Unable to parse palette tag");
}
BlockState 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");
}
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;
BlockState state = palette.get(blockData[index]);
if (state == null) {
throw new IllegalArgumentException("Invalid Palette Index " + index);
}
this.states[x][z][y] = state;
}
}
}
}
private static final class SerializedBlockState {
private static final Pattern REGEX = Pattern.compile("(?<location>(\\w+:)?\\w+)(\\[(?<properties>(\\w+=\\w+,?)+)])?");
private final ResourceLocation resourceLocation;
private final Map<String, String> properties;
private BlockState blockState;
private SerializedBlockState(ResourceLocation resourceLocation, Map<String, String> properties) {
this.resourceLocation = resourceLocation;
this.properties = properties;
}
private BlockState deserialize() {
if (this.blockState == null) {
Block block = Registry.BLOCK.getOrDefault(this.resourceLocation);
this.blockState = block.getDefaultState();
this.properties.keySet().stream().sorted(String::compareTo).forEachOrdered(key -> {
IProperty<?> property = block.getStateContainer().getProperty(key);
if (property != null) {
this.blockState = setPropertyValue(this.blockState, property, this.properties.get(key));
}
});
}
return this.blockState;
}
private 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<String, String> 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;
}
}
private static <T extends Comparable<T>> BlockState setPropertyValue(BlockState state, IProperty<T> property, String value) {
Optional<T> parsed = property.parseValue(value);
if (parsed.isPresent()) {
return state.with(property, parsed.get());
} else {
throw new IllegalArgumentException("Invalid value for property " + property);
}
}
}
}

View File

@@ -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.BlockState;
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 BlockState desiredState(int x, int y, int z, BlockState current, List<BlockState> approxPlaceable) {
return schematic.getSchematic().getBlockState(new BlockPos(x, y, z));
return this.getDirect(x, y, z);
}
@Override
public BlockState getDirect(int x, int y, int z) {
return this.schematic.getSchematic().getBlockState(new BlockPos(x, y, z));
}
@Override

View File

@@ -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<Tuple<ISchematic, BlockPos>> getOpenSchematic() {
public static Optional<Tuple<IStaticSchematic, BlockPos>> getOpenSchematic() {
return Optional.ofNullable(ClientProxy.schematic)
.map(world -> new Tuple<>(new SchematicAdapter(world), world.position));
}

View File

@@ -0,0 +1,95 @@
/*
* 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.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 valueIn) {
ByteList bytes = new ByteArrayList();
int value = valueIn;
while ((value & 0x80) != 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) == 0) {
break;
}
}
return new VarInt(value);
}
}