Switch to using an int[] for storing precomputed data, and also use lazy loading

This commit is contained in:
scorbett123 2022-07-14 12:49:47 +01:00
parent 8d480cefb9
commit fdcdcbb85f
2 changed files with 52 additions and 79 deletions

View File

@ -27,27 +27,73 @@ import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.Arrays;
import java.util.Optional; import java.util.Optional;
import static baritone.pathing.movement.MovementHelper.isFlowing; import static baritone.pathing.movement.MovementHelper.isFlowing;
import static baritone.pathing.movement.MovementHelper.isWater; import static baritone.pathing.movement.MovementHelper.isWater;
public class PrecomputedData { // TODO add isFullyPassable public class PrecomputedData { // TODO add isFullyPassable
private final int[] data = new int[Block.BLOCK_STATE_IDS.size()]; // Has to be of type boolean due to otherwise it has a generic type
PrecomputedDataForBlockState canWalkOn; private final int completedMask = 0b1;
PrecomputedDataForBlockState canWalkThrough; private final int canWalkOnMask = 0b10;
private final int canWalkOnSpecialMask = 0b100;
private final int canWalkThroughMask = 0b1000;
private final int canWalkThroughSpecialMask = 0b10000;
public PrecomputedData() { public PrecomputedData() {
canWalkOn = new PrecomputedDataForBlockState(MovementHelper::canWalkOnBlockState, MovementHelper::canWalkOnPosition); Arrays.fill(data, 0);
}
canWalkThrough = new PrecomputedDataForBlockState(MovementHelper::canWalkThroughBlockState, MovementHelper::canWalkThroughPosition); private void fillData(int id, IBlockState state) {
Optional<Boolean> canWalkOnState = MovementHelper.canWalkOnBlockState(state);
if (canWalkOnState.isPresent()) {
if (canWalkOnState.get()) {
data[id] = data[id] | canWalkOnMask;
}
} else {
data[id] = data[id] | canWalkOnSpecialMask;
}
Optional<Boolean> canWalkThroughState = MovementHelper.canWalkThroughBlockState(state);
if (canWalkThroughState.isPresent()) {
if (canWalkThroughState.get()) {
data[id] = data[id] | canWalkThroughMask;
}
} else {
data[id] = data[id] | canWalkThroughSpecialMask;
}
data[id] = data[id] | completedMask;
} }
public boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) { public boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
return canWalkOn.get(bsi, x, y, z, state); int id = Block.BLOCK_STATE_IDS.get(state);
if ((data[id] & completedMask) == 0) { // we need to fill in the data
fillData(id, state);
}
if ((data[id] & canWalkOnSpecialMask) != 0) {
return MovementHelper.canWalkOnPosition(bsi, x, y, z, state);
} else {
return (data[id] & canWalkOnMask) != 0;
}
} }
public boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, IBlockState state) { public boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
return canWalkThrough.get(bsi, x, y, z, state); int id = Block.BLOCK_STATE_IDS.get(state);
if ((data[id] & completedMask) == 0) { // we need to fill in the data
fillData(id, state);
}
if ((data[id] & canWalkThroughSpecialMask) != 0) {
return MovementHelper.canWalkOnPosition(bsi, x, y, z, state);
} else {
return (data[id] & canWalkThroughMask) != 0;
}
} }
} }

View File

@ -1,73 +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.pathing.precompute;
import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.world.IBlockAccess;
import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.Optional;
import java.util.function.Function;
public class PrecomputedDataForBlockState {
boolean[] dataPerBlockState = new boolean[Block.BLOCK_STATE_IDS.size()]; // Has to be of type boolean due to otherwise it has a generic type
boolean[] specialCases = new boolean[Block.BLOCK_STATE_IDS.size()]; // We can also be certain that size will return the highest as it fills in all positions with null until we get to the highest block state
private final SpecialCaseFunction specialCaseHandler;
private final Function<IBlockState, Optional<Boolean>> precomputer;
public PrecomputedDataForBlockState(Function<IBlockState, Optional<Boolean>> precomputer, SpecialCaseFunction specialCaseHandler) {
this.specialCaseHandler = specialCaseHandler;
this.precomputer = precomputer;
this.refresh();
}
public void refresh() {
for (Iterator<IBlockState> it = Block.BLOCK_STATE_IDS.iterator(); it.hasNext(); ) { // Can be replaced with an enhanced for because that breaks github actions for some reason I can't be bothered to dig into
IBlockState state = it.next(); // state should never be null
Optional<Boolean> applied = precomputer.apply(state);
int id = Block.BLOCK_STATE_IDS.get(state);
if (applied.isPresent()) {
dataPerBlockState[id] = applied.get();
specialCases[id] = false;
} else {
dataPerBlockState[id] = false;
specialCases[id] = true;
}
}
}
public boolean get(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
int id = Block.BLOCK_STATE_IDS.get(state);
if (specialCases[id]) {
return specialCaseHandler.apply(bsi, x, y, z, state);
} else {
return dataPerBlockState[id];
}
}
interface SpecialCaseFunction {
public boolean apply(BlockStateInterface bsi, int x, int y, int z, IBlockState blockState);
}
}