rework chunk caching

This commit is contained in:
Leijurv 2018-08-22 11:41:31 -07:00
parent 56975c0e0f
commit 38aad9d92c
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
4 changed files with 78 additions and 53 deletions

View File

@ -43,12 +43,12 @@ public final class CachedChunk implements IBlockTypeAccess {
/** /**
* The chunk x coordinate * The chunk x coordinate
*/ */
private final int x; public final int x;
/** /**
* The chunk z coordinate * The chunk z coordinate
*/ */
private final int z; public final int z;
/** /**
* The actual raw data of this packed chunk. * The actual raw data of this packed chunk.
@ -62,6 +62,8 @@ public final class CachedChunk implements IBlockTypeAccess {
*/ */
private final String[] overview; private final String[] overview;
private final int[] heightMap;
CachedChunk(int x, int z, BitSet data, String[] overview) { CachedChunk(int x, int z, BitSet data, String[] overview) {
validateSize(data); validateSize(data);
@ -69,6 +71,8 @@ public final class CachedChunk implements IBlockTypeAccess {
this.z = z; this.z = z;
this.data = data; this.data = data;
this.overview = overview; this.overview = overview;
this.heightMap = new int[256];
calculateHeightMap();
} }
@Override @Override
@ -77,25 +81,22 @@ public final class CachedChunk implements IBlockTypeAccess {
return PathingBlockType.fromBits(data.get(index), data.get(index + 1)); return PathingBlockType.fromBits(data.get(index), data.get(index + 1));
} }
void updateContents(BitSet data) { private void calculateHeightMap() {
validateSize(data); for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
for (int i = 0; i < data.length(); i++) int index = z << 4 | x;
this.data.set(i, data.get(i)); heightMap[index] = 0;
for (int y = 256; y >= 0; y--) {
if (getBlockType(x, y, z) != PathingBlockType.AIR) {
heightMap[index] = y;
}
}
}
}
} }
/** public final String[] getOverview() {
* @return Thee chunk x coordinat return overview;
*/
public final int getX() {
return this.x;
}
/**
* @return The chunk z coordinate
*/
public final int getZ() {
return this.z;
} }
/** /**

View File

@ -24,6 +24,7 @@ import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
@ -77,13 +78,8 @@ public final class CachedRegion implements IBlockTypeAccess {
return null; return null;
} }
final void updateCachedChunk(int chunkX, int chunkZ, BitSet chunkData, String[] chunkOverview) { final void updateCachedChunk(int chunkX, int chunkZ, CachedChunk chunk) {
CachedChunk chunk = this.getChunk(chunkX, chunkZ); this.chunks[chunkX][chunkZ] = chunk;
if (chunk == null) {
this.chunks[chunkX][chunkZ] = new CachedChunk(chunkX, chunkZ, chunkData, chunkOverview);
} else {
chunk.updateContents(chunkData);
}
hasUnsavedChanges = true; hasUnsavedChanges = true;
} }
@ -135,6 +131,15 @@ public final class CachedRegion implements IBlockTypeAccess {
} }
} }
} }
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
if (chunks[x][z] != null) {
for (int i = 0; i < 256; i++) {
out.writeUTF(chunks[x][z].getOverview()[i]);
}
}
}
}
out.writeInt(~CACHED_REGION_MAGIC); out.writeInt(~CACHED_REGION_MAGIC);
} }
hasUnsavedChanges = false; hasUnsavedChanges = false;
@ -155,6 +160,7 @@ public final class CachedRegion implements IBlockTypeAccess {
return; return;
System.out.println("Loading region " + x + "," + z + " from disk " + path); System.out.println("Loading region " + x + "," + z + " from disk " + path);
long start = System.currentTimeMillis();
try ( try (
FileInputStream fileIn = new FileInputStream(regionFile.toFile()); FileInputStream fileIn = new FileInputStream(regionFile.toFile());
@ -175,12 +181,7 @@ public final class CachedRegion implements IBlockTypeAccess {
case CHUNK_PRESENT: case CHUNK_PRESENT:
byte[] bytes = new byte[CachedChunk.SIZE_IN_BYTES]; byte[] bytes = new byte[CachedChunk.SIZE_IN_BYTES];
in.readFully(bytes); in.readFully(bytes);
BitSet bits = BitSet.valueOf(bytes); this.chunks[x][z] = new CachedChunk(x, z, BitSet.valueOf(bytes), new String[256]);
String[] overview = new String[256];
for(int i = 0; i < 256; i++) {
overview[i] = in.readUTF();
}
updateCachedChunk(x, z, bits, overview);
break; break;
case CHUNK_NOT_PRESENT: case CHUNK_NOT_PRESENT:
this.chunks[x][z] = null; this.chunks[x][z] = null;
@ -190,13 +191,24 @@ public final class CachedRegion implements IBlockTypeAccess {
} }
} }
} }
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
if (chunks[x][z] != null) {
for (int i = 0; i < 256; i++) {
chunks[x][z].getOverview()[i] = in.readUTF();
}
System.out.println(Arrays.asList(chunks[x][z].getOverview()));
}
}
}
int fileEndMagic = in.readInt(); int fileEndMagic = in.readInt();
if (fileEndMagic != ~magic) { if (fileEndMagic != ~magic) {
throw new IOException("Bad end of file magic"); throw new IOException("Bad end of file magic");
} }
} }
hasUnsavedChanges = false; hasUnsavedChanges = false;
System.out.println("Loaded region successfully"); long end = System.currentTimeMillis();
System.out.println("Loaded region successfully in " + (end - start) + "ms");
} catch (IOException ex) { } catch (IOException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }

View File

@ -67,13 +67,17 @@ public final class CachedWorld implements IBlockTypeAccess {
@Override @Override
public final PathingBlockType getBlockType(int x, int y, int z) { public final PathingBlockType getBlockType(int x, int y, int z) {
CachedRegion region = getOrCreateRegion(x >> 9, z >> 9); // no point in doing getOrCreate region, if we don't have it we don't have it
CachedRegion region = getRegion(x >> 9, z >> 9);
if (region == null) {
return null;
}
return region.getBlockType(x & 511, y, z & 511); return region.getBlockType(x & 511, y, z & 511);
} }
private void updateCachedChunk(int chunkX, int chunkZ, BitSet data) { private void updateCachedChunk(CachedChunk chunk) {
CachedRegion region = getOrCreateRegion(chunkX >> 5, chunkZ >> 5); CachedRegion region = getOrCreateRegion(chunk.x >> 5, chunk.z >> 5);
region.updateCachedChunk(chunkX & 31, chunkZ & 31, data, ); region.updateCachedChunk(chunk.x & 31, chunk.z & 31, chunk);
} }
public final void save() { public final void save() {
@ -105,7 +109,7 @@ public final class CachedWorld implements IBlockTypeAccess {
* @param regionZ The region Z coordinate * @param regionZ The region Z coordinate
* @return The region located at the specified coordinates * @return The region located at the specified coordinates
*/ */
CachedRegion getOrCreateRegion(int regionX, int regionZ) { private CachedRegion getOrCreateRegion(int regionX, int regionZ) {
return cachedRegions.computeIfAbsent(getRegionID(regionX, regionZ), id -> { return cachedRegions.computeIfAbsent(getRegionID(regionX, regionZ), id -> {
CachedRegion newRegion = new CachedRegion(regionX, regionZ); CachedRegion newRegion = new CachedRegion(regionX, regionZ);
newRegion.load(this.directory); newRegion.load(this.directory);
@ -157,7 +161,8 @@ public final class CachedWorld implements IBlockTypeAccess {
Chunk chunk = queue.take(); Chunk chunk = queue.take();
BitSet packedChunk = ChunkPacker.createPackedChunk(chunk); BitSet packedChunk = ChunkPacker.createPackedChunk(chunk);
String[] packedOverview = ChunkPacker.createPackedOverview(chunk); String[] packedOverview = ChunkPacker.createPackedOverview(chunk);
CachedWorld.this.updateCachedChunk(chunk.x, chunk.z, packedChunk); CachedChunk cached = new CachedChunk(chunk.x, chunk.z, packedChunk, packedOverview);
CachedWorld.this.updateCachedChunk(cached);
//System.out.println("Processed chunk at " + chunk.x + "," + chunk.z); //System.out.println("Processed chunk at " + chunk.x + "," + chunk.z);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -20,14 +20,13 @@ package baritone.bot.chunk;
import baritone.bot.pathing.movement.MovementHelper; import baritone.bot.pathing.movement.MovementHelper;
import baritone.bot.utils.BlockStateInterface; import baritone.bot.utils.BlockStateInterface;
import baritone.bot.utils.Helper; import baritone.bot.utils.Helper;
import baritone.bot.utils.pathing.BetterBlockPos;
import baritone.bot.utils.pathing.PathingBlockType; import baritone.bot.utils.pathing.PathingBlockType;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockAir; import net.minecraft.block.BlockAir;
import net.minecraft.block.BlockDoublePlant;
import net.minecraft.block.BlockTallGrass;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockPos.MutableBlockPos;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import java.util.BitSet; import java.util.BitSet;
@ -48,7 +47,7 @@ public final class ChunkPacker implements Helper {
for (int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
int index = CachedChunk.getPositionIndex(x, y, z); int index = CachedChunk.getPositionIndex(x, y, z);
boolean[] bits = getPathingBlockType(new BlockPos(x, y, z), chunk.getBlockState(x, y, z)).getBits(); boolean[] bits = getPathingBlockType(chunk.getBlockState(x, y, z).getBlock()).getBits();
bitSet.set(index, bits[0]); bitSet.set(index, bits[0]);
bitSet.set(index + 1, bits[1]); bitSet.set(index + 1, bits[1]);
} }
@ -65,26 +64,30 @@ public final class ChunkPacker implements Helper {
public static String[] createPackedOverview(Chunk chunk) { public static String[] createPackedOverview(Chunk chunk) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
String[] blockNames = new String[256]; String[] blockNames = new String[256];
for(int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
for(int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
int height = chunk.getHeightValue(x, z); int height = chunk.getHeightValue(x, z);
IBlockState blockState = chunk.getBlockState(x, height, z); IBlockState blockState = chunk.getBlockState(x, height, z);
for(int y = height; y > 0; y--) { for (int y = height; y > 0; y--) {
blockState = chunk.getBlockState(x, y, z); blockState = chunk.getBlockState(x, y, z);
if(blockState.getBlock() != Blocks.AIR) { if (getPathingBlockType(blockState.getBlock()) != PathingBlockType.AIR) {
break; break;
} }
} }
blockNames[z << 4 | x] = blockState.getBlock().getLocalizedName(); ResourceLocation loc = Block.REGISTRY.getNameForObject(blockState.getBlock());
String name = loc.getPath(); // normally, only write the part after the minecraft:
if (!loc.getNamespace().equals("minecraft")) {
// Baritone is running on top of forge with mods installed, perhaps?
name = loc.toString(); // include the namespace with the colon
}
blockNames[z << 4 | x] = name;
} }
} }
long end = System.currentTimeMillis(); long end = System.currentTimeMillis();
return blockNames; return blockNames;
} }
private static PathingBlockType getPathingBlockType(BlockPos pos, IBlockState state) { private static PathingBlockType getPathingBlockType(Block block) {
Block block = state.getBlock();
if (BlockStateInterface.isWater(block)) { if (BlockStateInterface.isWater(block)) {
return PathingBlockType.WATER; return PathingBlockType.WATER;
} }
@ -93,7 +96,11 @@ public final class ChunkPacker implements Helper {
return PathingBlockType.AVOID; return PathingBlockType.AVOID;
} }
if (block instanceof BlockAir) { // We used to do an AABB check here
// however, this failed in the nether when you were near a nether fortress
// because fences check their adjacent blocks in the world for their fence connection status to determine AABB shape
// this caused a nullpointerexception when we saved chunks on unload, because they were unable to check their neighbors
if (block instanceof BlockAir || block instanceof BlockTallGrass || block instanceof BlockDoublePlant) {
return PathingBlockType.AIR; return PathingBlockType.AIR;
} }