Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -171,6 +179,25 @@ public class StashFinder extends Module {
);

private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

private record CsvField(String name, ToIntFunction<Chunk> getter, ObjIntConsumer<Chunk> setter) {
public CsvField(String name, ToIntFunction<Chunk> getter) {
this(name, getter, null);
}
}

private static final List<CsvField> 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<ChunkPos, Vec3> tracerPositions = new HashMap<>();
public List<Chunk> chunks = new ArrayList<>();

Expand Down Expand Up @@ -217,6 +244,7 @@ private void onChunkData(ChunkDataEvent event) {
case DispenserBlockEntity _ -> chunk.dispensersDroppers++;
case HopperBlockEntity _ -> chunk.hoppers++;
default -> {
// Do not track other block entities
}
}
}
Expand All @@ -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();
Expand Down Expand Up @@ -290,22 +318,22 @@ 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);
};

WButton open = table.add(theme.button("Open")).widget();
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 = () -> {
Expand All @@ -327,45 +355,38 @@ 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<List<Chunk>>() {
}.getType());
reader.close();

for (Chunk chunk : chunks) chunk.calculatePos();

loaded = true;
} catch (Exception _) {
if (chunks == null) chunks = new ArrayList<>();
}
}

// 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<>();
}
Expand All @@ -374,37 +395,41 @@ 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);
}
}

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
Expand All @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
Expand Down
Loading