baritone/src/main/java/baritone/pathing/movement/CalculationContext.java

182 lines
7.6 KiB
Java

/*
* 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.pathing.movement;
import baritone.Baritone;
import baritone.api.IBaritone;
import baritone.api.pathing.movement.ActionCosts;
import baritone.cache.WorldData;
import baritone.pathing.precompute.PrecomputedData;
import baritone.utils.BlockStateInterface;
import baritone.utils.ToolSet;
import baritone.utils.pathing.BetterWorldBorder;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import java.util.ArrayList;
import java.util.List;
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
/**
* @author Brady
* @since 8/7/2018
*/
public class CalculationContext {
private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET);
public final boolean safeForThreadedUse;
public final IBaritone baritone;
public final Level world;
public final WorldData worldData;
public final BlockStateInterface bsi;
public final ToolSet toolSet;
public final boolean hasWaterBucket;
public final boolean hasThrowaway;
public final boolean canSprint;
protected final double placeBlockCost; // protected because you should call the function instead
public final boolean allowBreak;
public final List<Block> allowBreakAnyway;
public final boolean allowParkour;
public final boolean allowParkourPlace;
public final boolean allowJumpAt256;
public final boolean allowParkourAscend;
public final boolean assumeWalkOnWater;
public final int frostWalker;
public final boolean allowDiagonalDescend;
public final boolean allowDiagonalAscend;
public final boolean allowDownward;
public final int maxFallHeightNoWater;
public final int maxFallHeightBucket;
public final double waterWalkSpeed;
public final double breakBlockAdditionalCost;
public double backtrackCostFavoringCoefficient;
public double jumpPenalty;
public final double walkOnWaterOnePenalty;
public final BetterWorldBorder worldBorder;
public final PrecomputedData precomputedData;
public CalculationContext(IBaritone baritone) {
this(baritone, false);
}
public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) {
this.precomputedData = new PrecomputedData();
this.safeForThreadedUse = forUseOnAnotherThread;
this.baritone = baritone;
LocalPlayer player = baritone.getPlayerContext().player();
this.world = baritone.getPlayerContext().world();
this.worldData = (WorldData) baritone.getWorldProvider().getCurrentWorld();
this.bsi = new BlockStateInterface(world, worldData, forUseOnAnotherThread);
this.toolSet = new ToolSet(player);
this.hasThrowaway = Baritone.settings().allowPlace.value && ((Baritone) baritone).getInventoryBehavior().hasGenericThrowaway();
this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.value && Inventory.isHotbarSlot(player.getInventory().findSlotMatchingItem(STACK_BUCKET_WATER)) && world.dimension() != Level.NETHER;
this.canSprint = Baritone.settings().allowSprint.value && player.getFoodData().getFoodLevel() > 6;
this.placeBlockCost = Baritone.settings().blockPlacementPenalty.value;
this.allowBreak = Baritone.settings().allowBreak.value;
this.allowBreakAnyway = new ArrayList<>(Baritone.settings().allowBreakAnyway.value);
this.allowParkour = Baritone.settings().allowParkour.value;
this.allowParkourPlace = Baritone.settings().allowParkourPlace.value;
this.allowJumpAt256 = Baritone.settings().allowJumpAt256.value;
this.allowParkourAscend = Baritone.settings().allowParkourAscend.value;
this.assumeWalkOnWater = Baritone.settings().assumeWalkOnWater.value;
this.frostWalker = EnchantmentHelper.getEnchantmentLevel(Enchantments.FROST_WALKER, baritone.getPlayerContext().player());
this.allowDiagonalDescend = Baritone.settings().allowDiagonalDescend.value;
this.allowDiagonalAscend = Baritone.settings().allowDiagonalAscend.value;
this.allowDownward = Baritone.settings().allowDownward.value;
this.maxFallHeightNoWater = Baritone.settings().maxFallHeightNoWater.value;
this.maxFallHeightBucket = Baritone.settings().maxFallHeightBucket.value;
int depth = EnchantmentHelper.getDepthStrider(player);
if (depth > 3) {
depth = 3;
}
float mult = depth / 3.0F;
this.waterWalkSpeed = ActionCosts.WALK_ONE_IN_WATER_COST * (1 - mult) + ActionCosts.WALK_ONE_BLOCK_COST * mult;
this.breakBlockAdditionalCost = Baritone.settings().blockBreakAdditionalPenalty.value;
this.backtrackCostFavoringCoefficient = Baritone.settings().backtrackCostFavoringCoefficient.value;
this.jumpPenalty = Baritone.settings().jumpPenalty.value;
this.walkOnWaterOnePenalty = Baritone.settings().walkOnWaterOnePenalty.value;
// why cache these things here, why not let the movements just get directly from settings?
// because if some movements are calculated one way and others are calculated another way,
// then you get a wildly inconsistent path that isn't optimal for either scenario.
this.worldBorder = new BetterWorldBorder(world.getWorldBorder());
}
public final IBaritone getBaritone() {
return baritone;
}
public BlockState get(int x, int y, int z) {
return bsi.get0(x, y, z); // laughs maniacally
}
public boolean isLoaded(int x, int z) {
return bsi.isLoaded(x, z);
}
public BlockState get(BlockPos pos) {
return get(pos.getX(), pos.getY(), pos.getZ());
}
public Block getBlock(int x, int y, int z) {
return get(x, y, z).getBlock();
}
public double costOfPlacingAt(int x, int y, int z, BlockState current) {
if (!hasThrowaway) { // only true if allowPlace is true, see constructor
return COST_INF;
}
if (isPossiblyProtected(x, y, z)) {
return COST_INF;
}
if (!worldBorder.canPlaceAt(x, z)) {
return COST_INF;
}
return placeBlockCost;
}
public double breakCostMultiplierAt(int x, int y, int z, BlockState current) {
if (!allowBreak && !allowBreakAnyway.contains(current.getBlock())) {
return COST_INF;
}
if (isPossiblyProtected(x, y, z)) {
return COST_INF;
}
return 1;
}
public double placeBucketCost() {
return placeBlockCost; // shrug
}
public boolean isPossiblyProtected(int x, int y, int z) {
// TODO more protection logic here; see #220
return false;
}
}