Skip to content

Commit

Permalink
Implement new world pattern (#315)
Browse files Browse the repository at this point in the history
  • Loading branch information
pop4959 authored Feb 1, 2024
1 parent ce93af7 commit 9947f37
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ private synchronized void update(final int chunkX, final int chunkZ, final boole
public void run() {
final String poolThreadName = Thread.currentThread().getName();
Thread.currentThread().setName(String.format("Chunky-%s Thread", selection.world().getName()));
chunkIterator.process();
final Semaphore working = new Semaphore(MAX_WORKING_COUNT);
final boolean forceLoadExistingChunks = chunky.getConfig().isForceLoadExistingChunks();
startTime.set(System.currentTimeMillis());
Expand Down
22 changes: 2 additions & 20 deletions common/src/main/java/org/popcraft/chunky/command/TrimCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void execute(final Sender sender, final CommandArguments arguments) {
if (regionPath.isPresent()) {
try (final Stream<Path> files = Files.list(regionPath.get())) {
final List<Path> regions = files
.filter(file -> tryRegionCoordinate(file.getFileName().toString()).isPresent())
.filter(file -> ChunkCoordinate.fromRegionFile(file.getFileName().toString()).isPresent())
.toList();
final long totalRegions = regions.size();
for (final Path region: regions) {
Expand Down Expand Up @@ -135,7 +135,7 @@ public void execute(final Sender sender, final CommandArguments arguments) {
}

private int checkRegion(final World world, final String regionFileName, final Shape shape, final boolean inside, final boolean inhabitedTimeCheck, final int inhabitedTime) {
final Optional<ChunkCoordinate> regionCoordinate = tryRegionCoordinate(regionFileName);
final Optional<ChunkCoordinate> regionCoordinate = ChunkCoordinate.fromRegionFile(regionFileName);
if (regionCoordinate.isEmpty()) {
return 0;
}
Expand All @@ -148,24 +148,6 @@ private int checkRegion(final World world, final String regionFileName, final Sh
}
}

private Optional<ChunkCoordinate> tryRegionCoordinate(final String regionFileName) {
if (!regionFileName.startsWith("r.")) {
return Optional.empty();
}
final int extension = regionFileName.indexOf(".mca");
if (extension < 2) {
return Optional.empty();
}
final String regionCoordinates = regionFileName.substring(2, extension);
final int separator = regionCoordinates.indexOf('.');
final Optional<Integer> regionX = Input.tryInteger(regionCoordinates.substring(0, separator));
final Optional<Integer> regionZ = Input.tryInteger(regionCoordinates.substring(separator + 1));
if (regionX.isPresent() && regionZ.isPresent()) {
return Optional.of(new ChunkCoordinate(regionX.get(), regionZ.get()));
}
return Optional.empty();
}

private boolean shouldDeleteRegion(final Shape shape, final boolean inside, final int chunkX, final int chunkZ) {
for (int offsetX = 0; offsetX < 32; ++offsetX) {
for (int offsetZ = 0; offsetZ < 32; ++offsetZ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ public interface ChunkIterator extends Iterator<ChunkCoordinate> {
long total();

String name();

default void process() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ private ChunkIteratorFactory() {
}

public static ChunkIterator getChunkIterator(final Selection selection, final long count) {
if (selection.pattern().getType().equals(PatternType.WORLD)) {
return new WorldChunkIterator(selection);
}
final String shape = selection.shape();
if (ShapeType.RECTANGLE.equals(shape) || ShapeType.ELLIPSE.equals(shape) || ShapeType.OVAL.equals(shape)) {
return new Loop2ChunkIterator(selection, count);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ public final class PatternType {
public static final String SPIRAL = "spiral";
public static final String CSV = "csv";
public static final String REGION = "region";
public static final String WORLD = "world";

public static final List<String> ALL = List.of(CONCENTRIC, LOOP, SPIRAL, CSV, REGION);
public static final List<String> ALL = List.of(CONCENTRIC, LOOP, SPIRAL, CSV, REGION, WORLD);

private PatternType() {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package org.popcraft.chunky.iterator;

import org.popcraft.chunky.Selection;
import org.popcraft.chunky.nbt.StringTag;
import org.popcraft.chunky.nbt.util.RegionFile;
import org.popcraft.chunky.util.ChunkCoordinate;
import org.popcraft.chunky.util.Hilbert;
import org.popcraft.chunky.util.Parameter;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;

public class WorldChunkIterator implements ChunkIterator {
private final int minRegionX;
private final int minRegionZ;
private final int maxRegionX;
private final int maxRegionZ;
private final int minChunkX;
private final int minChunkZ;
private final int maxChunkX;
private final int maxChunkZ;
private final Queue<ChunkCoordinate> chunks;
private final AtomicLong total = new AtomicLong();
private final Path savePath;
private final Path regionPath;
private final String name;

public WorldChunkIterator(final Selection selection) {
final int centerRegionX = selection.centerRegionX();
final int centerRegionZ = selection.centerRegionZ();
final int radiusRegionsX = selection.radiusRegionsX();
final int radiusRegionsZ = selection.radiusRegionsZ();
this.minRegionX = centerRegionX - radiusRegionsX;
this.minRegionZ = centerRegionZ - radiusRegionsZ;
this.maxRegionX = centerRegionX + radiusRegionsX;
this.maxRegionZ = centerRegionZ + radiusRegionsZ;
final int centerChunkX = selection.centerChunkX();
final int centerChunkZ = selection.centerChunkZ();
final int radiusChunksX = selection.radiusChunksX();
final int radiusChunksZ = selection.radiusChunksZ();
this.minChunkX = centerChunkX - radiusChunksX;
this.minChunkZ = centerChunkZ - radiusChunksZ;
this.maxChunkX = centerChunkX + radiusChunksX;
this.maxChunkZ = centerChunkZ + radiusChunksZ;
this.chunks = new LinkedList<>();
final String worldName = selection.world().getName();
final String saveFile = worldName.substring(worldName.indexOf(':') + 1);
this.savePath = selection.chunky().getConfig().getDirectory().resolve(String.format("%s.csv", saveFile));
this.regionPath = selection.world().getRegionDirectory().orElse(null);
this.name = Parameter.of(PatternType.CSV, saveFile).toString();
}

@Override
public boolean hasNext() {
return !chunks.isEmpty();
}

@Override
public ChunkCoordinate next() {
if (chunks.isEmpty()) {
throw new NoSuchElementException();
}
return chunks.poll();
}

@Override
public long total() {
return total.get();
}

@Override
public String name() {
return name;
}

@Override
public void process() {
if (regionPath == null) {
return;
}
final StringBuilder saveData = new StringBuilder();
try (final Stream<Path> files = Files.list(regionPath)) {
final List<Path> regions = files
.filter(file -> {
final ChunkCoordinate regionCoordinate = ChunkCoordinate.fromRegionFile(file.getFileName().toString())
.orElse(null);
return regionCoordinate != null && regionCoordinate.x() >= minRegionX && regionCoordinate.x() <= maxRegionX && regionCoordinate.z() >= minRegionZ && regionCoordinate.z() <= maxRegionZ;
})
.toList();
for (final Path region : regions) {
final ChunkCoordinate regionCoordinate = ChunkCoordinate.fromRegionFile(region.getFileName().toString())
.orElseThrow(IllegalStateException::new);
final int regionX = regionCoordinate.x();
final int regionZ = regionCoordinate.z();
final RegionFile regionFile = new RegionFile(region.toFile());
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")
.map(StringTag::value)
.map(status -> "minecraft:full".equals(status) || "full".equals(status))
.orElse(false);
if (generated) {
chunks.add(chunkCoordinate);
saveData.append(chunkCoordinate.x()).append(',').append(chunkCoordinate.z()).append('\n');
total.incrementAndGet();
}
});
}
}
Files.writeString(savePath, saveData, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
}
}
19 changes: 19 additions & 0 deletions common/src/main/java/org/popcraft/chunky/util/ChunkCoordinate.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
package org.popcraft.chunky.util;

import java.util.Objects;
import java.util.Optional;

public record ChunkCoordinate(int x, int z) implements Comparable<ChunkCoordinate> {
public static Optional<ChunkCoordinate> fromRegionFile(final String regionFileName) {
if (!regionFileName.startsWith("r.")) {
return Optional.empty();
}
final int extension = regionFileName.indexOf(".mca");
if (extension < 2) {
return Optional.empty();
}
final String regionCoordinates = regionFileName.substring(2, extension);
final int separator = regionCoordinates.indexOf('.');
final Optional<Integer> regionX = Input.tryInteger(regionCoordinates.substring(0, separator));
final Optional<Integer> regionZ = Input.tryInteger(regionCoordinates.substring(separator + 1));
if (regionX.isPresent() && regionZ.isPresent()) {
return Optional.of(new ChunkCoordinate(regionX.get(), regionZ.get()));
}
return Optional.empty();
}

@Override
public int compareTo(final ChunkCoordinate o) {
return this.x == o.x ? Integer.compare(this.z, o.z) : Integer.compare(this.x, o.x);
Expand Down
7 changes: 7 additions & 0 deletions common/src/main/java/org/popcraft/chunky/util/Hilbert.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.popcraft.chunky.util;

import java.util.Arrays;
import java.util.Iterator;

public final class Hilbert {
private static final ChunkCoordinate[] regionChunkCoordinateOffsets = {
new ChunkCoordinate(0, 0), new ChunkCoordinate(0, 1), new ChunkCoordinate(1, 1),
Expand Down Expand Up @@ -352,4 +355,8 @@ private Hilbert() {
public static ChunkCoordinate regionDistanceToChunkCoordinateOffset(final int distance) {
return regionChunkCoordinateOffsets[distance];
}

public static ChunkCoordinate[] chunkCoordinateOffsets() {
return regionChunkCoordinateOffsets;
}
}
1 change: 1 addition & 0 deletions common/src/main/resources/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"pattern_spiral": "spiral",
"pattern_csv": "csv",
"pattern_region": "region",
"pattern_world": "world",
"shape_circle": "circle",
"shape_diamond": "diamond",
"shape_ellipse": "ellipse",
Expand Down

0 comments on commit 9947f37

Please sign in to comment.