cached chunks expiration setting, fixes #181
This commit is contained in:
parent
1b2304146b
commit
de6d6c8714
@ -404,6 +404,12 @@ public class Settings {
|
|||||||
*/
|
*/
|
||||||
public Setting<Integer> followRadius = new Setting<>(3);
|
public Setting<Integer> followRadius = new Setting<>(3);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached chunks (regardless of if they're in RAM or saved to disk) expire and are deleted after this number of seconds
|
||||||
|
* -1 to disable
|
||||||
|
*/
|
||||||
|
public Setting<Long> cachedChunksExpirySeconds = new Setting<>(-1L);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The function that is called when Baritone will log to chat. This function can be added to
|
* The function that is called when Baritone will log to chat. This function can be added to
|
||||||
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
|
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
|
||||||
|
@ -106,7 +106,9 @@ public final class CachedChunk implements IBlockTypeAccess, Helper {
|
|||||||
|
|
||||||
private final Map<String, List<BlockPos>> specialBlockLocations;
|
private final Map<String, List<BlockPos>> specialBlockLocations;
|
||||||
|
|
||||||
CachedChunk(int x, int z, BitSet data, IBlockState[] overview, Map<String, List<BlockPos>> specialBlockLocations) {
|
public final long cacheTimestamp;
|
||||||
|
|
||||||
|
CachedChunk(int x, int z, BitSet data, IBlockState[] overview, Map<String, List<BlockPos>> specialBlockLocations, long cacheTimestamp) {
|
||||||
validateSize(data);
|
validateSize(data);
|
||||||
|
|
||||||
this.x = x;
|
this.x = x;
|
||||||
@ -115,6 +117,7 @@ public final class CachedChunk implements IBlockTypeAccess, Helper {
|
|||||||
this.overview = overview;
|
this.overview = overview;
|
||||||
this.heightMap = new int[256];
|
this.heightMap = new int[256];
|
||||||
this.specialBlockLocations = specialBlockLocations;
|
this.specialBlockLocations = specialBlockLocations;
|
||||||
|
this.cacheTimestamp = cacheTimestamp;
|
||||||
calculateHeightMap();
|
calculateHeightMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
90
src/main/java/baritone/cache/CachedRegion.java
vendored
90
src/main/java/baritone/cache/CachedRegion.java
vendored
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
package baritone.cache;
|
package baritone.cache;
|
||||||
|
|
||||||
|
import baritone.Baritone;
|
||||||
import baritone.api.cache.ICachedRegion;
|
import baritone.api.cache.ICachedRegion;
|
||||||
import net.minecraft.block.state.IBlockState;
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@ -112,6 +113,7 @@ public final class CachedRegion implements ICachedRegion {
|
|||||||
if (!hasUnsavedChanges) {
|
if (!hasUnsavedChanges) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
removeExpired();
|
||||||
try {
|
try {
|
||||||
Path path = Paths.get(directory);
|
Path path = Paths.get(directory);
|
||||||
if (!Files.exists(path)) {
|
if (!Files.exists(path)) {
|
||||||
@ -129,8 +131,8 @@ public final class CachedRegion implements ICachedRegion {
|
|||||||
DataOutputStream out = new DataOutputStream(gzipOut)
|
DataOutputStream out = new DataOutputStream(gzipOut)
|
||||||
) {
|
) {
|
||||||
out.writeInt(CACHED_REGION_MAGIC);
|
out.writeInt(CACHED_REGION_MAGIC);
|
||||||
for (int z = 0; z < 32; z++) {
|
for (int x = 0; x < 32; x++) {
|
||||||
for (int x = 0; x < 32; x++) {
|
for (int z = 0; z < 32; z++) {
|
||||||
CachedChunk chunk = this.chunks[x][z];
|
CachedChunk chunk = this.chunks[x][z];
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
out.write(CHUNK_NOT_PRESENT);
|
out.write(CHUNK_NOT_PRESENT);
|
||||||
@ -143,8 +145,8 @@ public final class CachedRegion implements ICachedRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int z = 0; z < 32; z++) {
|
for (int x = 0; x < 32; x++) {
|
||||||
for (int x = 0; x < 32; x++) {
|
for (int z = 0; z < 32; z++) {
|
||||||
if (chunks[x][z] != null) {
|
if (chunks[x][z] != null) {
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < 256; i++) {
|
||||||
out.writeUTF(ChunkPacker.blockToString(chunks[x][z].getOverview()[i].getBlock()));
|
out.writeUTF(ChunkPacker.blockToString(chunks[x][z].getOverview()[i].getBlock()));
|
||||||
@ -152,8 +154,8 @@ public final class CachedRegion implements ICachedRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int z = 0; z < 32; z++) {
|
for (int x = 0; x < 32; x++) {
|
||||||
for (int x = 0; x < 32; x++) {
|
for (int z = 0; z < 32; z++) {
|
||||||
if (chunks[x][z] != null) {
|
if (chunks[x][z] != null) {
|
||||||
Map<String, List<BlockPos>> locs = chunks[x][z].getRelativeBlocks();
|
Map<String, List<BlockPos>> locs = chunks[x][z].getRelativeBlocks();
|
||||||
out.writeShort(locs.entrySet().size());
|
out.writeShort(locs.entrySet().size());
|
||||||
@ -168,10 +170,17 @@ public final class CachedRegion implements ICachedRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (int x = 0; x < 32; x++) {
|
||||||
|
for (int z = 0; z < 32; z++) {
|
||||||
|
if (chunks[x][z] != null) {
|
||||||
|
out.writeLong(chunks[x][z].cacheTimestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hasUnsavedChanges = false;
|
hasUnsavedChanges = false;
|
||||||
System.out.println("Saved region successfully");
|
System.out.println("Saved region successfully");
|
||||||
} catch (IOException ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,42 +212,42 @@ public final class CachedRegion implements ICachedRegion {
|
|||||||
// by switching on the magic value, and either loading it normally, or loading through a converter.
|
// by switching on the magic value, and either loading it normally, or loading through a converter.
|
||||||
throw new IOException("Bad magic value " + magic);
|
throw new IOException("Bad magic value " + magic);
|
||||||
}
|
}
|
||||||
CachedChunk[][] tmpCached = new CachedChunk[32][32];
|
boolean[][] present = new boolean[32][32];
|
||||||
|
BitSet[][] bitSets = new BitSet[32][32];
|
||||||
Map<String, List<BlockPos>>[][] location = new Map[32][32];
|
Map<String, List<BlockPos>>[][] location = new Map[32][32];
|
||||||
for (int z = 0; z < 32; z++) {
|
IBlockState[][][] overview = new IBlockState[32][32][];
|
||||||
for (int x = 0; x < 32; x++) {
|
long[][] cacheTimestamp = new long[32][32];
|
||||||
|
for (int x = 0; x < 32; x++) {
|
||||||
|
for (int z = 0; z < 32; z++) {
|
||||||
int isChunkPresent = in.read();
|
int isChunkPresent = in.read();
|
||||||
switch (isChunkPresent) {
|
switch (isChunkPresent) {
|
||||||
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);
|
||||||
|
bitSets[x][z] = BitSet.valueOf(bytes);
|
||||||
location[x][z] = new HashMap<>();
|
location[x][z] = new HashMap<>();
|
||||||
int regionX = this.x;
|
overview[x][z] = new IBlockState[256];
|
||||||
int regionZ = this.z;
|
present[x][z] = true;
|
||||||
int chunkX = x + 32 * regionX;
|
|
||||||
int chunkZ = z + 32 * regionZ;
|
|
||||||
tmpCached[x][z] = new CachedChunk(chunkX, chunkZ, BitSet.valueOf(bytes), new IBlockState[256], location[x][z]);
|
|
||||||
break;
|
break;
|
||||||
case CHUNK_NOT_PRESENT:
|
case CHUNK_NOT_PRESENT:
|
||||||
tmpCached[x][z] = null;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IOException("Malformed stream");
|
throw new IOException("Malformed stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int z = 0; z < 32; z++) {
|
for (int x = 0; x < 32; x++) {
|
||||||
for (int x = 0; x < 32; x++) {
|
for (int z = 0; z < 32; z++) {
|
||||||
if (tmpCached[x][z] != null) {
|
if (present[x][z]) {
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < 256; i++) {
|
||||||
tmpCached[x][z].getOverview()[i] = ChunkPacker.stringToBlock(in.readUTF()).getDefaultState();
|
overview[x][z][i] = ChunkPacker.stringToBlock(in.readUTF()).getDefaultState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int z = 0; z < 32; z++) {
|
for (int x = 0; x < 32; x++) {
|
||||||
for (int x = 0; x < 32; x++) {
|
for (int z = 0; z < 32; z++) {
|
||||||
if (tmpCached[x][z] != null) {
|
if (present[x][z]) {
|
||||||
// 16 * 16 * 256 = 65536 so a short is enough
|
// 16 * 16 * 256 = 65536 so a short is enough
|
||||||
// ^ haha jokes on leijurv, java doesn't have unsigned types so that isn't correct
|
// ^ haha jokes on leijurv, java doesn't have unsigned types so that isn't correct
|
||||||
// also why would you have more than 32767 special blocks in a chunk
|
// also why would you have more than 32767 special blocks in a chunk
|
||||||
@ -264,21 +273,52 @@ public final class CachedRegion implements ICachedRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (int x = 0; x < 32; x++) {
|
||||||
|
for (int z = 0; z < 32; z++) {
|
||||||
|
if (present[x][z]) {
|
||||||
|
cacheTimestamp[x][z] = in.readLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// only if the entire file was uncorrupted do we actually set the chunks
|
// only if the entire file was uncorrupted do we actually set the chunks
|
||||||
for (int x = 0; x < 32; x++) {
|
for (int x = 0; x < 32; x++) {
|
||||||
for (int z = 0; z < 32; z++) {
|
for (int z = 0; z < 32; z++) {
|
||||||
this.chunks[x][z] = tmpCached[x][z];
|
if (present[x][z]) {
|
||||||
|
int regionX = this.x;
|
||||||
|
int regionZ = this.z;
|
||||||
|
int chunkX = x + 32 * regionX;
|
||||||
|
int chunkZ = z + 32 * regionZ;
|
||||||
|
this.chunks[x][z] = new CachedChunk(chunkX, chunkZ, bitSets[x][z], overview[x][z], location[x][z], cacheTimestamp[x][z]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
removeExpired();
|
||||||
hasUnsavedChanges = false;
|
hasUnsavedChanges = false;
|
||||||
long end = System.nanoTime() / 1000000L;
|
long end = System.nanoTime() / 1000000L;
|
||||||
System.out.println("Loaded region successfully in " + (end - start) + "ms");
|
System.out.println("Loaded region successfully in " + (end - start) + "ms");
|
||||||
} catch (IOException ex) {
|
} catch (Exception ex) { // corrupted files can cause NullPointerExceptions as well as IOExceptions
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized final void removeExpired() {
|
||||||
|
long expiry = Baritone.settings().cachedChunksExpirySeconds.get();
|
||||||
|
if (expiry < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long oldestAcceptableAge = now - expiry * 1000L;
|
||||||
|
for (int x = 0; x < 32; x++) {
|
||||||
|
for (int z = 0; z < 32; z++) {
|
||||||
|
if (this.chunks[x][z] != null && this.chunks[x][z].cacheTimestamp < oldestAcceptableAge) {
|
||||||
|
System.out.println("Removing chunk " + (x + 32 * this.x) + "," + (z + 32 * this.z) + " because it was cached " + (now - this.chunks[x][z].cacheTimestamp) / 1000L + " seconds ago, and max age is " + expiry);
|
||||||
|
this.chunks[x][z] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The region x coordinate
|
* @return The region x coordinate
|
||||||
*/
|
*/
|
||||||
|
@ -142,6 +142,7 @@ public final class CachedWorld implements ICachedWorld, Helper {
|
|||||||
public final void save() {
|
public final void save() {
|
||||||
if (!Baritone.settings().chunkCaching.get()) {
|
if (!Baritone.settings().chunkCaching.get()) {
|
||||||
System.out.println("Not saving to disk; chunk caching is disabled.");
|
System.out.println("Not saving to disk; chunk caching is disabled.");
|
||||||
|
allRegions().forEach(CachedRegion::removeExpired); // even if we aren't saving to disk, still delete expired old chunks from RAM
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long start = System.nanoTime() / 1000000L;
|
long start = System.nanoTime() / 1000000L;
|
||||||
|
@ -106,7 +106,7 @@ public final class ChunkPacker implements Helper {
|
|||||||
blocks[z << 4 | x] = Blocks.AIR.getDefaultState();
|
blocks[z << 4 | x] = Blocks.AIR.getDefaultState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new CachedChunk(chunk.x, chunk.z, bitSet, blocks, specialBlocks);
|
return new CachedChunk(chunk.x, chunk.z, bitSet, blocks, specialBlocks, System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String blockToString(Block block) {
|
public static String blockToString(Block block) {
|
||||||
|
Loading…
Reference in New Issue
Block a user