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..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,9 +45,17 @@ 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.*; +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 +179,25 @@ 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.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), + 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 +244,7 @@ private void onChunkData(ChunkDataEvent event) { case DispenserBlockEntity _ -> chunk.dispensersDroppers++; case HopperBlockEntity _ -> chunk.hoppers++; default -> { + // Do not track other block entities } } } @@ -230,7 +258,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(); @@ -290,14 +318,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); }; @@ -305,7 +333,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 = () -> { @@ -327,16 +355,11 @@ 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 +367,26 @@ 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(" "); + 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); + } + Chunk chunk = new Chunk(new ChunkPos(Integer.parseInt(values[0]), Integer.parseInt(values[1]))); - 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]); + for (int i = 2; 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 +395,18 @@ 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); + writer.newLine(); + for (Chunk chunk : chunks) { + chunk.write(writer); + } + } } catch (IOException e) { MeteorClient.LOG.error("Error while writing the stash list to csv", e); } @@ -389,22 +414,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 @@ -413,12 +438,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) @@ -479,32 +504,23 @@ public enum Mode { } public static class Chunk { - private static final StringBuilder sb = new StringBuilder(); - - public ChunkPos chunkPos; - public transient int x, z; + public final ChunkPos chunkPos; 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() { 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) { @@ -530,7 +546,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; }