diff options
| author | viciscat <51047087+viciscat@users.noreply.github.com> | 2025-07-21 21:25:51 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-21 15:25:51 -0400 |
| commit | b0c4c1f669721e5edbe2b4c34d361a000b744b13 (patch) | |
| tree | f49b2e7fb22163d23bcf85fbad93423d6637e7d4 | |
| parent | 4a43f346a9415f338aff68e51d6cd5f62c57608e (diff) | |
| download | Skyblocker-b0c4c1f669721e5edbe2b4c34d361a000b744b13.tar.gz Skyblocker-b0c4c1f669721e5edbe2b4c34d361a000b744b13.tar.bz2 Skyblocker-b0c4c1f669721e5edbe2b4c34d361a000b744b13.zip | |
waypoint import options + fixes (#1434)
* waypoint import options
* actually show error toast if failed to import
5 files changed, 93 insertions, 14 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java index 5184fdd8..c71fb88a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java @@ -31,6 +31,7 @@ import net.minecraft.command.argument.EnumArgumentType; import net.minecraft.text.Text; import net.minecraft.util.StringIdentifiable; import org.apache.commons.io.IOUtils; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -130,21 +131,24 @@ public class Waypoints { } } - public static List<WaypointGroup> fromSkyblocker(String waypointsString, Location defaultIsland) { + public static @Nullable List<WaypointGroup> fromSkyblocker(String waypointsString, Location defaultIsland) { if (waypointsString.startsWith(PREFIX)) { try (GZIPInputStream reader = new GZIPInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(waypointsString.replace(PREFIX, ""))))) { return CODEC.parse(JsonOps.INSTANCE, SkyblockerMod.GSON.fromJson(new String(reader.readAllBytes()), JsonArray.class)).resultOrPartial(LOGGER::error).orElseThrow(); } catch (IOException e) { LOGGER.error("[Skyblocker Waypoints] Encountered exception while parsing Skyblocker waypoint data", e); + return null; } } else if (waypointsString.startsWith(SKYBLOCKER_LEGACY_ORDERED)) { try (GZIPInputStream reader = new GZIPInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(waypointsString.replace(SKYBLOCKER_LEGACY_ORDERED, ""))))) { return applyDefaultLocation(SKYBLOCKER_LEGACY_ORDERED_CODEC.parse(JsonOps.INSTANCE, SkyblockerMod.GSON.fromJson(new String(reader.readAllBytes()), JsonObject.class)).resultOrPartial(LOGGER::error).orElseThrow(), defaultIsland); } catch (IOException e) { LOGGER.error("[Skyblocker Waypoints] Encountered exception while parsing Skyblocker legacy ordered waypoint data", e); + return null; } } - return Collections.emptyList(); + LOGGER.error("[Skyblocker Waypoints] Unknown skyblocker waypoint data prefix"); + return null; } public static String toSkyblocker(List<WaypointGroup> waypointGroups) { @@ -158,7 +162,7 @@ public class Waypoints { return PREFIX + new String(Base64.getEncoder().encode(output.toByteArray())); } - public static List<WaypointGroup> fromSkytils(String waypointsString, Location defaultIsland) { + public static @Nullable List<WaypointGroup> fromSkytils(String waypointsString, Location defaultIsland) { try { if (waypointsString.startsWith("<Skytils-Waypoint-Data>(V")) { int version = Integer.parseInt(waypointsString.substring(25, waypointsString.indexOf(')'))); @@ -173,8 +177,10 @@ public class Waypoints { } else return fromSkytilsJson(new String(Base64.getDecoder().decode(waypointsString)), defaultIsland); } catch (NumberFormatException e) { LOGGER.error("[Skyblocker Waypoints] Encountered exception while parsing Skytils waypoint data version", e); + return null; } catch (Exception e) { LOGGER.error("[Skyblocker Waypoints] Encountered exception while decoding Skytils waypoint data", e); + return null; } return Collections.emptyList(); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsShareScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsShareScreen.java index 7773c9c9..f3a31135 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsShareScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsShareScreen.java @@ -6,9 +6,7 @@ import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; import de.hysky.skyblocker.utils.waypoint.WaypointGroup; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.GridWidget; -import net.minecraft.client.gui.widget.SimplePositioningWidget; +import net.minecraft.client.gui.widget.*; import net.minecraft.client.toast.SystemToast; import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Text; @@ -20,6 +18,10 @@ import java.util.Set; public class WaypointsShareScreen extends AbstractWaypointsScreen<WaypointsScreen> { private final Set<NamedWaypoint> selectedWaypoints = new HashSet<>(); + // Import options + private boolean overrideLocation = false; + private boolean sortWaypoints = false; + protected WaypointsShareScreen(WaypointsScreen parent, Multimap<Location, WaypointGroup> waypoints) { super(Text.translatable("skyblocker.waypoints.shareWaypoints"), parent, waypoints, parent.island); } @@ -29,11 +31,18 @@ public class WaypointsShareScreen extends AbstractWaypointsScreen<WaypointsScree super.init(); GridWidget gridWidget = new GridWidget(); gridWidget.getMainPositioner().marginX(5).marginY(2); - GridWidget.Adder adder = gridWidget.createAdder(2); + GridWidget.Adder adder = gridWidget.createAdder(3); + // First row adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.importWaypointsSkyblocker"), buttonImport -> { try { List<WaypointGroup> waypointGroups = Waypoints.fromSkyblocker(client.keyboard.getClipboard(), island); + if (waypointGroups == null) { + showErrorToast(); + return; + } for (WaypointGroup waypointGroup : waypointGroups) { + if (overrideLocation) waypointGroup = waypointGroup.withIsland(island); + if (sortWaypoints) waypointGroup = waypointGroup.sortWaypoints(NamedWaypoint.NAME_COMPARATOR); selectedWaypoints.addAll(waypointGroup.waypoints()); waypoints.put(waypointGroup.island(), waypointGroup); } @@ -41,8 +50,8 @@ public class WaypointsShareScreen extends AbstractWaypointsScreen<WaypointsScree SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importSuccess"), Text.translatable("skyblocker.waypoints.importSuccessText", waypointGroups.stream().map(WaypointGroup::waypoints).mapToInt(List::size).sum(), waypointGroups.size())); } catch (Exception e) { Waypoints.LOGGER.error("[Skyblocker Waypoints] Encountered exception while parsing Skyblocker waypoint data", e); - SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importError"), Text.translatable("skyblocker.waypoints.importErrorText")); - } + showErrorToast(); + } }).tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.importWaypointsSkyblocker.tooltip"))).build()); adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.exportWaypointsSkyblocker"), buttonExport -> { try { @@ -54,10 +63,22 @@ public class WaypointsShareScreen extends AbstractWaypointsScreen<WaypointsScree SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.exportError"), Text.translatable("skyblocker.waypoints.exportErrorText")); } }).tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.exportWaypointsSkyblocker.tooltip"))).build()); + adder.add(CheckboxWidget.builder(Text.translatable("skyblocker.waypoints.importOptions.overrideLocation"), textRenderer) + .maxWidth(ButtonWidget.DEFAULT_WIDTH) + .callback((checkbox, checked) -> overrideLocation = checked) + .tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.importOptions.overrideLocation.tooltip"))) + .build()); + // Second row adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.importWaypointsSkytils"), buttonImport -> { try { List<WaypointGroup> waypointGroups = Waypoints.fromSkytils(client.keyboard.getClipboard(), island); + if (waypointGroups == null) { + showErrorToast(); + return; + } for (WaypointGroup waypointGroup : waypointGroups) { + if (overrideLocation) waypointGroup = waypointGroup.withIsland(island); + if (sortWaypoints) waypointGroup = waypointGroup.sortWaypoints(NamedWaypoint.NAME_COMPARATOR); selectedWaypoints.addAll(waypointGroup.waypoints()); waypoints.put(waypointGroup.island(), waypointGroup); } @@ -65,8 +86,8 @@ public class WaypointsShareScreen extends AbstractWaypointsScreen<WaypointsScree SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importSuccess"), Text.translatable("skyblocker.waypoints.importSuccessText", waypointGroups.stream().map(WaypointGroup::waypoints).mapToInt(List::size).sum(), waypointGroups.size())); } catch (Exception e) { Waypoints.LOGGER.error("[Skyblocker Waypoints] Encountered exception while parsing Skytils waypoint data", e); - SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importError"), Text.translatable("skyblocker.waypoints.importErrorText")); - } + showErrorToast(); + } }).tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.importWaypointsSkytils.tooltip"))).build()); adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.exportWaypointsSkytils"), buttonExport -> { try { @@ -78,17 +99,26 @@ public class WaypointsShareScreen extends AbstractWaypointsScreen<WaypointsScree SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.exportError"), Text.translatable("skyblocker.waypoints.exportErrorText")); } }).tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.exportWaypointsSkytils.tooltip"))).build()); + adder.add(CheckboxWidget.builder(Text.translatable("skyblocker.waypoints.importOptions.sortWaypoints"), textRenderer) + .maxWidth(ButtonWidget.DEFAULT_WIDTH) + .callback((checkbox, checked) -> sortWaypoints = checked) + .tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.importOptions.sortWaypoints.tooltip"))) + .build()); + + // Third row adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.importWaypointsSnoopy"), buttonImport -> { try { WaypointGroup waypointGroup = Waypoints.fromColeweightJson(client.keyboard.getClipboard(), island); + if (overrideLocation) waypointGroup = waypointGroup.withIsland(island); + if (sortWaypoints) waypointGroup = waypointGroup.sortWaypoints(NamedWaypoint.NAME_COMPARATOR); selectedWaypoints.addAll(waypointGroup.waypoints()); waypoints.put(waypointGroup.island(), waypointGroup); waypointsListWidget.updateEntries(); SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importSuccess"), Text.translatable("skyblocker.waypoints.importSuccessText", waypointGroup.waypoints().size(), 1)); } catch (Exception e) { Waypoints.LOGGER.error("[Skyblocker Waypoints] Encountered exception while parsing Snoopy waypoint data", e); - SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importError"), Text.translatable("skyblocker.waypoints.importErrorText")); - } + showErrorToast(); + } }).tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.importWaypointsSnoopy.tooltip"))).build()); adder.add(ButtonWidget.builder(ScreenTexts.DONE, buttonBack -> close()).build()); gridWidget.refreshPositions(); @@ -96,7 +126,11 @@ public class WaypointsShareScreen extends AbstractWaypointsScreen<WaypointsScree gridWidget.forEachChild(this::addDrawableChild); } - @Override + private void showErrorToast() { + SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importError"), Text.translatable("skyblocker.waypoints.importErrorText")); + } + + @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { super.render(context, mouseX, mouseY, delta); context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 16, 0xFFFFFF); diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java index 8387be4d..6be3cdb1 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java @@ -17,6 +17,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ColorHelper; import net.minecraft.util.math.Vec3d; +import java.util.Comparator; import java.util.Objects; import java.util.Optional; import java.util.OptionalDouble; @@ -56,6 +57,8 @@ public class NamedWaypoint extends Waypoint { Codec.floatRange(0, 1).listOf().xmap(Floats::toArray, FloatArrayList::new).optionalFieldOf("colorComponents", new float[0]).forGetter(waypoint -> waypoint.colorComponents) ).apply(instance, (pos, colorComponents) -> new OrderedNamedWaypoint(pos, "", new float[]{0, 1, 0}))); + public static final Comparator<NamedWaypoint> NAME_COMPARATOR = new NameComparator(); + public final Text name; public final Vec3d centerPos; @@ -169,4 +172,31 @@ public class NamedWaypoint extends Waypoint { Codec.either(Codec.STRING, Codec.INT).xmap(either -> either.map(Function.identity(), Object::toString), Either::left).optionalFieldOf("name").forGetter(ColeweightOptions::name) ).apply(instance, ColeweightOptions::new)); } + + private static class NameComparator implements Comparator<NamedWaypoint> { + + @Override + public int compare(NamedWaypoint o1, NamedWaypoint o2) { + String string1 = o1.getName().getString(); + String string2 = o2.getName().getString(); + + String prefix1 = string1.replaceFirst("\\d+$", ""); + String prefix2 = string2.replaceFirst("\\d+$", ""); + + int i = prefix1.compareTo(prefix2); + if (i != 0) return i; + + String num1 = string1.substring(prefix1.length()); + String num2 = string2.substring(prefix2.length()); + if (num1.isEmpty() || num2.isEmpty()) return string1.compareTo(string2); + + try { + int i1 = Integer.parseInt(num1); + int i2 = Integer.parseInt(num2); + return Integer.compare(i1, i2); + } catch (NumberFormatException e) { + return string1.compareTo(string2); + } + } + } } diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointGroup.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointGroup.java index 200b4eaa..6a4c50e1 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointGroup.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointGroup.java @@ -8,6 +8,7 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; import net.minecraft.util.math.BlockPos; +import java.util.Comparator; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -100,6 +101,10 @@ public class WaypointGroup { return new WaypointGroup(name, island, waypoints.stream().filter(predicate).toList(), ordered); } + public WaypointGroup sortWaypoints(Comparator<NamedWaypoint> comparator) { + return new WaypointGroup(name, island, waypoints.stream().sorted(comparator).toList(), ordered); + } + /** * Returns a deep copy of this {@link WaypointGroup} with a mutable waypoints list for editing. */ diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 377b2dac..5447f383 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -1328,6 +1328,10 @@ "skyblocker.waypoints.importWaypointsSnoopy.tooltip": "Import Waypoints from Clipboard (Snoopy Format)", "skyblocker.waypoints.exportWaypointsSkytils": "Export Waypoints (Skytils)", "skyblocker.waypoints.exportWaypointsSkytils.tooltip": "Export Waypoints to Clipboard (Skytils Format)", + "skyblocker.waypoints.importOptions.overrideLocation": "Override Location", + "skyblocker.waypoints.importOptions.overrideLocation.tooltip": "Import the waypoints in the currently selected location instead of the one saved.", + "skyblocker.waypoints.importOptions.sortWaypoints": "Sort Waypoints", + "skyblocker.waypoints.importOptions.sortWaypoints.tooltip": "Sorts the imported waypoints based on their names.", "skyblocker.waypoints.importSuccess": "Waypoints Imported", "skyblocker.waypoints.importSuccessText": "Successfully imported %d waypoint(s) from %d group(s).", "skyblocker.waypoints.importError": "Error Importing Waypoints", |
