Skip to content

Commit

Permalink
McQuad -- Version 1.2.2
Browse files Browse the repository at this point in the history
Added filtering of "Spurious Regions".
- initial cut at McaDump for analyzing region files.
- added timeStampAt() to RegionFile, so we can retrieve chunk timestamps.
    (to be used later in chunk-resolution heatmap generation)
  • Loading branch information
Simon Hunt committed Jun 29, 2016
1 parent e0e7839 commit b20aa7d
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 6 deletions.
2 changes: 1 addition & 1 deletion core/src/main/java/com/meowster/mcquad/McQuad.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
public class McQuad {

/* This version is displayed in the masthead of the web app */
private static final String MCQUAD_VERSION = "1.2.1";
private static final String MCQUAD_VERSION = "1.2.2";

private final ParsedArgs parsedArgs;
private final OutputUtils outputUtils;
Expand Down
56 changes: 56 additions & 0 deletions core/src/main/java/com/meowster/mcquad/McaDump.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.meowster.mcquad;

import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.meowster.util.StringUtils.printErr;
import static java.lang.System.exit;

/**
* Command-line based region file analysis program, for dumping information
* about MCA (Minecraft Anvil format) files.
* <pre>
* Usage: com.meowster.mcquad.McaDump {region file}.
* </pre>
*/
public class McaDump {

private static final Pattern RE_REGION_FILE =
Pattern.compile("^r\\.(-?\\d+)\\.(-?\\d+)\\.mca$");

private McaDump(File mca) {
Matcher m = RE_REGION_FILE.matcher(mca.getName());
if (m.matches()) {
int x = Integer.parseInt(m.group(1));
int z = Integer.parseInt(m.group(2));
Region region = new Region(x, z, mca);
RegionDataDump.analyze(region);
} else {
printErr("No match?? {}", mca.getName());
exit(1);
}
}

private static int usage() {
System.out.println("Usage: McaDump {region file}");
return 2;
}

/**
* Main entry point.
*
* @param args command line arguments.
*/
public static void main(String[] args) {
if (args.length != 1) {
exit(usage());
}
File mca = new File(args[0]);
if (!mca.canRead()) {
printErr("Unable to read file: {}", args[0]);
exit(usage());
}
new McaDump(mca);
}
}
32 changes: 30 additions & 2 deletions core/src/main/java/com/meowster/mcquad/Region.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Region {
* @param f the region file
* @param mock file is a mock
*/
public Region(int x, int z, File f, boolean mock) {
Region(int x, int z, File f, boolean mock) {
this.coord = new Coord(x, z);
this.f = f;
this.mock = mock;
Expand All @@ -51,6 +51,17 @@ public Region(int x, int z, File f, boolean mock) {
this(x, z, null, true);
}

/**
* Constructor for creating region file (not a mock).
*
* @param x the x-coord
* @param z the z-coord
* @param f the region file
*/
Region(int x, int z, File f) {
this(x, z, f, false);
}

@Override
public String toString() {
return "Region{" + coord + ", mock=" + mock + ", f=" + f + '}';
Expand Down Expand Up @@ -79,6 +90,15 @@ File regionFile() {
return f;
}

/**
* Returns true if this is a mock (test) region.
*
* @return true if mock; false otherwise
*/
boolean isMock() {
return mock;
}

/**
* Returns the last modified timestamp for the backing region file.
* If there is no backing file (for example, unit tests running in
Expand Down Expand Up @@ -123,12 +143,20 @@ DataInputStream getChunkDataStream(int cx, int cz) {
return rf == null ? null : rf.getChunkDataStream(cx, cz);
}

/**
* Returns the number of chunks contained in this region.
*
* @return the number of chunks in the region
*/
int chunkCount() {
return rf == null ? 0 : rf.chunkCount();
}

/**
* Instructs the region to release any resources used to hold region data,
* since we have generated the image and the data is no longer required.
*/
void releaseResources() {
rf = null;
}

}
12 changes: 12 additions & 0 deletions core/src/main/java/com/meowster/mcquad/RegionData.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ void load(Set<Region> regions) {
* @param r the region to load
*/
private void loadRegion(Region r) {
/*
* NOTE:
* There is a bug in the Minecraft server (observed in 1.10.2) that
* sometimes outputs region files containing a single chunk, with no
* bearing to where players have explored. We need to filter out these
* spurious regions.
*/
if (!r.isMock() && r.chunkCount() < 2) {
printErr("Spurious region detected: {}", r);
return;
}

bounds.add(r.coord());
regionMap.put(r.coord(), r);
}
Expand Down
88 changes: 88 additions & 0 deletions core/src/main/java/com/meowster/mcquad/RegionDataDump.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.meowster.mcquad;

import java.io.DataInputStream;

import static com.meowster.util.StringUtils.EOL;
import static com.meowster.util.StringUtils.printOut;

/**
* Analysis of a region file.
*/
class RegionDataDump {

private static final String HASH = " #";
private static final String DOT = " .";

private static final int NCHUNKS = 32; // chunk dimension of region
private static final int NBLOCKS = 16; // block dimension of chunk

private static final int CHUNKS_PER_REGION = NCHUNKS * NCHUNKS;


private static Region region;
private static int totalChunks;
private static ChunkStuff[][] data;
private static int singleX;
private static int singleZ;

/**
* Analyze the region and output results.
*
* @param r the region to analyze
*/
static void analyze(Region r) {
region = r;
totalChunks = 0;
data = new ChunkStuff[NCHUNKS][NCHUNKS];

// iterate over the chunks in the region...
for (int cz = 0; cz < NCHUNKS; cz++) {
for (int cx = 0; cx < NCHUNKS; cx++) {
DataInputStream dis = region.getChunkDataStream(cx, cz);
if (dis == null)
continue;

totalChunks++;
singleX = cx;
singleZ = cz;

// Chunk chunk = new Chunk(dis);
data[cz][cx] = new ChunkStuff(null);
}
}

outputResults();
}


private static void outputResults() {
printOut("Region: {}; Chunks: {}/{}",
region.regionFile().getName(),
totalChunks,
CHUNKS_PER_REGION
);
if (totalChunks == 1) {
printOut(" Chunk coords [{}, {}]", singleX, singleZ);
}
// printOut(createMap());
}

private static String createMap() {
StringBuilder sb = new StringBuilder();
for (int cz = 0; cz < NCHUNKS; cz++) {
for (int cx = 0; cx < NCHUNKS; cx++) {
sb.append(data[cz][cx] != null ? HASH : DOT);
}
sb.append(EOL);
}
return sb.toString();
}


// retains info about a chunk
private static class ChunkStuff {
ChunkStuff(Chunk chunk) {
// capture any data we need for dumping...
}
}
}
48 changes: 48 additions & 0 deletions core/src/main/java/com/meowster/mcquad/RegionFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,54 @@ else if (version == VERSION_DEFLATE)
}
}

/**
* Returns the number of chunks available in this region.
*
* @return the chunk count
*/
int chunkCount() {
int nChunks = 0;
for (int cz = 0; cz < NCHUNKS; cz++) {
for (int cx = 0; cx < NCHUNKS; cx++) {
if (chunkAvailableAt(cx, cz)) {
nChunks++;
}
}
}
return nChunks;
}

/**
* Returns true if there is chunk data at the specified coordinates.
*
* @param x chunk x-coord
* @param z chunk z-coord
* @return true if chunk data is here; false otherwise
*/
boolean chunkAvailableAt(int x, int z) {
if (outOfBounds(x, z))
return false;

int offset = getOffset(x, z);
if (offset == 0)
return false;

final int sectorNumber = offset >> 8;
final int numSectors = offset & 0xff;

return sectorNumber + numSectors <= nSectors;
}

/**
* Returns the chunk timestamp for the specified coordinates.
*
* @param x chunk x-coord
* @param z chunk z-coord
* @return true if chunk data is here; false otherwise
*/
int timeStampAt(int x, int z) {
return outOfBounds(x, z) ? 0 : chunkTimestamps[x + z * 32];
}

private boolean outOfBounds(int x, int z) {
return x < 0 || x >= NCHUNKS || z < 0 || z >= NCHUNKS;
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<modelVersion>4.0.0</modelVersion>

<properties>
<mcquad.version>1.2.1</mcquad.version>
<mcquad.version>1.2.2</mcquad.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Expand Down
2 changes: 1 addition & 1 deletion tools/src/bin/mcquad-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ export MCMAPS_CONTEXT=/mcmaps
##

# MCQUAD_VERSION should be set to correct version to pull out of maven repo
export MCQUAD_VERSION=1.2.1
export MCQUAD_VERSION=1.2.2

2 changes: 1 addition & 1 deletion tools/src/dev/cpwww.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

BACK=$PWD
TARBALL=static.tar.gz
VERSION=1.2.1
VERSION=1.2.2

cd ../../../web/target/mcquad-web-${VERSION}/
echo BUILD TAR
Expand Down
21 changes: 21 additions & 0 deletions tools/src/dev/mcadump.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

MCQUAD_VERSION=1.2.2

MAIN=com.meowster.mcquad.McaDump

CP="/Users/simonh/dev/mcquad/McQuad/core/target/classes"

MCSAVES="/Users/simonh/dev/mcquad/tmp"

ls "$MCSAVES"

JAVA=/usr/bin/java


for FILE in $(ls "$MCSAVES");
do
$JAVA -cp $CP $MAIN "$MCSAVES/$FILE"
done


0 comments on commit b20aa7d

Please sign in to comment.