Implement chunk filters
This commit is contained in:
1 parent
62c437dcc8
commit
2a58fdaf80
5 files changed
+95
-31
No files matched your search
@@ -2,8 +2,10 @@ package org.popcraft.chunky.command;
|
||||
|
||||
import org.popcraft.chunky.Chunky;
|
||||
import org.popcraft.chunky.Selection;
|
||||
import org.popcraft.chunky.nbt.CompoundTag;
|
||||
import org.popcraft.chunky.nbt.LongTag;
|
||||
import org.popcraft.chunky.nbt.Tag;
|
||||
import org.popcraft.chunky.nbt.TagType;
|
||||
import org.popcraft.chunky.nbt.util.ChunkFilter;
|
||||
import org.popcraft.chunky.nbt.util.RegionFile;
|
||||
import org.popcraft.chunky.platform.Sender;
|
||||
import org.popcraft.chunky.platform.World;
|
||||
@@ -103,7 +105,7 @@ public class TrimCommand implements ChunkyCommand {
|
||||
.filter(file -> ChunkCoordinate.fromRegionFile(file.getFileName().toString()).isPresent())
|
||||
.toList();
|
||||
final long totalRegions = regions.size();
|
||||
for (final Path region: regions) {
|
||||
for (final Path region : regions) {
|
||||
if (trimTask.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
@@ -112,7 +114,7 @@ public class TrimCommand implements ChunkyCommand {
|
||||
if (!trimTask.isCancelled() && !chunky.getConfig().isSilent()) {
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
final boolean updateIntervalElapsed = ((currentTime - updateTime.get()) / 1e3) > chunky.getConfig().getUpdateInterval();
|
||||
if (updateIntervalElapsed) {
|
||||
if (updateIntervalElapsed || finishedRegions.get() == totalRegions) {
|
||||
sender.sendMessagePrefixed(TranslationKey.TASK_TRIM_UPDATE, selection.world().getName(), finishedRegions.get(), String.format("%.2f", 100f * finishedRegions.get() / totalRegions));
|
||||
updateTime.set(currentTime);
|
||||
}
|
||||
@@ -186,7 +188,7 @@ public class TrimCommand implements ChunkyCommand {
|
||||
final Path entitiesPath = world.getEntitiesDirectory().map(region -> region.resolve(regionFileName)).orElse(null);
|
||||
int marked = 0;
|
||||
int deleted = 0;
|
||||
final RegionFile regionData = inhabitedTimeCheck ? new RegionFile(regionPath.toFile()) : null;
|
||||
final RegionFile regionData = inhabitedTimeCheck ? new RegionFile(regionPath.toFile(), ChunkFilter.of(TagType.LONG, "InhabitedTime")) : null;
|
||||
try (final RandomAccessFile regionFile = new RandomAccessFile(regionPath.toFile(), "rw");
|
||||
final RandomAccessFile poiFile = poiPath == null || Files.notExists(poiPath) ? null : new RandomAccessFile(poiPath.toFile(), "rw");
|
||||
final RandomAccessFile entitiesFile = entitiesPath == null || Files.notExists(entitiesPath) ? null : new RandomAccessFile(entitiesPath.toFile(), "rw")) {
|
||||
@@ -209,12 +211,8 @@ public class TrimCommand implements ChunkyCommand {
|
||||
}
|
||||
final boolean trimInhabited = regionData == null || regionData.getChunk(offsetChunkX, offsetChunkZ)
|
||||
.map(chunk -> {
|
||||
final CompoundTag compoundTag = chunk.getData();
|
||||
if (compoundTag == null) {
|
||||
return true;
|
||||
}
|
||||
final LongTag inhabited = compoundTag.getLong("InhabitedTime").orElse(null);
|
||||
if (inhabited == null) {
|
||||
final Tag tag = chunk.getData();
|
||||
if (!(tag instanceof final LongTag inhabited)) {
|
||||
return true;
|
||||
}
|
||||
return inhabited.value() <= inhabitedTime;
|
||||
|
||||
@@ -3,6 +3,8 @@ package org.popcraft.chunky.iterator;
|
||||
import org.popcraft.chunky.Chunky;
|
||||
import org.popcraft.chunky.Selection;
|
||||
import org.popcraft.chunky.nbt.StringTag;
|
||||
import org.popcraft.chunky.nbt.TagType;
|
||||
import org.popcraft.chunky.nbt.util.ChunkFilter;
|
||||
import org.popcraft.chunky.nbt.util.RegionFile;
|
||||
import org.popcraft.chunky.util.ChunkCoordinate;
|
||||
import org.popcraft.chunky.util.Hilbert;
|
||||
@@ -16,6 +18,7 @@ import java.nio.file.StandardOpenOption;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Stream;
|
||||
@@ -109,14 +112,16 @@ public class WorldChunkIterator implements ChunkIterator {
|
||||
.orElseThrow(IllegalStateException::new);
|
||||
final int regionX = regionCoordinate.x();
|
||||
final int regionZ = regionCoordinate.z();
|
||||
final RegionFile regionFile = new RegionFile(region.toFile());
|
||||
final RegionFile regionFile = new RegionFile(region.toFile(), ChunkFilter.of(TagType.STRING, "Status"));
|
||||
for (final ChunkCoordinate offset : Hilbert.chunkCoordinateOffsets()) {
|
||||
final ChunkCoordinate chunkCoordinate = new ChunkCoordinate((regionX << 5) + offset.x(), (regionZ << 5) + offset.z());
|
||||
if (chunkCoordinate.x() < minChunkX || chunkCoordinate.x() > maxChunkX || chunkCoordinate.z() < minChunkZ || chunkCoordinate.z() > maxChunkZ) {
|
||||
continue;
|
||||
}
|
||||
regionFile.getChunk(chunkCoordinate.x(), chunkCoordinate.z()).ifPresent(chunk -> {
|
||||
final boolean generated = chunk.getData().getString("Status")
|
||||
final boolean generated = Optional.ofNullable(chunk.getData())
|
||||
.filter(StringTag.class::isInstance)
|
||||
.map(StringTag.class::cast)
|
||||
.map(StringTag::value)
|
||||
.map(status -> "minecraft:full".equals(status) || "full".equals(status))
|
||||
.orElse(false);
|
||||
|
||||
@@ -1,21 +1,41 @@
|
||||
package org.popcraft.chunky.nbt.util;
|
||||
|
||||
import org.popcraft.chunky.nbt.CompoundTag;
|
||||
import org.popcraft.chunky.nbt.Tag;
|
||||
|
||||
public final class Chunk {
|
||||
private CompoundTag data;
|
||||
private int x;
|
||||
private int z;
|
||||
private Tag data;
|
||||
private long lastModified;
|
||||
|
||||
public Chunk(final CompoundTag data, final long lastModified) {
|
||||
public Chunk(final int x, final int z, final Tag data, final long lastModified) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.data = data;
|
||||
this.lastModified = lastModified;
|
||||
}
|
||||
|
||||
public CompoundTag getData() {
|
||||
public Tag getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(CompoundTag data) {
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(int z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public void setData(Tag data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.popcraft.chunky.nbt.util;
|
||||
|
||||
public final class ChunkFilter {
|
||||
private final byte type;
|
||||
private final String name;
|
||||
|
||||
private ChunkFilter(final byte type, final String name) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static ChunkFilter of(final byte type, final String name) {
|
||||
return new ChunkFilter(type, name);
|
||||
}
|
||||
|
||||
public byte getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.popcraft.chunky.nbt.util;
|
||||
|
||||
import org.popcraft.chunky.nbt.CompoundTag;
|
||||
import org.popcraft.chunky.nbt.IntTag;
|
||||
import org.popcraft.chunky.nbt.Tag;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
@@ -25,10 +23,32 @@ public final class RegionFile {
|
||||
private final Map<ChunkPos, Chunk> chunkMap = new HashMap<>();
|
||||
|
||||
public RegionFile(final File file) {
|
||||
this(file, null);
|
||||
}
|
||||
|
||||
public RegionFile(final File file, final ChunkFilter filter) {
|
||||
try (final RandomAccessFile region = new RandomAccessFile(file, "r")) {
|
||||
if (region.length() < 4096) {
|
||||
return;
|
||||
}
|
||||
final String regionFileName = file.getName();
|
||||
if (!regionFileName.startsWith("r.")) {
|
||||
return;
|
||||
}
|
||||
final int extension = regionFileName.indexOf(".mca");
|
||||
if (extension < 2) {
|
||||
return;
|
||||
}
|
||||
final String regionCoordinates = regionFileName.substring(2, extension);
|
||||
final int separator = regionCoordinates.indexOf('.');
|
||||
final int regionX;
|
||||
final int regionZ;
|
||||
try {
|
||||
regionX = Integer.parseInt(regionCoordinates.substring(0, separator));
|
||||
regionZ = Integer.parseInt(regionCoordinates.substring(separator + 1));
|
||||
} catch (final NumberFormatException e) {
|
||||
return;
|
||||
}
|
||||
final int[] offsetTable = new int[ENTRIES];
|
||||
final int[] sizeTable = new int[ENTRIES];
|
||||
for (int i = 0; i < ENTRIES; ++i) {
|
||||
@@ -58,24 +78,22 @@ public final class RegionFile {
|
||||
final InflaterInputStream inflater = new InflaterInputStream(bytes);
|
||||
final BufferedInputStream buffer = new BufferedInputStream(inflater);
|
||||
final DataInputStream input = new DataInputStream(buffer)) {
|
||||
if (Tag.load(input) instanceof final CompoundTag data) {
|
||||
chunks.add(new Chunk(data, timestampTable[i]));
|
||||
final int x = (regionX * 32) + (i % 32);
|
||||
final int z = (regionZ * 32) + (i / 32);
|
||||
final Tag data;
|
||||
if (filter == null) {
|
||||
data = Tag.load(input);
|
||||
} else {
|
||||
data = Tag.find(input, filter.getType(), filter.getName());
|
||||
}
|
||||
final Chunk chunk = new Chunk(x, z, data, timestampTable[i]);
|
||||
chunks.add(chunk);
|
||||
chunkMap.put(ChunkPos.of(x, z), chunk);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
for (final Chunk chunk : chunks) {
|
||||
final CompoundTag data = chunk.getData();
|
||||
final Optional<IntTag> xPos = data.getInt("xPos");
|
||||
final Optional<IntTag> zPos = data.getInt("zPos");
|
||||
if (xPos.isPresent() && zPos.isPresent()) {
|
||||
final int x = xPos.get().value();
|
||||
final int z = zPos.get().value();
|
||||
chunkMap.put(ChunkPos.of(x, z), chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Chunk> getChunks() {
|
||||
|
||||
Reference in new issue
Block a user