baritone/src/main/java/baritone/utils/BlockStateInterface.java

171 lines
6.4 KiB
Java
Raw Normal View History

2018-08-08 03:16:53 +00:00
/*
* 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
2018-08-08 03:16:53 +00:00
* 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,
2018-08-08 03:16:53 +00:00
* 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.
2018-08-08 03:16:53 +00:00
*
* You should have received a copy of the GNU Lesser General Public License
2018-08-08 03:16:53 +00:00
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
2018-08-22 20:15:56 +00:00
package baritone.utils;
2018-08-22 20:15:56 +00:00
import baritone.Baritone;
2018-11-13 21:14:29 +00:00
import baritone.api.utils.IPlayerContext;
import baritone.cache.CachedRegion;
2018-09-11 17:28:03 +00:00
import baritone.cache.WorldData;
import baritone.utils.accessor.IChunkProviderClient;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
2019-10-22 20:58:10 +00:00
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
2018-08-08 00:41:13 +00:00
import net.minecraft.world.chunk.Chunk;
2018-09-09 15:53:15 +00:00
/**
* Wraps get for chuck caching capability
*
* @author leijurv
*/
2018-11-13 22:33:45 +00:00
public class BlockStateInterface {
private final Long2ObjectMap<Chunk> loadedChunks;
2018-11-12 01:36:54 +00:00
private final WorldData worldData;
protected final IBlockAccess world;
2019-10-22 20:58:10 +00:00
public final BlockPos.MutableBlockPos isPassableBlockPos;
public final IBlockAccess access;
2018-11-12 01:36:54 +00:00
private Chunk prev = null;
private CachedRegion prevCached = null;
2018-09-09 16:50:19 +00:00
2019-01-11 02:55:55 +00:00
private final boolean useTheRealWorld;
2018-10-14 05:23:49 +00:00
private static final IBlockState AIR = Blocks.AIR.getDefaultState();
2018-11-13 21:14:29 +00:00
public BlockStateInterface(IPlayerContext ctx) {
this(ctx, false);
2018-11-13 21:14:29 +00:00
}
public BlockStateInterface(IPlayerContext ctx, boolean copyLoadedChunks) {
this(ctx.world(), (WorldData) ctx.worldData(), copyLoadedChunks);
}
public BlockStateInterface(World world, WorldData worldData, boolean copyLoadedChunks) {
2019-10-22 20:58:10 +00:00
this.world = world;
2018-11-12 01:36:54 +00:00
this.worldData = worldData;
Long2ObjectMap<Chunk> worldLoaded = ((IChunkProviderClient) world.getChunkProvider()).loadedChunks();
if (copyLoadedChunks) {
this.loadedChunks = new Long2ObjectOpenHashMap<>(worldLoaded); // make a copy that we can safely access from another thread
} else {
this.loadedChunks = worldLoaded; // this will only be used on the main thread
}
2019-03-05 05:30:04 +00:00
this.useTheRealWorld = !Baritone.settings().pathThroughCachedOnly.value;
if (!Minecraft.getMinecraft().isCallingFromMinecraftThread()) {
throw new IllegalStateException();
}
2019-10-22 20:58:10 +00:00
this.isPassableBlockPos = new BlockPos.MutableBlockPos();
this.access = new BlockStateInterfaceAccessWrapper(this);
2018-09-09 15:53:15 +00:00
}
2018-11-23 17:03:51 +00:00
public boolean worldContainsLoadedChunk(int blockX, int blockZ) {
return loadedChunks.containsKey(ChunkPos.asLong(blockX >> 4, blockZ >> 4));
}
2018-11-13 21:14:29 +00:00
public static Block getBlock(IPlayerContext ctx, BlockPos pos) { // won't be called from the pathing thread because the pathing thread doesn't make a single blockpos pog
return get(ctx, pos).getBlock();
2018-11-12 01:36:54 +00:00
}
2018-11-13 21:14:29 +00:00
public static IBlockState get(IPlayerContext ctx, BlockPos pos) {
return new BlockStateInterface(ctx).get0(pos.getX(), pos.getY(), pos.getZ()); // immense iq
2018-11-12 02:23:18 +00:00
// can't just do world().get because that doesn't work for out of bounds
// and toBreak and stuff fails when the movement is instantiated out of load range but it's not able to BlockStateInterface.get what it's going to walk on
}
public IBlockState get0(BlockPos pos) {
return get0(pos.getX(), pos.getY(), pos.getZ());
}
2018-11-13 21:14:29 +00:00
public IBlockState get0(int x, int y, int z) { // Mickey resigned
2018-08-08 00:41:13 +00:00
// Invalid vertical position
2018-09-09 15:53:15 +00:00
if (y < 0 || y >= 256) {
2018-09-09 16:50:19 +00:00
return AIR;
2018-09-08 04:32:25 +00:00
}
2018-08-08 00:41:13 +00:00
2019-01-11 02:55:55 +00:00
if (useTheRealWorld) {
Chunk cached = prev;
// there's great cache locality in block state lookups
// generally it's within each movement
// if it's the same chunk as last time
// we can just skip the mc.world.getChunk lookup
// which is a Long2ObjectOpenHashMap.get
2018-09-23 15:05:59 +00:00
// see issue #113
2018-09-09 15:53:15 +00:00
if (cached != null && cached.x == x >> 4 && cached.z == z >> 4) {
return cached.getBlockState(x, y, z);
}
2018-11-23 17:03:51 +00:00
Chunk chunk = loadedChunks.get(ChunkPos.asLong(x >> 4, z >> 4));
2018-11-23 17:03:51 +00:00
if (chunk != null && chunk.isLoaded()) {
prev = chunk;
2018-09-09 15:53:15 +00:00
return chunk.getBlockState(x, y, z);
}
2018-08-14 03:17:16 +00:00
}
2018-09-09 16:50:19 +00:00
// same idea here, skip the Long2ObjectOpenHashMap.get if at all possible
// except here, it's 512x512 tiles instead of 16x16, so even better repetition
CachedRegion cached = prevCached;
2018-09-11 18:56:59 +00:00
if (cached == null || cached.getX() != x >> 9 || cached.getZ() != z >> 9) {
if (worldData == null) {
2018-09-09 16:50:19 +00:00
return AIR;
}
CachedRegion region = worldData.cache.getRegion(x >> 9, z >> 9);
2018-09-11 18:56:59 +00:00
if (region == null) {
return AIR;
2018-08-08 00:41:13 +00:00
}
2018-09-11 18:56:59 +00:00
prevCached = region;
cached = region;
}
IBlockState type = cached.getBlock(x & 511, y, z & 511);
if (type == null) {
return AIR;
2018-08-08 00:41:13 +00:00
}
2018-09-11 18:56:59 +00:00
return type;
}
2018-11-12 01:36:54 +00:00
public boolean isLoaded(int x, int z) {
Chunk prevChunk = prev;
if (prevChunk != null && prevChunk.x == x >> 4 && prevChunk.z == z >> 4) {
return true;
}
2018-11-23 17:03:51 +00:00
prevChunk = loadedChunks.get(ChunkPos.asLong(x >> 4, z >> 4));
if (prevChunk != null && prevChunk.isLoaded()) {
2018-09-24 19:44:34 +00:00
prev = prevChunk;
return true;
}
CachedRegion prevRegion = prevCached;
if (prevRegion != null && prevRegion.getX() == x >> 9 && prevRegion.getZ() == z >> 9) {
return prevRegion.isCached(x & 511, z & 511);
}
2018-11-12 01:36:54 +00:00
if (worldData == null) {
return false;
}
2018-11-12 01:36:54 +00:00
prevRegion = worldData.cache.getRegion(x >> 9, z >> 9);
2018-09-24 19:44:34 +00:00
if (prevRegion == null) {
return false;
}
2018-09-24 19:44:34 +00:00
prevCached = prevRegion;
return prevRegion.isCached(x & 511, z & 511);
}
}