Merge branch 'master' into 1.13.2

This commit is contained in:
ZacSharp
2022-03-21 17:57:39 +01:00
24 changed files with 211 additions and 745 deletions

View File

@@ -68,7 +68,6 @@ public class Baritone implements IBaritone {
private PathingBehavior pathingBehavior;
private LookBehavior lookBehavior;
private MemoryBehavior memoryBehavior;
private InventoryBehavior inventoryBehavior;
private InputOverrideHandler inputOverrideHandler;
@@ -100,7 +99,6 @@ public class Baritone implements IBaritone {
// the Behavior constructor calls baritone.registerBehavior(this) so this populates the behaviors arraylist
pathingBehavior = new PathingBehavior(this);
lookBehavior = new LookBehavior(this);
memoryBehavior = new MemoryBehavior(this);
inventoryBehavior = new InventoryBehavior(this);
inputOverrideHandler = new InputOverrideHandler(this);
}
@@ -151,10 +149,6 @@ public class Baritone implements IBaritone {
return this.playerContext;
}
public MemoryBehavior getMemoryBehavior() {
return this.memoryBehavior;
}
@Override
public FollowProcess getFollowProcess() {
return this.followProcess;

View File

@@ -1,319 +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.behavior;
import baritone.Baritone;
import baritone.api.cache.Waypoint;
import baritone.api.event.events.BlockInteractEvent;
import baritone.api.event.events.PacketEvent;
import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.event.events.type.EventState;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.Helper;
import baritone.cache.ContainerMemory;
import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block;
import net.minecraft.block.BlockBed;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.network.Packet;
import net.minecraft.network.play.client.CPacketCloseWindow;
import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock;
import net.minecraft.network.play.server.SPacketCloseWindow;
import net.minecraft.network.play.server.SPacketOpenWindow;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityLockable;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
/**
* doesn't work for horse inventories :^)
*
* @author Brady
* @since 8/6/2018
*/
public final class MemoryBehavior extends Behavior {
private final List<FutureInventory> futureInventories = new ArrayList<>(); // this is per-bot
private Integer enderChestWindowId; // nae nae
public MemoryBehavior(Baritone baritone) {
super(baritone);
}
@Override
public synchronized void onTick(TickEvent event) {
if (!Baritone.settings().containerMemory.value) {
return;
}
if (event.getType() == TickEvent.Type.OUT) {
enderChestWindowId = null;
futureInventories.clear();
}
}
@Override
public synchronized void onPlayerUpdate(PlayerUpdateEvent event) {
if (event.getState() == EventState.PRE) {
updateInventory();
}
}
@Override
public synchronized void onSendPacket(PacketEvent event) {
if (!Baritone.settings().containerMemory.value) {
return;
}
Packet p = event.getPacket();
if (event.getState() == EventState.PRE) {
if (p instanceof CPacketPlayerTryUseItemOnBlock) {
CPacketPlayerTryUseItemOnBlock packet = event.cast();
TileEntity tileEntity = ctx.world().getTileEntity(packet.getPos());
// if tileEntity is an ender chest, we don't need to do anything. ender chests are treated the same regardless of what coordinate right clicked
// Ensure the TileEntity is a container of some sort
if (tileEntity instanceof TileEntityLockable) {
TileEntityLockable lockable = (TileEntityLockable) tileEntity;
int size = lockable.getSizeInventory();
BetterBlockPos position = BetterBlockPos.from(tileEntity.getPos());
BetterBlockPos adj = BetterBlockPos.from(neighboringConnectedBlock(position));
System.out.println(position + " " + adj);
if (adj != null) {
size *= 2; // double chest or double trapped chest
if (adj.getX() < position.getX() || adj.getZ() < position.getZ()) {
position = adj; // standardize on the lower coordinate, regardless of which side of the large chest we right clicked
}
}
this.futureInventories.add(new FutureInventory(System.nanoTime() / 1000000L, size, lockable.getGuiID(), position));
}
}
if (p instanceof CPacketCloseWindow) {
getCurrent().save();
}
}
}
@Override
public synchronized void onReceivePacket(PacketEvent event) {
if (!Baritone.settings().containerMemory.value) {
return;
}
Packet p = event.getPacket();
if (event.getState() == EventState.PRE) {
if (p instanceof SPacketOpenWindow) {
SPacketOpenWindow packet = event.cast();
// Remove any entries that were created over a second ago, this should make up for INSANE latency
futureInventories.removeIf(i -> System.nanoTime() / 1000000L - i.time > 1000);
System.out.println("Received packet " + packet.getGuiId() + " " + packet.getEntityId() + " " + packet.getSlotCount() + " " + packet.getWindowId());
System.out.println(packet.getWindowTitle());
if (packet.getWindowTitle() instanceof TextComponentTranslation && ((TextComponentTranslation) packet.getWindowTitle()).getKey().equals("container.enderchest")) {
// title is not customized (i.e. this isn't just a renamed shulker)
enderChestWindowId = packet.getWindowId();
return;
}
futureInventories.stream()
.filter(i -> i.type.equals(packet.getGuiId()) && i.slots == packet.getSlotCount())
.findFirst().ifPresent(matched -> {
// Remove the future inventory
futureInventories.remove(matched);
// Setup the remembered inventory
getCurrentContainer().setup(matched.pos, packet.getWindowId(), packet.getSlotCount());
});
}
if (p instanceof SPacketCloseWindow) {
getCurrent().save();
}
}
}
@Override
public void onBlockInteract(BlockInteractEvent event) {
if (event.getType() == BlockInteractEvent.Type.USE && BlockStateInterface.getBlock(ctx, event.getPos()) instanceof BlockBed) {
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, BetterBlockPos.from(event.getPos())));
}
}
@Override
public void onPlayerDeath() {
Waypoint deathWaypoint = new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet());
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(deathWaypoint);
ITextComponent component = new TextComponentString("Death position saved.");
component.getStyle()
.setColor(TextFormatting.WHITE)
.setHoverEvent(new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new TextComponentString("Click to goto death")
))
.setClickEvent(new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
String.format(
"%s%s goto %s @ %d",
FORCE_COMMAND_PREFIX,
"wp",
deathWaypoint.getTag().getName(),
deathWaypoint.getCreationTimestamp()
)
));
Helper.HELPER.logDirect(component);
}
private void updateInventory() {
if (!Baritone.settings().containerMemory.value) {
return;
}
int windowId = ctx.player().openContainer.windowId;
if (enderChestWindowId != null) {
if (windowId == enderChestWindowId) {
getCurrent().contents = ctx.player().openContainer.getInventory().subList(0, 27);
} else {
getCurrent().save();
enderChestWindowId = null;
}
}
if (getCurrentContainer() != null) {
getCurrentContainer().getInventoryFromWindow(windowId).ifPresent(inventory -> inventory.updateFromOpenWindow(ctx));
}
}
private ContainerMemory getCurrentContainer() {
if (baritone.getWorldProvider().getCurrentWorld() == null) {
return null;
}
return (ContainerMemory) baritone.getWorldProvider().getCurrentWorld().getContainerMemory();
}
private BlockPos neighboringConnectedBlock(BlockPos in) {
BlockStateInterface bsi = baritone.bsi;
Block block = bsi.get0(in).getBlock();
if (block != Blocks.TRAPPED_CHEST && block != Blocks.CHEST) {
return null; // other things that have contents, but can be placed adjacent without combining
}
for (int i = 0; i < 4; i++) {
BlockPos adj = in.offset(EnumFacing.byHorizontalIndex(i));
if (bsi.get0(adj).getBlock() == block) {
return adj;
}
}
return null;
}
/**
* An inventory that we are not yet fully aware of, but are expecting to exist at some point in the future.
*/
private static final class FutureInventory {
/**
* The time that we initially expected the inventory to be provided, in milliseconds
*/
private final long time;
/**
* The amount of slots in the inventory
*/
private final int slots;
/**
* The type of inventory
*/
private final String type;
/**
* The position of the inventory container
*/
private final BlockPos pos;
private FutureInventory(long time, int slots, String type, BlockPos pos) {
this.time = time;
this.slots = slots;
this.type = type;
this.pos = pos;
// betterblockpos has censoring
System.out.println("Future inventory created " + time + " " + slots + " " + type + " " + BetterBlockPos.from(pos));
}
}
public Optional<List<ItemStack>> echest() {
return Optional.ofNullable(getCurrent().contents).map(Collections::unmodifiableList);
}
public EnderChestMemory getCurrent() {
Path path = baritone.getWorldProvider().getCurrentWorld().directory;
return EnderChestMemory.getByServerAndPlayer(path.getParent(), ctx.player().getUniqueID());
}
public static class EnderChestMemory {
private static final Map<Path, EnderChestMemory> memory = new HashMap<>();
private final Path enderChest;
private List<ItemStack> contents;
private EnderChestMemory(Path enderChest) {
this.enderChest = enderChest;
System.out.println("Echest storing in " + enderChest);
try {
this.contents = ContainerMemory.readItemStacks(Files.readAllBytes(enderChest));
} catch (IOException e) {
e.printStackTrace();
System.out.println("CANNOT read echest =( =(");
this.contents = null;
}
}
public synchronized void save() {
System.out.println("Saving");
if (contents != null) {
try {
enderChest.getParent().toFile().mkdir();
Files.write(enderChest, ContainerMemory.writeItemStacks(contents));
} catch (IOException e) {
e.printStackTrace();
System.out.println("CANNOT save echest =( =(");
}
}
}
private static synchronized EnderChestMemory getByServerAndPlayer(Path serverStorage, UUID player) {
return memory.computeIfAbsent(serverStorage.resolve("echests").resolve(player.toString()), EnderChestMemory::new);
}
}
}

View File

@@ -1,183 +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.cache;
import baritone.Baritone;
import baritone.api.cache.IContainerMemory;
import baritone.api.cache.IRememberedInventory;
import baritone.api.utils.IPlayerContext;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.*;
public class ContainerMemory implements IContainerMemory {
private final Path saveTo;
/**
* The current remembered inventories
*/
private final Map<BlockPos, RememberedInventory> inventories = new HashMap<>();
public ContainerMemory(Path saveTo) {
this.saveTo = saveTo;
try {
read(Files.readAllBytes(saveTo));
} catch (NoSuchFileException ignored) {
inventories.clear();
} catch (Exception ex) {
ex.printStackTrace();
inventories.clear();
}
}
private void read(byte[] bytes) throws IOException {
PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes));
int chests = in.readInt();
for (int i = 0; i < chests; i++) {
int x = in.readInt();
int y = in.readInt();
int z = in.readInt();
RememberedInventory rem = new RememberedInventory();
rem.items.addAll(readItemStacks(in));
rem.size = rem.items.size();
rem.windowId = -1;
if (rem.items.isEmpty()) {
continue; // this only happens if the list has no elements, not if the list has elements that are all empty item stacks
}
inventories.put(new BlockPos(x, y, z), rem);
}
}
public synchronized void save() throws IOException {
if (!Baritone.settings().containerMemory.value) {
return;
}
ByteBuf buf = Unpooled.buffer(0, Integer.MAX_VALUE);
PacketBuffer out = new PacketBuffer(buf);
out.writeInt(inventories.size());
for (Map.Entry<BlockPos, RememberedInventory> entry : inventories.entrySet()) {
out = new PacketBuffer(out.writeInt(entry.getKey().getX()));
out = new PacketBuffer(out.writeInt(entry.getKey().getY()));
out = new PacketBuffer(out.writeInt(entry.getKey().getZ()));
out = writeItemStacks(entry.getValue().getContents(), out);
}
Files.write(saveTo, out.array());
}
public synchronized void setup(BlockPos pos, int windowId, int slotCount) {
RememberedInventory inventory = inventories.computeIfAbsent(pos, x -> new RememberedInventory());
inventory.windowId = windowId;
inventory.size = slotCount;
}
public synchronized Optional<RememberedInventory> getInventoryFromWindow(int windowId) {
return inventories.values().stream().filter(i -> i.windowId == windowId).findFirst();
}
@Override
public final synchronized RememberedInventory getInventoryByPos(BlockPos pos) {
return inventories.get(pos);
}
@Override
public final synchronized Map<BlockPos, IRememberedInventory> getRememberedInventories() {
// make a copy since this map is modified from the packet thread
return new HashMap<>(inventories);
}
public static List<ItemStack> readItemStacks(byte[] bytes) throws IOException {
PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes));
return readItemStacks(in);
}
public static List<ItemStack> readItemStacks(PacketBuffer in) throws IOException {
int count = in.readInt();
List<ItemStack> result = new ArrayList<>();
for (int i = 0; i < count; i++) {
result.add(in.readItemStack());
}
return result;
}
public static byte[] writeItemStacks(List<ItemStack> write) {
ByteBuf buf = Unpooled.buffer(0, Integer.MAX_VALUE);
PacketBuffer out = new PacketBuffer(buf);
out = writeItemStacks(write, out);
return out.array();
}
public static PacketBuffer writeItemStacks(List<ItemStack> write, PacketBuffer out2) {
PacketBuffer out = out2; // avoid reassigning an argument LOL
out = new PacketBuffer(out.writeInt(write.size()));
for (ItemStack stack : write) {
out = out.writeItemStack(stack);
}
return out;
}
/**
* An inventory that we are aware of.
* <p>
* Associated with a {@link BlockPos} in {@link ContainerMemory#inventories}.
*/
public static class RememberedInventory implements IRememberedInventory {
/**
* The list of items in the inventory
*/
private final List<ItemStack> items;
/**
* The last known window ID of the inventory
*/
private int windowId;
/**
* The size of the inventory
*/
private int size;
private RememberedInventory() {
this.items = new ArrayList<>();
}
@Override
public final List<ItemStack> getContents() {
return Collections.unmodifiableList(this.items);
}
@Override
public final int getSize() {
return this.size;
}
public void updateFromOpenWindow(IPlayerContext ctx) {
items.clear();
items.addAll(ctx.player().openContainer.getInventory().subList(0, size));
}
}
}

View File

@@ -19,7 +19,6 @@ package baritone.cache;
import baritone.Baritone;
import baritone.api.cache.ICachedWorld;
import baritone.api.cache.IContainerMemory;
import baritone.api.cache.IWaypointCollection;
import baritone.api.cache.IWorldData;
@@ -35,7 +34,6 @@ public class WorldData implements IWorldData {
public final CachedWorld cache;
private final WaypointCollection waypoints;
private final ContainerMemory containerMemory;
//public final MapData map;
public final Path directory;
public final int dimension;
@@ -44,7 +42,6 @@ public class WorldData implements IWorldData {
this.directory = directory;
this.cache = new CachedWorld(directory.resolve("cache"), dimension);
this.waypoints = new WaypointCollection(directory.resolve("waypoints"));
this.containerMemory = new ContainerMemory(directory.resolve("containers"));
this.dimension = dimension;
}
@@ -53,15 +50,6 @@ public class WorldData implements IWorldData {
System.out.println("Started saving the world in a new thread");
cache.save();
});
Baritone.getExecutor().execute(() -> {
System.out.println("Started saving saved containers in a new thread");
try {
containerMemory.save();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Failed to save saved containers");
}
});
}
@Override
@@ -73,9 +61,4 @@ public class WorldData implements IWorldData {
public IWaypointCollection getWaypoints() {
return this.waypoints;
}
@Override
public IContainerMemory getContainerMemory() {
return this.containerMemory;
}
}

View File

@@ -78,7 +78,14 @@ public class WorldProvider implements IWorldProvider, Helper {
directory = new File(directory, "baritone");
readme = directory;
} else { // Otherwise, the server must be remote...
String folderName = mc.getCurrentServerData().serverIP;
String folderName;
if (mc.getCurrentServerData() != null) {
folderName = mc.getCurrentServerData().serverIP;
} else {
//replaymod causes null currentServerData and false singleplayer.
currentWorld = null;
return;
}
if (SystemUtils.IS_OS_WINDOWS) {
folderName = folderName.replace(":", "_");
}

View File

@@ -1,83 +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.cache.IRememberedInventory;
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.utils.BetterBlockPos;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
public class ChestsCommand extends Command {
public ChestsCommand(IBaritone baritone) {
super(baritone, "chests");
}
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
args.requireMax(0);
Set<Map.Entry<BlockPos, IRememberedInventory>> entries =
ctx.worldData().getContainerMemory().getRememberedInventories().entrySet();
if (entries.isEmpty()) {
throw new CommandInvalidStateException("No remembered inventories");
}
for (Map.Entry<BlockPos, IRememberedInventory> entry : entries) {
// betterblockpos has censoring
BetterBlockPos pos = new BetterBlockPos(entry.getKey());
IRememberedInventory inv = entry.getValue();
logDirect(pos.toString());
for (ItemStack item : inv.getContents()) {
ITextComponent component = item.getTextComponent();
component.appendText(String.format(" x %d", item.getCount()));
logDirect(component);
}
}
}
@Override
public Stream<String> tabComplete(String label, IArgConsumer args) {
return Stream.empty();
}
@Override
public String getShortDesc() {
return "Display remembered inventories";
}
@Override
public List<String> getLongDesc() {
return Arrays.asList(
"The chests command lists remembered inventories, I guess?",
"",
"Usage:",
"> chests"
);
}
}

View File

@@ -51,7 +51,6 @@ public final class DefaultCommands {
new TunnelCommand(baritone),
new RenderCommand(baritone),
new FarmCommand(baritone),
new ChestsCommand(baritone),
new FollowCommand(baritone),
new ExploreFilterCommand(baritone),
new ReloadAllCommand(baritone),

View File

@@ -112,7 +112,7 @@ public class ExecutionControlCommands {
);
}
};
resumeCommand = new Command(baritone, "resume", "r") {
resumeCommand = new Command(baritone, "resume", "r", "unpause") {
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
args.requireMax(0);

View File

@@ -72,10 +72,10 @@ public class FindCommand extends Command {
@Override
public List<String> getLongDesc() {
return Arrays.asList(
"",
"The find command searches through Baritone's cache and attempts to find the location of the block.",
"",
"Usage:",
"> "
"> find <block> - Find positions of a certain block"
);
}
}

View File

@@ -17,9 +17,11 @@
package baritone.command.defaults;
import baritone.Baritone;
import baritone.api.IBaritone;
import baritone.api.cache.IWaypoint;
import baritone.api.cache.Waypoint;
import baritone.api.cache.IWorldData;
import baritone.api.command.Command;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.datatypes.ForWaypoints;
@@ -41,12 +43,15 @@ import net.minecraft.util.text.event.HoverEvent;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
public class WaypointsCommand extends Command {
private Map<IWorldData,List<IWaypoint>> deletedWaypoints = new HashMap<>();
public WaypointsCommand(IBaritone baritone) {
super(baritone, "waypoints", "waypoint", "wp");
}
@@ -125,11 +130,13 @@ public class WaypointsCommand extends Command {
);
}
} else if (action == Action.SAVE) {
IWaypoint.Tag tag = IWaypoint.Tag.getByName(args.getString());
IWaypoint.Tag tag = args.hasAny() ? IWaypoint.Tag.getByName(args.peekString()) : null;
if (tag == null) {
throw new CommandInvalidStateException(String.format("'%s' is not a tag ", args.consumedString()));
tag = IWaypoint.Tag.USER;
} else {
args.get();
}
String name = args.hasAny() ? args.getString() : "";
String name = (args.hasExactlyOne() || args.hasExactly(4)) ? args.getString() : "";
BetterBlockPos pos = args.hasAny()
? args.getDatatypePost(RelativeBlockPos.INSTANCE, ctx.playerFeet())
: ctx.playerFeet();
@@ -147,7 +154,42 @@ public class WaypointsCommand extends Command {
for (IWaypoint waypoint : waypoints) {
ForWaypoints.waypoints(this.baritone).removeWaypoint(waypoint);
}
logDirect(String.format("Cleared %d waypoints", waypoints.length));
deletedWaypoints.computeIfAbsent(baritone.getWorldProvider().getCurrentWorld(), k -> new ArrayList<>()).addAll(Arrays.<IWaypoint>asList(waypoints));
ITextComponent textComponent = new TextComponentString(String.format("Cleared %d waypoints, click to restore them", waypoints.length));
textComponent.getStyle().setClickEvent(new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
String.format(
"%s%s restore @ %s",
FORCE_COMMAND_PREFIX,
label,
Stream.of(waypoints).map(wp -> Long.toString(wp.getCreationTimestamp())).collect(Collectors.joining(" "))
)
));
logDirect(textComponent);
} else if (action == Action.RESTORE) {
List<IWaypoint> waypoints = new ArrayList<>();
List<IWaypoint> deletedWaypoints = this.deletedWaypoints.getOrDefault(baritone.getWorldProvider().getCurrentWorld(), Collections.emptyList());
if (args.peekString().equals("@")) {
args.get();
// no args.requireMin(1) because if the user clears an empty tag there is nothing to restore
while (args.hasAny()) {
long timestamp = args.getAs(Long.class);
for (IWaypoint waypoint : deletedWaypoints) {
if (waypoint.getCreationTimestamp() == timestamp) {
waypoints.add(waypoint);
break;
}
}
}
} else {
args.requireExactly(1);
int size = deletedWaypoints.size();
int amount = Math.min(size, args.getAs(Integer.class));
waypoints = new ArrayList<>(deletedWaypoints.subList(size - amount, size));
}
waypoints.forEach(ForWaypoints.waypoints(this.baritone)::addWaypoint);
deletedWaypoints.removeIf(waypoints::contains);
logDirect(String.format("Restored %d waypoints", waypoints.size()));
} else {
IWaypoint[] waypoints = args.getDatatypeFor(ForWaypoints.INSTANCE);
IWaypoint waypoint = null;
@@ -216,6 +258,20 @@ public class WaypointsCommand extends Command {
waypoint.getCreationTimestamp()
)
));
ITextComponent recreateComponent = new TextComponentString("Click to show a command to recreate this waypoint");
recreateComponent.getStyle().setClickEvent(new ClickEvent(
ClickEvent.Action.SUGGEST_COMMAND,
String.format(
"%s%s save %s %s %s %s %s",
Baritone.settings().prefix.value, // This uses the normal prefix because it is run by the user.
label,
waypoint.getTag().getName(),
waypoint.getName(),
waypoint.getLocation().x,
waypoint.getLocation().y,
waypoint.getLocation().z
)
));
ITextComponent backComponent = new TextComponentString("Click to return to the waypoints list");
backComponent.getStyle().setClickEvent(new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
@@ -227,10 +283,22 @@ public class WaypointsCommand extends Command {
));
logDirect(deleteComponent);
logDirect(goalComponent);
logDirect(recreateComponent);
logDirect(backComponent);
} else if (action == Action.DELETE) {
ForWaypoints.waypoints(this.baritone).removeWaypoint(waypoint);
logDirect("That waypoint has successfully been deleted");
deletedWaypoints.computeIfAbsent(baritone.getWorldProvider().getCurrentWorld(), k -> new ArrayList<>()).add(waypoint);
ITextComponent textComponent = new TextComponentString("That waypoint has successfully been deleted, click to restore it");
textComponent.getStyle().setClickEvent(new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
String.format(
"%s%s restore @ %s",
FORCE_COMMAND_PREFIX,
label,
waypoint.getCreationTimestamp()
)
));
logDirect(textComponent);
} else if (action == Action.GOAL) {
Goal goal = new GoalBlock(waypoint.getLocation());
baritone.getCustomGoalProcess().setGoal(goal);
@@ -262,6 +330,8 @@ public class WaypointsCommand extends Command {
.sortAlphabetically()
.filterPrefix(args.getString())
.stream();
} else if (action == Action.RESTORE) {
return Stream.empty();
} else {
return args.tabCompleteDatatype(ForWaypoints.INSTANCE);
}
@@ -289,15 +359,19 @@ public class WaypointsCommand extends Command {
"",
"Note that the info, delete, and goal commands let you specify a waypoint by tag. If there is more than one waypoint with a certain tag, then they will let you select which waypoint you mean.",
"",
"Missing arguments for the save command use the USER tag, creating an unnamed waypoint and your current position as defaults.",
"",
"Usage:",
"> wp [l/list] - List all waypoints.",
"> wp <s/save> <tag> - Save your current position as an unnamed waypoint with the specified tag.",
"> wp <s/save> <tag> <name> - Save the waypoint with the specified name.",
"> wp <s/save> <tag> <name> <pos> - Save the waypoint with the specified name and position.",
"> wp <i/info/show> <tag> - Show info on a waypoint by tag.",
"> wp <d/delete> <tag> - Delete a waypoint by tag.",
"> wp <g/goal> <tag> - Set a goal to a waypoint by tag.",
"> wp <goto> <tag> - Set a goal to a waypoint by tag and start pathing."
"> wp <l/list> <tag> - List all waypoints by tag.",
"> wp <s/save> - Save an unnamed USER waypoint at your current position",
"> wp <s/save> [tag] [name] [pos] - Save a waypoint with the specified tag, name and position.",
"> wp <i/info/show> <tag/name> - Show info on a waypoint by tag or name.",
"> wp <d/delete> <tag/name> - Delete a waypoint by tag or name.",
"> wp <restore> <n> - Restore the last n deleted waypoints.",
"> wp <c/clear> <tag> - Delete all waypoints with the specified tag.",
"> wp <g/goal> <tag/name> - Set a goal to a waypoint by tag or name.",
"> wp <goto> <tag/name> - Set a goal to a waypoint by tag or name and start pathing."
);
}
@@ -307,6 +381,7 @@ public class WaypointsCommand extends Command {
SAVE("save", "s"),
INFO("info", "show", "i"),
DELETE("delete", "d"),
RESTORE("restore"),
GOAL("goal", "g"),
GOTO("goto");
private final String[] names;

View File

@@ -143,7 +143,6 @@ public class CalculationContext {
return COST_INF;
}
if (!worldBorder.canPlaceAt(x, z)) {
// TODO perhaps MovementHelper.canPlaceAgainst could also use this?
return COST_INF;
}
return placeBlockCost;

View File

@@ -56,8 +56,12 @@ import static baritone.pathing.movement.Movement.HORIZONTALS_BUT_ALSO_DOWN_____S
public interface MovementHelper extends ActionCosts, Helper {
static boolean avoidBreaking(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
if (!bsi.worldBorder.canPlaceAt(x, y)) {
return true;
}
Block b = state.getBlock();
return b == Blocks.ICE // ice becomes water, and water can mess up the path
return Baritone.settings().blocksToDisallowBreaking.value.contains(b)
|| b == Blocks.ICE // ice becomes water, and water can mess up the path
|| b instanceof BlockSilverfish // obvious reasons
// call context.get directly with x,y,z. no need to make 5 new BlockPos for no reason
|| avoidAdjacentBreaking(bsi, x, y + 1, z, true)
@@ -141,6 +145,9 @@ public interface MovementHelper extends ActionCosts, Helper {
}
return true;
}
if (block instanceof BlockCauldron) {
return false;
}
// 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
@@ -377,6 +384,9 @@ public interface MovementHelper extends ActionCosts, Helper {
}
static boolean canPlaceAgainst(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
if (!bsi.worldBorder.canPlaceAt(x, z)) {
return false;
}
// can we look at the center of a side face of this block and likely be able to place?
// (thats how this check is used)
// therefore dont include weird things that we technically could place against (like carpet) but practically can't

View File

@@ -45,8 +45,10 @@ import baritone.utils.schematic.MapArtSchematic;
import baritone.utils.schematic.SelectionSchematic;
import baritone.utils.schematic.SchematicSystem;
import baritone.utils.schematic.schematica.SchematicaHelper;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.minecraft.block.BlockAir;
import net.minecraft.block.*;
import net.minecraft.block.BlockFlowingFluid;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
@@ -54,6 +56,7 @@ import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.state.IProperty;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.*;
@@ -849,6 +852,27 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
return result;
}
public static final Set<IProperty<?>> orientationProps =
ImmutableSet.of(BlockRotatedPillar.AXIS, BlockHorizontal.HORIZONTAL_FACING,
BlockStairs.FACING, BlockStairs.HALF, BlockStairs.SHAPE,
BlockPane.NORTH, BlockPane.EAST, BlockPane.SOUTH, BlockPane.WEST, BlockVine.UP,
BlockTrapDoor.OPEN, BlockTrapDoor.HALF
);
private boolean sameWithoutOrientation(IBlockState first, IBlockState second) {
if (first.getBlock() != second.getBlock()) {
return false;
}
ImmutableMap<IProperty<?>, Comparable<?>> map1 = first.getValues();
ImmutableMap<IProperty<?>, Comparable<?>> map2 = second.getValues();
for (IProperty<?> prop : map1.keySet()) {
if (map1.get(prop) != map2.get(prop) && !orientationProps.contains(prop)) {
return false;
}
}
return true;
}
private boolean valid(IBlockState current, IBlockState desired, boolean itemVerify) {
if (desired == null) {
return true;
@@ -874,7 +898,10 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
if (Baritone.settings().buildValidSubstitutes.value.getOrDefault(desired.getBlock(), Collections.emptyList()).contains(current.getBlock()) && !itemVerify) {
return true;
}
return current.equals(desired);
if (current.equals(desired)) {
return true;
}
return Baritone.settings().buildIgnoreDirection.value && sameWithoutOrientation(current, desired);
}
public class BuilderCalculationContext extends CalculationContext {

View File

@@ -22,6 +22,7 @@ import baritone.api.utils.IPlayerContext;
import baritone.cache.CachedRegion;
import baritone.cache.WorldData;
import baritone.utils.accessor.IChunkProviderClient;
import baritone.utils.pathing.BetterWorldBorder;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.block.Block;
@@ -46,6 +47,7 @@ public class BlockStateInterface {
protected final IBlockReader world;
public final BlockPos.MutableBlockPos isPassableBlockPos;
public final IBlockReader access;
public final BetterWorldBorder worldBorder;
private Chunk prev = null;
private CachedRegion prevCached = null;
@@ -64,6 +66,7 @@ public class BlockStateInterface {
public BlockStateInterface(World world, WorldData worldData, boolean copyLoadedChunks) {
this.world = world;
this.worldBorder = new BetterWorldBorder(world.getWorldBorder());
this.worldData = worldData;
Long2ObjectMap<Chunk> worldLoaded = ((IChunkProviderClient) world.getChunkProvider()).loadedChunks();
if (copyLoadedChunks) {

View File

@@ -158,7 +158,7 @@ public class ToolSet {
}
private double avoidanceMultiplier(Block b) {
return Baritone.settings().blocksToAvoidBreaking.value.contains(b) ? 0.1 : 1;
return Baritone.settings().blocksToAvoidBreaking.value.contains(b) ? Baritone.settings().avoidBreakingMultiplier.value : 1;
}
/**