From 04c2b4edab0aae71d1ecd7d828974606105cc472 Mon Sep 17 00:00:00 2001 From: Big-Iron-Cheems <52252627+Big-Iron-Cheems@users.noreply.github.com> Date: Thu, 27 Aug 2026 13:58:15 +0200 Subject: [PATCH 1/5] refactor(stash-finder): modernize file IO and CSV handling This also fixes mismatches in CSV field read/writes. --- .../systems/modules/world/StashFinder.java | 116 +++++++++++------- 1 file changed, 69 insertions(+), 47 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java index fc462b8fe43..448ea4173cb 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java @@ -46,8 +46,15 @@ import net.minecraft.world.level.block.entity.*; import net.minecraft.world.phys.Vec3; -import java.io.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; +import java.util.function.ObjIntConsumer; +import java.util.function.ToIntFunction; +import java.util.stream.Collectors; public class StashFinder extends Module { private final SettingGroup sgGeneral = settings.getDefaultGroup(); @@ -171,6 +178,22 @@ public class StashFinder extends Module { ); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + private record CsvField(String name, ToIntFunction getter, ObjIntConsumer setter) { + } + + private static final List CSV_FIELDS = List.of( + new CsvField("x", c -> c.x, (c, v) -> c.x = v), + new CsvField("z", c -> c.z, (c, v) -> c.z = v), + new CsvField("chests", c -> c.chests, (c, v) -> c.chests = v), + new CsvField("barrels", c -> c.barrels, (c, v) -> c.barrels = v), + new CsvField("shulkers", c -> c.shulkers, (c, v) -> c.shulkers = v), + new CsvField("enderChests", c -> c.enderChests, (c, v) -> c.enderChests = v), + new CsvField("furnaces", c -> c.furnaces, (c, v) -> c.furnaces = v), + new CsvField("dispensersDroppers", c -> c.dispensersDroppers, (c, v) -> c.dispensersDroppers = v), + new CsvField("hoppers", c -> c.hoppers, (c, v) -> c.hoppers = v) + ); + private final Map tracerPositions = new HashMap<>(); public List chunks = new ArrayList<>(); @@ -217,6 +240,7 @@ private void onChunkData(ChunkDataEvent event) { case DispenserBlockEntity _ -> chunk.dispensersDroppers++; case HopperBlockEntity _ -> chunk.hoppers++; default -> { + // Do not track other block entities } } } @@ -327,16 +351,12 @@ private void load() { boolean loaded = false; // Try to load json - File file = getJsonFile(); - if (file.exists()) { - try { - FileReader reader = new FileReader(file); + Path jsonFile = getJsonFile(); + if (Files.exists(jsonFile)) { + try (BufferedReader reader = Files.newBufferedReader(jsonFile)) { chunks = GSON.fromJson(reader, new TypeToken>() { }.getType()); - reader.close(); - for (Chunk chunk : chunks) chunk.calculatePos(); - loaded = true; } catch (Exception _) { if (chunks == null) chunks = new ArrayList<>(); @@ -344,28 +364,28 @@ private void load() { } // Try to load csv - file = getCsvFile(); - if (!loaded && file.exists()) { - try { - BufferedReader reader = new BufferedReader(new FileReader(file)); - reader.readLine(); + Path csvFile = getCsvFile(); + if (!loaded && Files.exists(csvFile)) { + try (BufferedReader reader = Files.newBufferedReader(csvFile)) { + reader.readLine(); // Skip header String line; while ((line = reader.readLine()) != null) { - String[] values = line.split(" "); - Chunk chunk = new Chunk(new ChunkPos(Integer.parseInt(values[0]), Integer.parseInt(values[1]))); + String[] values = line.split(","); + if (values.length != CSV_FIELDS.size()) { + throw new IllegalStateException("Invalid CSV row length: expected " + CSV_FIELDS.size() + ", got " + values.length); + } - chunk.chests = Integer.parseInt(values[2]); - chunk.shulkers = Integer.parseInt(values[3]); - chunk.enderChests = Integer.parseInt(values[4]); - chunk.furnaces = Integer.parseInt(values[5]); - chunk.dispensersDroppers = Integer.parseInt(values[6]); - chunk.hoppers = Integer.parseInt(values[7]); + int x = Integer.parseInt(values[0]); + int z = Integer.parseInt(values[1]); + Chunk chunk = new Chunk(new ChunkPos(Math.floorDiv(x - 8, 16), Math.floorDiv(z - 8, 16))); + + for (int i = 0; i < CSV_FIELDS.size(); i++) { + CSV_FIELDS.get(i).setter().accept(chunk, Integer.parseInt(values[i])); + } chunks.add(chunk); } - - reader.close(); } catch (Exception _) { if (chunks == null) chunks = new ArrayList<>(); } @@ -374,14 +394,17 @@ private void load() { private void saveCsv() { try { - File file = getCsvFile(); - file.getParentFile().mkdirs(); - Writer writer = new FileWriter(file); - - writer.write("X,Z,Chests,Barrels,Shulkers,EnderChests,Furnaces,DispensersDroppers,Hoppers\n"); - for (Chunk chunk : chunks) chunk.write(writer); - - writer.close(); + Path csvFile = getCsvFile(); + Files.createDirectories(csvFile.getParent()); + try (BufferedWriter writer = Files.newBufferedWriter(csvFile)) { + String header = CSV_FIELDS.stream() + .map(CsvField::name) + .collect(Collectors.joining(",")); + writer.write(header + "\n"); + for (Chunk chunk : chunks) { + chunk.write(writer); + } + } } catch (IOException e) { MeteorClient.LOG.error("Error while writing the stash list to csv", e); } @@ -389,22 +412,22 @@ private void saveCsv() { private void saveJson() { try { - File file = getJsonFile(); - file.getParentFile().mkdirs(); - Writer writer = new FileWriter(file); - GSON.toJson(chunks, writer); - writer.close(); + Path jsonFile = getJsonFile(); + Files.createDirectories(jsonFile.getParent()); + try (BufferedWriter writer = Files.newBufferedWriter(jsonFile)) { + GSON.toJson(chunks, writer); + } } catch (IOException e) { MeteorClient.LOG.error("Error while writing the stash list to json", e); } } - private File getJsonFile() { - return new File(new File(new File(MeteorClient.FOLDER, "stashes"), Utils.getFileWorldName()), "stashes.json"); + private Path getJsonFile() { + return Path.of(MeteorClient.FOLDER.getPath(), "stashes", Utils.getFileWorldName(), "stashes.json"); } - private File getCsvFile() { - return new File(new File(new File(MeteorClient.FOLDER, "stashes"), Utils.getFileWorldName()), "stashes.csv"); + private Path getCsvFile() { + return Path.of(MeteorClient.FOLDER.getPath(), "stashes", Utils.getFileWorldName(), "stashes.csv"); } @Override @@ -479,8 +502,6 @@ public enum Mode { } public static class Chunk { - private static final StringBuilder sb = new StringBuilder(); - public ChunkPos chunkPos; public transient int x, z; public int chests, barrels, shulkers, enderChests, furnaces, dispensersDroppers, hoppers; @@ -500,11 +521,12 @@ public int getTotal() { return chests + barrels + shulkers + enderChests + furnaces + dispensersDroppers + hoppers; } - public void write(Writer writer) throws IOException { - sb.setLength(0); - sb.append(x).append(',').append(z).append(','); - sb.append(chests).append(',').append(barrels).append(',').append(shulkers).append(',').append(enderChests).append(',').append(furnaces).append(',').append(dispensersDroppers).append(',').append(hoppers).append('\n'); - writer.write(sb.toString()); + public void write(BufferedWriter writer) throws IOException { + String line = CSV_FIELDS.stream() + .map(field -> String.valueOf(field.getter().applyAsInt(this))) + .collect(Collectors.joining(",")); + writer.write(line); + writer.newLine(); } public boolean countsEqual(Chunk c) { From bc66f487a602d894d5ec7565175fffb20d2c2741 Mon Sep 17 00:00:00 2001 From: Big-Iron-Cheems <52252627+Big-Iron-Cheems@users.noreply.github.com> Date: Thu, 27 Aug 2026 14:45:35 +0200 Subject: [PATCH 2/5] fix(stash-finder): store chunk coords like before Mistakenly switched to world coords. --- .../systems/modules/world/StashFinder.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java index 448ea4173cb..aff864f477f 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java @@ -180,11 +180,14 @@ public class StashFinder extends Module { private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private record CsvField(String name, ToIntFunction getter, ObjIntConsumer setter) { + public CsvField(String name, ToIntFunction getter) { + this(name, getter, null); + } } private static final List CSV_FIELDS = List.of( - new CsvField("x", c -> c.x, (c, v) -> c.x = v), - new CsvField("z", c -> c.z, (c, v) -> c.z = v), + new CsvField("x", c -> c.chunkPos.x()), + new CsvField("z", c -> c.chunkPos.z()), new CsvField("chests", c -> c.chests, (c, v) -> c.chests = v), new CsvField("barrels", c -> c.barrels, (c, v) -> c.barrels = v), new CsvField("shulkers", c -> c.shulkers, (c, v) -> c.shulkers = v), @@ -376,11 +379,9 @@ private void load() { throw new IllegalStateException("Invalid CSV row length: expected " + CSV_FIELDS.size() + ", got " + values.length); } - int x = Integer.parseInt(values[0]); - int z = Integer.parseInt(values[1]); - Chunk chunk = new Chunk(new ChunkPos(Math.floorDiv(x - 8, 16), Math.floorDiv(z - 8, 16))); + Chunk chunk = new Chunk(new ChunkPos(Integer.parseInt(values[0]), Integer.parseInt(values[1]))); - for (int i = 0; i < CSV_FIELDS.size(); i++) { + for (int i = 2; i < CSV_FIELDS.size(); i++) { CSV_FIELDS.get(i).setter().accept(chunk, Integer.parseInt(values[i])); } From 580952e4c99eff9c10efe7330c0a4df1d705c51d Mon Sep 17 00:00:00 2001 From: Big-Iron-Cheems <52252627+Big-Iron-Cheems@users.noreply.github.com> Date: Thu, 27 Aug 2026 14:56:30 +0200 Subject: [PATCH 3/5] refactor(stash-finder): derive world coordinates from chunk position No need to store transient x/z coords and recalculate the values on load. --- .../systems/modules/world/StashFinder.java | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java index aff864f477f..288560b452d 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java @@ -257,7 +257,7 @@ private void onChunkData(ChunkDataEvent event) { if (renderTracer.get()) { double y = mc.player != null ? mc.player.getEyeY() : 0.0; - tracerPositions.put(chunk.chunkPos, new Vec3(chunk.x, y, chunk.z)); + tracerPositions.put(chunk.chunkPos, new Vec3(chunk.chunkPos.getMiddleBlockX(), y, chunk.chunkPos.getMiddleBlockZ())); } saveJson(); @@ -317,14 +317,14 @@ public WWidget getWidget(GuiTheme theme) { private void fillTable(GuiTheme theme, WTable table) { for (Chunk chunk : chunks) { - table.add(theme.label("Pos: " + chunk.x + ", " + chunk.z)).padRight(10); + table.add(theme.label("Pos: " + chunk.chunkPos.getMiddleBlockX() + ", " + chunk.chunkPos.getMiddleBlockZ())).padRight(10); table.add(theme.label("Total: " + chunk.getTotal())).padRight(10); WCheckbox visible = table.add(theme.checkbox(tracerPositions.containsKey(chunk.chunkPos))).widget(); visible.action = () -> { if (visible.checked) { double y = mc.player != null ? mc.player.getEyeY() : 0.0; - tracerPositions.put(chunk.chunkPos, new Vec3(chunk.x, y, chunk.z)); + tracerPositions.put(chunk.chunkPos, new Vec3(chunk.chunkPos.getMiddleBlockX(), y, chunk.chunkPos.getMiddleBlockZ())); } else tracerPositions.remove(chunk.chunkPos); }; @@ -332,7 +332,7 @@ private void fillTable(GuiTheme theme, WTable table) { open.action = () -> mc.gui.setScreen(new ChunkScreen(theme, chunk)); WButton gotoBtn = table.add(theme.button("Goto")).widget(); - gotoBtn.action = () -> PathManagers.get().moveTo(new BlockPos(chunk.x, 0, chunk.z), true); + gotoBtn.action = () -> PathManagers.get().moveTo(new BlockPos(chunk.chunkPos.getMiddleBlockX(), 0, chunk.chunkPos.getMiddleBlockZ()), true); WMinus delete = table.add(theme.minus()).widget(); delete.action = () -> { @@ -359,7 +359,6 @@ private void load() { try (BufferedReader reader = Files.newBufferedReader(jsonFile)) { chunks = GSON.fromJson(reader, new TypeToken>() { }.getType()); - for (Chunk chunk : chunks) chunk.calculatePos(); loaded = true; } catch (Exception _) { if (chunks == null) chunks = new ArrayList<>(); @@ -437,12 +436,12 @@ public String getInfoString() { } private void sendChatNotification(Chunk chunk) { - MutableComponent coords = Component.literal(chunk.x + ", " + chunk.z) + MutableComponent coords = Component.literal(chunk.chunkPos.getMiddleBlockX() + ", " + chunk.chunkPos.getMiddleBlockZ()) .setStyle(Style.EMPTY .withColor(ChatFormatting.WHITE) .applyFormat(ChatFormatting.UNDERLINE) .withHoverEvent(new HoverEvent.ShowText(Component.literal("Path to stash"))) - .withClickEvent(new RunnableClickEvent(() -> PathManagers.get().moveTo(new BlockPos(chunk.x, 0, chunk.z), true)))); + .withClickEvent(new RunnableClickEvent(() -> PathManagers.get().moveTo(new BlockPos(chunk.chunkPos.getMiddleBlockX(), 0, chunk.chunkPos.getMiddleBlockZ()), true)))); MutableComponent message = Component.literal("Found stash at ") .withStyle(ChatFormatting.GRAY) @@ -504,18 +503,10 @@ public enum Mode { public static class Chunk { public ChunkPos chunkPos; - public transient int x, z; public int chests, barrels, shulkers, enderChests, furnaces, dispensersDroppers, hoppers; public Chunk(ChunkPos chunkPos) { this.chunkPos = chunkPos; - - calculatePos(); - } - - public void calculatePos() { - x = chunkPos.x() * 16 + 8; - z = chunkPos.z() * 16 + 8; } public int getTotal() { @@ -553,7 +544,7 @@ private static class ChunkScreen extends WindowScreen { private final Chunk chunk; public ChunkScreen(GuiTheme theme, Chunk chunk) { - super(theme, "Chunk at " + chunk.x + ", " + chunk.z); + super(theme, "Chunk at " + chunk.chunkPos.getMiddleBlockX() + ", " + chunk.chunkPos.getMiddleBlockZ()); this.chunk = chunk; } From fcdb8cb1acc9e0c005bed0bef6970606f634bf5d Mon Sep 17 00:00:00 2001 From: Big-Iron-Cheems <52252627+Big-Iron-Cheems@users.noreply.github.com> Date: Thu, 27 Aug 2026 14:58:43 +0200 Subject: [PATCH 4/5] refactor(stash-finder): internal chunkPos is effectively final Only the counters are to be mutated at any time. --- .../meteorclient/systems/modules/world/StashFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java index 288560b452d..be4a5dc0498 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java @@ -502,7 +502,7 @@ public enum Mode { } public static class Chunk { - public ChunkPos chunkPos; + public final ChunkPos chunkPos; public int chests, barrels, shulkers, enderChests, furnaces, dispensersDroppers, hoppers; public Chunk(ChunkPos chunkPos) { From beb4b25241e4a6e857c804de4e4ba052b1735e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E8=91=89=20Scarlet?= <93977077+mukjepscarlet@users.noreply.github.com> Date: Thu, 27 Aug 2026 23:49:51 +0800 Subject: [PATCH 5/5] Apply comments --- .../meteorclient/systems/modules/world/StashFinder.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java index be4a5dc0498..6b08e47ed5f 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/StashFinder.java @@ -45,6 +45,7 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.*; import net.minecraft.world.phys.Vec3; +import org.apache.commons.lang3.StringUtils; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -373,7 +374,7 @@ private void load() { String line; while ((line = reader.readLine()) != null) { - String[] values = line.split(","); + String[] values = StringUtils.split(line, ','); if (values.length != CSV_FIELDS.size()) { throw new IllegalStateException("Invalid CSV row length: expected " + CSV_FIELDS.size() + ", got " + values.length); } @@ -400,7 +401,8 @@ private void saveCsv() { String header = CSV_FIELDS.stream() .map(CsvField::name) .collect(Collectors.joining(",")); - writer.write(header + "\n"); + writer.write(header); + writer.newLine(); for (Chunk chunk : chunks) { chunk.write(writer); }