diff --git a/README.md b/README.md index 56de831..c085756 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ MCResourceAnalyzer gathers data from Minecraft region files to determine the emp 1. Clone the repository and build it with Maven or [download the latest release here](https://github.com/Meeples10/MCResourceAnalyzer/releases). 2. If your world was generated with a version after Beta 1.3, use the `region` directory from your Minecraft world as the program's input. -If the world was generated with a version between Infdev 20100327 and Beta 1.2, use the entire world directory to `region` as the program's input. -If the world was generated with Indev, rename the save file to `world.mclevel` and copy it to the same directory as the program. +If the world was generated with a version between Infdev 20100327 and Beta 1.2, use the entire world directory as the input. +If the world was generated with Indev, use the `world.mclevel` file as the input. 3. Run the program with `java -jar mc-resource-analyzer-x.x.x.jar [options...] [input path]`. After analyzing the world, the program will create a file in the same directory named `data.csv`. Note that the numbers for `minecraft:air` may be inaccurate at high Y values due to the way Minecraft stores chunks. @@ -46,7 +46,7 @@ java -jar mc-resource-analyzer-x.x.x.jar [-hHmsStV] [-B=PATH] [-M=PATH] [-o=STRI ### Version compatibility -MCResourceAnalyzer 1.2.0 can analyze worlds generated with any version of Minecraft: Java Edition between Indev 0.31 20100122 and 1.20.1. +MCResourceAnalyzer 1.2.1 can analyze worlds generated with any version of Minecraft: Java Edition between Indev 0.31 20100122 and 1.20.1. Note that Indev worlds with the `Long` and `Deep` world shapes are not supported. diff --git a/pom.xml b/pom.xml index 7f43e3e..001891f 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ io.github.meeples10.mcresourceanalyzer mc-resource-analyzer - 1.2.0 + 1.2.1 jar MCResourceAnalyzer diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/Analysis.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/Analysis.java index caf66d0..78f6848 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/Analysis.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/Analysis.java @@ -1,9 +1,9 @@ package io.github.meeples10.mcresourceanalyzer; -import java.util.HashMap; +import java.util.Hashtable; import java.util.Map; public class Analysis { - public Map blocks = new HashMap(); - public Map> heights = new HashMap>(); + public Map blocks = new Hashtable<>(); + public Map> heights = new Hashtable<>(); } diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/AnalyzerThread.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/AnalyzerThread.java index af89c6f..8201d4d 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/AnalyzerThread.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/AnalyzerThread.java @@ -1,16 +1,52 @@ package io.github.meeples10.mcresourceanalyzer; import java.util.HashSet; +import java.util.Hashtable; import java.util.Set; public abstract class AnalyzerThread extends Thread { + final RegionAnalyzer ra; final Region r; final Set analyses = new HashSet<>(); - public AnalyzerThread(Region region) { + public AnalyzerThread(RegionAnalyzer ra, Region region) { + this.ra = ra; r = region; setName(r.name); } - public abstract void run(); + public void run() { + process(); + ra.add(combineAnalyses()); + } + + public abstract void process(); + + private Analysis combineAnalyses() { + Analysis out = new Analysis(); + for(Analysis a : analyses) { + for(String blockName : a.blocks.keySet()) { + long count = a.blocks.get(blockName); + if(out.blocks.containsKey(blockName)) { + out.blocks.put(blockName, out.blocks.get(blockName) + count); + } else { + out.blocks.put(blockName, count); + } + } + for(String blockName : a.heights.keySet()) { + if(!out.heights.containsKey(blockName)) { + out.heights.put(blockName, new Hashtable()); + } + for(int y : a.heights.get(blockName).keySet()) { + long count = a.heights.get(blockName).get(y); + if(out.heights.get(blockName).containsKey(y)) { + out.heights.get(blockName).put(y, out.heights.get(blockName).get(y) + count); + } else { + out.heights.get(blockName).put(y, count); + } + } + } + } + return out; + } } diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzer.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzer.java index 103a73b..0f35a4d 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzer.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzer.java @@ -4,8 +4,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; -import java.util.HashMap; import java.util.HashSet; +import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -19,8 +19,8 @@ public abstract class RegionAnalyzer { private Version version; public int chunkCount = 0; - public Map blockCounter = new HashMap(); - public Map> heightCounter = new HashMap>(); + public Map blockCounter = new Hashtable<>(); + public Map> heightCounter = new Hashtable<>(); private long firstStartTime; public long duration; List regions = new ArrayList<>(); @@ -56,29 +56,12 @@ public void run(File input) { pool.submit(t); } pool.shutdown(); + threads.clear(); try { pool.awaitTermination(100, TimeUnit.DAYS); } catch(InterruptedException e) { e.printStackTrace(); } - for(AnalyzerThread t : threads) { - for(Analysis a : t.analyses) { - for(String s : a.blocks.keySet()) { - blockCounter.put(s, blockCounter.getOrDefault(s, 0L) + a.blocks.get(s)); - } - for(String s : a.heights.keySet()) { - if(heightCounter.containsKey(s)) { - Map existing = heightCounter.get(s); - Map heights = a.heights.get(s); - for(int i : heights.keySet()) { - existing.put(i, existing.getOrDefault(i, 0L) + heights.get(i)); - } - } else { - heightCounter.put(s, a.heights.get(s)); - } - } - } - } } duration = System.currentTimeMillis() - getStartTime(); @@ -195,7 +178,7 @@ public String generateTable(double totalBlocks, double totalExcludingAir) { data.append("\n"); } data.append(""); - for(int i = minY; i < maxY; i++) { + for(int i = minY; i <= maxY; i++) { if(!heightCounter.get(key).containsKey(i)) { data.append(""); } else { @@ -256,7 +239,7 @@ static boolean mergeStates(byte id) { static void airHack(Analysis a, int sectionY, String airID) { if(Main.allowHack && sectionY < 15) { if(!a.blocks.containsKey(airID)) a.blocks.put(airID, 0L); - if(!a.heights.containsKey(airID)) a.heights.put(airID, new HashMap()); + if(!a.heights.containsKey(airID)) a.heights.put(airID, new Hashtable()); for(; sectionY < 16; sectionY++) { a.blocks.put(airID, a.blocks.get(airID) + 4096L); for(int y = sectionY * 16; y < sectionY * 16 + 16; y++) { @@ -270,7 +253,7 @@ static void airHack(Analysis a, int sectionY, String airID) { } } - int getMinimumY() { + private int getMinimumY() { int min = Integer.MAX_VALUE; for(Map map : heightCounter.values()) { for(int i : map.keySet()) { @@ -286,7 +269,7 @@ int getMinimumY() { } } - int getMaximumY() { + private int getMaximumY() { int max = Integer.MIN_VALUE; for(Map map : heightCounter.values()) { for(int i : map.keySet()) { @@ -296,12 +279,29 @@ int getMaximumY() { } } if(version == Version.INDEV || version == Version.ALPHA || version == Version.MCREGION) { - return 128; + return 127; } else { return max > 255 ? max : 255; } } + synchronized void add(Analysis a) { + for(String s : a.blocks.keySet()) { + blockCounter.put(s, blockCounter.getOrDefault(s, 0L) + a.blocks.get(s)); + } + for(String s : a.heights.keySet()) { + if(heightCounter.containsKey(s)) { + Map existing = heightCounter.get(s); + Map heights = a.heights.get(s); + for(int i : heights.keySet()) { + existing.put(i, existing.getOrDefault(i, 0L) + heights.get(i)); + } + } else { + heightCounter.put(s, a.heights.get(s)); + } + } + } + public enum Version { ANVIL_118(RegionAnalyzerAnvil118.class, true), ANVIL_2021(RegionAnalyzerAnvil2021.class, true), diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAlpha.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAlpha.java index 3293e9c..e601b8c 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAlpha.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAlpha.java @@ -3,7 +3,7 @@ import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Hashtable; import java.util.List; import net.minecraft.nbt.CompressedStreamTools; @@ -89,7 +89,7 @@ private void analyzeChunk(byte[] blocks, byte[] data) { a.blocks.put(blockName, 1L); } if(!a.heights.containsKey(blockName)) { - a.heights.put(blockName, new HashMap()); + a.heights.put(blockName, new Hashtable()); } if(a.heights.get(blockName).containsKey(y)) { a.heights.get(blockName).put(y, a.heights.get(blockName).get(y) + 1L); diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil118.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil118.java index f27c7c8..7071684 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil118.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil118.java @@ -3,7 +3,7 @@ import java.io.DataInputStream; import java.io.File; import java.io.IOException; -import java.util.HashMap; +import java.util.Hashtable; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -40,9 +40,8 @@ public void findChunks(File regionDir) { @Override public void analyze() { for(Region r : regions) { - threads.add(new AnalyzerThread(r) { - @Override - public void run() { + threads.add(new AnalyzerThread(this, r) { + public void process() { for(Chunk c : r.chunks) { try { Analysis a = processRegion(r.file, c.x(), c.z()); @@ -98,7 +97,7 @@ private Analysis analyzeChunk(NBTTagList sections) { a.blocks.put(blockName, 1L); } if(!a.heights.containsKey(blockName)) { - a.heights.put(blockName, new HashMap()); + a.heights.put(blockName, new Hashtable()); } if(a.heights.get(blockName).containsKey(actualY)) { a.heights.get(blockName).put(actualY, a.heights.get(blockName).get(actualY) + 1L); diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2012.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2012.java index 58e1d45..da68f0b 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2012.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2012.java @@ -3,7 +3,7 @@ import java.io.DataInputStream; import java.io.File; import java.io.IOException; -import java.util.HashMap; +import java.util.Hashtable; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -39,9 +39,8 @@ public void findChunks(File regionDir) { @Override public void analyze() { for(Region r : regions) { - threads.add(new AnalyzerThread(r) { - @Override - public void run() { + threads.add(new AnalyzerThread(this, r) { + public void process() { for(Chunk c : r.chunks) { try { Analysis a = processRegion(r.file, c.x(), c.z()); @@ -107,7 +106,7 @@ private Analysis analyzeChunk(NBTTagList sections) { a.blocks.put(blockName, 1L); } if(!a.heights.containsKey(blockName)) { - a.heights.put(blockName, new HashMap()); + a.heights.put(blockName, new Hashtable()); } if(a.heights.get(blockName).containsKey(actualY)) { a.heights.get(blockName).put(actualY, a.heights.get(blockName).get(actualY) + 1L); diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2018.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2018.java index badfc2a..dfcb9e7 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2018.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2018.java @@ -3,7 +3,7 @@ import java.io.DataInputStream; import java.io.File; import java.io.IOException; -import java.util.HashMap; +import java.util.Hashtable; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -42,9 +42,8 @@ public void analyze() { // The air hack does not seem to work for this version Main.allowHack = false; for(Region r : regions) { - threads.add(new AnalyzerThread(r) { - @Override - public void run() { + threads.add(new AnalyzerThread(this, r) { + public void process() { for(Chunk c : r.chunks) { try { Analysis a = processRegion(r.file, c.x(), c.z()); @@ -100,7 +99,7 @@ private Analysis analyzeChunk(NBTTagList sections) { a.blocks.put(blockName, 1L); } if(!a.heights.containsKey(blockName)) { - a.heights.put(blockName, new HashMap()); + a.heights.put(blockName, new Hashtable()); } if(a.heights.get(blockName).containsKey(actualY)) { a.heights.get(blockName).put(actualY, a.heights.get(blockName).get(actualY) + 1L); diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2021.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2021.java index cc34573..8ebb560 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2021.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerAnvil2021.java @@ -3,7 +3,7 @@ import java.io.DataInputStream; import java.io.File; import java.io.IOException; -import java.util.HashMap; +import java.util.Hashtable; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -40,9 +40,8 @@ public void findChunks(File regionDir) { @Override public void analyze() { for(Region r : regions) { - threads.add(new AnalyzerThread(r) { - @Override - public void run() { + threads.add(new AnalyzerThread(this, r) { + public void process() { for(Chunk c : r.chunks) { try { Analysis a = processRegion(r.file, c.x(), c.z()); @@ -98,7 +97,7 @@ private Analysis analyzeChunk(NBTTagList sections) { a.blocks.put(blockName, 1L); } if(!a.heights.containsKey(blockName)) { - a.heights.put(blockName, new HashMap()); + a.heights.put(blockName, new Hashtable()); } if(a.heights.get(blockName).containsKey(actualY)) { a.heights.get(blockName).put(actualY, a.heights.get(blockName).get(actualY) + 1L); diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerIndev.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerIndev.java index 38172a8..f59ce92 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerIndev.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerIndev.java @@ -3,7 +3,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.HashMap; +import java.util.Hashtable; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -72,7 +72,7 @@ private Analysis analyzeWorld(byte[] blocks, byte[] data, int width, int height) a.blocks.put(blockName, 1L); } if(!a.heights.containsKey(blockName)) { - a.heights.put(blockName, new HashMap()); + a.heights.put(blockName, new Hashtable()); } if(a.heights.get(blockName).containsKey(y)) { a.heights.get(blockName).put(y, a.heights.get(blockName).get(y) + 1L); diff --git a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerMCRegion.java b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerMCRegion.java index 501acac..16e8a67 100644 --- a/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerMCRegion.java +++ b/src/main/java/io/github/meeples10/mcresourceanalyzer/RegionAnalyzerMCRegion.java @@ -3,7 +3,7 @@ import java.io.DataInputStream; import java.io.File; import java.io.IOException; -import java.util.HashMap; +import java.util.Hashtable; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -34,9 +34,8 @@ public void findChunks(File regionDir) { @Override public void analyze() { for(Region r : regions) { - threads.add(new AnalyzerThread(r) { - @Override - public void run() { + threads.add(new AnalyzerThread(this, r) { + public void process() { for(Chunk c : r.chunks) { try { Analysis a = processRegion(r.file, c.x(), c.z()); @@ -95,7 +94,7 @@ private Analysis analyzeChunk(byte[] blocks, byte[] data) { a.blocks.put(blockName, 1L); } if(!a.heights.containsKey(blockName)) { - a.heights.put(blockName, new HashMap()); + a.heights.put(blockName, new Hashtable()); } if(a.heights.get(blockName).containsKey(y)) { a.heights.get(blockName).put(y, a.heights.get(blockName).get(y) + 1L);
id"); - for(int i = minY; i < maxY; i++) { + for(int i = minY; i <= maxY; i++) { data.append(i); data.append(""); } @@ -209,7 +192,7 @@ public String generateTable(double totalBlocks, double totalExcludingAir) { data.append(""); data.append(Main.modernizeIDs ? Main.getStringID(key) : key); data.append("0