Skip to content

Commit

Permalink
Implement towering
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexProgrammerDE committed Oct 18, 2023
1 parent dcc2ffe commit 455636a
Show file tree
Hide file tree
Showing 6 changed files with 431 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class Costs {
// We don't want a bot that tries to break blocks instead of walking around them
public static final double BREAK_BLOCK_ADDITION = 2;
public static final double PLACE_BLOCK = 5;
public static final double JUMP_UP_AND_PLACE_BELOW = JUMP + PLACE_BLOCK;
// Sliding around a corner is roughly like walking two blocks
public static final double CORNER_SLIDE = 2 - DIAGONAL;
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class BlockPlaceAction implements WorldAction {
private final Vector3i blockPosition;
private final BotActionManager.BlockPlaceData blockPlaceData;
private boolean putOnHotbar = false;
private boolean finishedPlacing = false;

@Override
public boolean isCompleted(BotConnection connection) {
Expand Down Expand Up @@ -141,7 +142,12 @@ public void tick(BotConnection connection) {
throw new IllegalStateException("Failed to find item stack");
}

if (finishedPlacing) {
return;
}

connection.sessionDataManager().getBotActionManager().placeBlock(Hand.MAIN_HAND, blockPlaceData);
finishedPlacing = true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public class GapJumpAction implements WorldAction {
private final Vector3d position;
private boolean didLook = false;
private int noJumpTicks = 0;
private boolean didJump = false;

@Override
public boolean isCompleted(BotConnection connection) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* ServerWrecker
*
* Copyright (C) 2023 ServerWrecker
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
*/
package net.pistonmaster.serverwrecker.pathfinding.execution;

import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import net.pistonmaster.serverwrecker.data.BlockItems;
import net.pistonmaster.serverwrecker.protocol.BotConnection;
import net.pistonmaster.serverwrecker.protocol.bot.BotActionManager;
import net.pistonmaster.serverwrecker.protocol.bot.container.SWItemStack;
import net.pistonmaster.serverwrecker.util.BlockTypeHelper;
import net.pistonmaster.serverwrecker.util.ItemTypeHelper;
import net.pistonmaster.serverwrecker.util.TimeUtil;
import org.cloudburstmc.math.vector.Vector3i;

import java.util.concurrent.TimeUnit;

@ToString
@RequiredArgsConstructor
public class JumpAndPlaceBelowAction implements WorldAction {
private final Vector3i blockPosition;
private final BotActionManager.BlockPlaceData blockPlaceData;
private boolean putOnHotbar = false;
private boolean finishedPlacing = false;

@Override
public boolean isCompleted(BotConnection connection) {
var levelState = connection.sessionDataManager().getCurrentLevel();
if (levelState == null) {
return false;
}

return levelState.getBlockStateAt(blockPosition)
.map(BlockTypeHelper::isFullBlock)
.orElse(false);
}

@Override
public void tick(BotConnection connection) {
var sessionDataManager = connection.sessionDataManager();
var movementManager = sessionDataManager.getBotMovementManager();
movementManager.getControlState().resetAll();

if (!putOnHotbar) {
var inventoryManager = sessionDataManager.getInventoryManager();
var playerInventory = inventoryManager.getPlayerInventory();

SWItemStack leastHardItem = null;
var leastHardness = 0F;
for (var slot : playerInventory.getStorage()) {
if (slot.item() == null) {
continue;
}

var item = slot.item();
var blockType = BlockItems.getBlockType(item.getType());
if (blockType.isEmpty()) {
continue;
}

if (leastHardItem == null || blockType.get().hardness() < leastHardness) {
leastHardItem = item;
leastHardness = blockType.get().hardness();
}
}

var heldSlot = playerInventory.getHotbarSlot(inventoryManager.getHeldItemSlot());
if (heldSlot.item() != null) {
var item = heldSlot.item();
if (ItemTypeHelper.isSafeFullBlockItem(item.getType())) {
putOnHotbar = true;
return;
}
}

for (var hotbarSlot : playerInventory.getHotbar()) {
if (hotbarSlot.item() == null) {
continue;
}

var item = hotbarSlot.item();
if (!ItemTypeHelper.isSafeFullBlockItem(item.getType())) {
continue;
}

inventoryManager.setHeldItemSlot(playerInventory.toHotbarIndex(hotbarSlot));
inventoryManager.sendHeldItemChange();
putOnHotbar = true;
return;
}

for (var slot : playerInventory.getMainInventory()) {
if (slot.item() == null) {
continue;
}

var item = slot.item();
if (!ItemTypeHelper.isSafeFullBlockItem(item.getType())) {
continue;
}

if (!inventoryManager.tryInventoryControl()) {
return;
}

try {
inventoryManager.leftClickSlot(slot.slot());
TimeUtil.waitTime(50, TimeUnit.MILLISECONDS);
inventoryManager.leftClickSlot(playerInventory.getHotbarSlot(inventoryManager.getHeldItemSlot()).slot());
TimeUtil.waitTime(50, TimeUnit.MILLISECONDS);

if (inventoryManager.getCursorItem() != null) {
inventoryManager.leftClickSlot(slot.slot());
TimeUtil.waitTime(50, TimeUnit.MILLISECONDS);
}
} finally {
inventoryManager.unlockInventoryControl();
}

putOnHotbar = true;
return;
}

throw new IllegalStateException("Failed to find item stack");
}

if (finishedPlacing) {
return;
}

if (movementManager.getY() <= blockPosition.getY() + 1) {
// Make sure we are so high that we can place the block
movementManager.getControlState().setJumping(true);
return;
} else {
movementManager.getControlState().setJumping(false);
}

connection.sessionDataManager().getBotActionManager().placeBlock(Hand.MAIN_HAND, blockPlaceData);
finishedPlacing = true;
}

@Override
public int getAllowedTicks() {
// 3-seconds max to place a block
return 3 * 20;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import net.pistonmaster.serverwrecker.pathfinding.graph.actions.parkour.ParkourDirection;
import net.pistonmaster.serverwrecker.pathfinding.graph.actions.parkour.ParkourMovement;
import net.pistonmaster.serverwrecker.pathfinding.graph.actions.updown.DownMovement;
import net.pistonmaster.serverwrecker.pathfinding.graph.actions.updown.UpMovement;
import net.pistonmaster.serverwrecker.protocol.bot.BotActionManager;
import net.pistonmaster.serverwrecker.protocol.bot.block.BlockStateMeta;
import net.pistonmaster.serverwrecker.protocol.bot.state.tag.TagsState;
Expand Down Expand Up @@ -82,6 +83,12 @@ public record MinecraftGraph(TagsState tagsState) {
actions.size()
));

actions.add(registerUpMovement(
blockSubscribers,
new UpMovement(),
actions.size()
));

ACTIONS_TEMPLATE = actions.toArray(new GraphAction[0]);
SUBSCRIPTION_KEYS = new Vector3i[blockSubscribers.size()];
SUBSCRIPTION_VALUES = new BlockSubscription[blockSubscribers.size()][];
Expand Down Expand Up @@ -310,6 +317,70 @@ public GraphInstructions[] getActions(BotEntityState node) {
}
}
}
} else if (action instanceof UpMovement upMovement) {
switch (subscriber.type) {
case MOVEMENT_FREE -> {
if (!calculatedFree) {
// We can walk through blocks like air or grass
isFree = blockState.blockShapeType().hasNoCollisions()
&& !BlockTypeHelper.isFluid(blockState.blockType());
calculatedFree = true;
}

if (isFree) {
upMovement.getNoNeedToBreak()[subscriber.blockArrayIndex] = true;
continue;
}

// Search for a way to break this block
if (blockState.blockType().diggable()
&& !upMovement.getUnsafeToBreak()[subscriber.blockArrayIndex]
&& BlockItems.hasItemType(blockState.blockType())) {
var cacheableMiningCost = node.inventory()
.getMiningCosts(tagsState, blockState);
// We can mine this block, lets add costs and continue
upMovement.getBlockBreakCosts()[subscriber.blockArrayIndex] = new MovementMiningCost(
absolutePositionBlock,
cacheableMiningCost.miningCost(),
cacheableMiningCost.willDrop()
);
} else {
// No way to break this block
upMovement.setImpossible(true);
}
}
case MOVEMENT_BREAK_SAFETY_CHECK -> {
// There is no need to break this block, so there is no need for safety checks
if (upMovement.getNoNeedToBreak()[subscriber.blockArrayIndex]) {
continue;
}

// The block was already marked as unsafe
if (upMovement.getUnsafeToBreak()[subscriber.blockArrayIndex]) {
continue;
}

var unsafe = switch (subscriber.safetyType) {
case FALLING_AND_FLUIDS -> BlockTypeHelper.isFluid(blockState.blockType())
|| BlockTypeHelper.isFallingAroundMinedBlock(blockState.blockType());
case FLUIDS -> BlockTypeHelper.isFluid(blockState.blockType());
};

if (unsafe) {
var currentValue = upMovement.getBlockBreakCosts()[subscriber.blockArrayIndex];

if (currentValue == null) {
// Store for a later time that this is unsafe,
// so if we check this block,
// we know it's unsafe
upMovement.getUnsafeToBreak()[subscriber.blockArrayIndex] = true;
} else {
// We learned that this block needs to be broken, so we need to set it as impossible
upMovement.setImpossible(true);
}
}
}
}
}
}
}
Expand Down Expand Up @@ -418,6 +489,34 @@ private static DownMovement registerDownMovement(Object2ObjectMap<Vector3i, Obje
return movement;
}

private static UpMovement registerUpMovement(Object2ObjectMap<Vector3i, ObjectList<BlockSubscription>> blockSubscribers,
UpMovement movement, int movementIndex) {
{
var blockId = 0;
for (var freeBlock : movement.listRequiredFreeBlocks()) {
blockSubscribers.computeIfAbsent(freeBlock, CREATE_MISSING_FUNCTION)
.add(new BlockSubscription(movementIndex, SubscriptionType.MOVEMENT_FREE, blockId++));
}
}

{
var safeBlocks = movement.listCheckSafeMineBlocks();
for (var i = 0; i < safeBlocks.length; i++) {
var savedBlock = safeBlocks[i];
if (savedBlock == null) {
continue;
}

for (var block : savedBlock) {
blockSubscribers.computeIfAbsent(block.position(), CREATE_MISSING_FUNCTION)
.add(new BlockSubscription(movementIndex, SubscriptionType.MOVEMENT_BREAK_SAFETY_CHECK, i, block.type()));
}
}
}

return movement;
}

enum SubscriptionType {
MOVEMENT_FREE,
MOVEMENT_BREAK_SAFETY_CHECK,
Expand Down
Loading

0 comments on commit 455636a

Please sign in to comment.