From e00501cda9bec3da79896f098279c2f2a0f1a926 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:51:57 -0400 Subject: [PATCH 01/10] Abstract Waypoint --- .../skyblocker/config/SkyblockerConfig.java | 22 +---- .../config/categories/DungeonsCategory.java | 4 +- .../dungeon/secrets/SecretWaypoint.java | 48 +++------- .../skyblocker/utils/waypoint/Waypoint.java | 95 +++++++++++++++++++ 4 files changed, 112 insertions(+), 57 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index 51f3f09863..8905644ff3 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -2,6 +2,7 @@ import de.hysky.skyblocker.skyblock.item.CustomArmorTrims; import de.hysky.skyblocker.utils.chat.ChatFilterResult; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import dev.isxander.yacl3.config.v2.api.SerialEntry; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -582,7 +583,7 @@ public static class SecretWaypoints { public boolean noInitSecretWaypoints = false; @SerialEntry - public WaypointType waypointType = WaypointType.WAYPOINT; + public Waypoint.Type waypointType = Waypoint.Type.WAYPOINT; @SerialEntry public boolean showSecretText = true; @@ -623,25 +624,6 @@ public static class SecretWaypoints { @SerialEntry public boolean enableDefaultWaypoints = true; } - - public enum WaypointType { - WAYPOINT, - OUTLINED_WAYPOINT, - HIGHLIGHT, - OUTLINED_HIGHLIGHT, - OUTLINE; - - @Override - public String toString() { - return switch (this) { - case WAYPOINT -> "Waypoint"; - case OUTLINED_WAYPOINT -> "Outlined Waypoint"; - case HIGHLIGHT -> "Highlight"; - case OUTLINED_HIGHLIGHT -> "Outlined Highlight"; - case OUTLINE -> "Outline"; - }; - } - } public static class DungeonChestProfit { @SerialEntry diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 2cdde89d8a..fdb1389259 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -2,7 +2,7 @@ import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; -import de.hysky.skyblocker.config.SkyblockerConfig.WaypointType; +import de.hysky.skyblocker.utils.waypoint.Waypoint.Type; import dev.isxander.yacl3.api.ButtonOption; import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; @@ -44,7 +44,7 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .controller(ConfigUtils::createBooleanController) .flag(OptionFlag.GAME_RESTART) .build()) - .option(Option.createBuilder() + .option(Option.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.waypointType")) .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.waypointType.@Tooltip"))) .binding(defaults.locations.dungeons.secretWaypoints.waypointType, diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index a520c73f0f..72cc5ad8ae 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -4,37 +4,35 @@ import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.Entity; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; import java.util.List; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.function.ToDoubleFunction; -public class SecretWaypoint { - private static final float HIGHLIGHT_ALPHA = 0.5f; - private static final float LINE_WIDTH = 5f; +public class SecretWaypoint extends Waypoint { static final List SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman"); + private static final SkyblockerConfig.SecretWaypoints config = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; + private static final Supplier typeSupplier = () -> config.waypointType; final int secretIndex; final Category category; private final Text name; - private final BlockPos pos; private final Vec3d centerPos; - private boolean missing; SecretWaypoint(int secretIndex, JsonObject waypoint, String name, BlockPos pos) { + super(pos, typeSupplier, Category.get(waypoint).colorComponents); this.secretIndex = secretIndex; this.category = Category.get(waypoint); this.name = Text.of(name); - this.pos = pos; this.centerPos = pos.toCenterPos(); - this.missing = true; } static ToDoubleFunction getSquaredDistanceToFunction(Entity entity) { @@ -45,8 +43,9 @@ static Predicate getRangePredicate(Entity entity) { return secretWaypoint -> entity.squaredDistanceTo(secretWaypoint.centerPos) <= 36D; } - boolean shouldRender() { - return category.isEnabled() && missing; + @Override + protected boolean shouldRender() { + return super.shouldRender() && category.isEnabled(); } boolean needsInteraction() { @@ -65,34 +64,13 @@ boolean isBat() { return category.isBat(); } - void setFound() { - this.missing = false; - } - - void setMissing() { - this.missing = true; - } - /** * Renders the secret waypoint, including a filled cube, a beacon beam, the name, and the distance from the player. */ - void render(WorldRenderContext context) { - SkyblockerConfig.SecretWaypoints config = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; - - switch (config.waypointType) { - case WAYPOINT -> RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, category.colorComponents, HIGHLIGHT_ALPHA); - case OUTLINED_WAYPOINT -> { - RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, category.colorComponents, HIGHLIGHT_ALPHA); - RenderHelper.renderOutline(context, new Box(pos), category.colorComponents, LINE_WIDTH, true); - } - case HIGHLIGHT -> RenderHelper.renderFilledThroughWalls(context, pos, category.colorComponents, HIGHLIGHT_ALPHA); - case OUTLINED_HIGHLIGHT -> { - RenderHelper.renderFilledThroughWalls(context, pos, category.colorComponents, HIGHLIGHT_ALPHA); - RenderHelper.renderOutline(context, new Box(pos), category.colorComponents, LINE_WIDTH, true); - } - //TODO In the future, shrink the box for wither essence and items so its more realistic - case OUTLINE -> RenderHelper.renderOutline(context, new Box(pos), category.colorComponents, LINE_WIDTH, true); - } + @Override + protected void render(WorldRenderContext context) { + //TODO In the future, shrink the box for wither essence and items so its more realistic + super.render(context); if (config.showSecretText) { Vec3d posUp = centerPos.add(0, 1, 0); diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java new file mode 100644 index 0000000000..2cb37e6b5f --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java @@ -0,0 +1,95 @@ +package de.hysky.skyblocker.utils.waypoint; + +import de.hysky.skyblocker.utils.render.RenderHelper; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; + +import java.util.function.Supplier; + +public class Waypoint { + protected static final float DEFAULT_HIGHLIGHT_ALPHA = 0.5f; + protected static final float DEFAULT_LINE_WIDTH = 5f; + protected final BlockPos pos; + protected final Box box; + protected final Supplier typeSupplier; + protected final float[] colorComponents; + protected final float alpha; + protected final float lineWidth; + protected final boolean throughWalls; + protected boolean shouldRender; + + protected Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorComponents) { + this(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA); + } + + protected Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorComponents, float alpha) { + this(pos, typeSupplier, colorComponents, alpha, DEFAULT_LINE_WIDTH); + } + + protected Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorComponents, float alpha, float lineWidth) { + this(pos, typeSupplier, colorComponents, alpha, lineWidth, true); + } + + protected Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorComponents, float alpha, float lineWidth, boolean throughWalls) { + this(pos, typeSupplier, colorComponents, alpha, lineWidth, throughWalls, true); + } + + protected Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorComponents, float alpha, float lineWidth, boolean throughWalls, boolean shouldRender) { + this.pos = pos; + this.box = new Box(pos); + this.typeSupplier = typeSupplier; + this.colorComponents = colorComponents; + this.alpha = alpha; + this.lineWidth = lineWidth; + this.throughWalls = throughWalls; + this.shouldRender = shouldRender; + } + + protected boolean shouldRender() { + return shouldRender; + } + + public void setFound() { + this.shouldRender = false; + } + + public void setMissing() { + this.shouldRender = true; + } + + protected void render(WorldRenderContext context) { + switch (typeSupplier.get()) { + case WAYPOINT -> RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, colorComponents, alpha); + case OUTLINED_WAYPOINT -> { + RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, colorComponents, alpha); + RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); + } + case HIGHLIGHT -> RenderHelper.renderFilledThroughWalls(context, pos, colorComponents, alpha); + case OUTLINED_HIGHLIGHT -> { + RenderHelper.renderFilledThroughWalls(context, pos, colorComponents, alpha); + RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); + } + case OUTLINE -> RenderHelper.renderOutline(context, box, colorComponents, lineWidth, throughWalls); + } + } + + public enum Type { + WAYPOINT, + OUTLINED_WAYPOINT, + HIGHLIGHT, + OUTLINED_HIGHLIGHT, + OUTLINE; + + @Override + public String toString() { + return switch (this) { + case WAYPOINT -> "Waypoint"; + case OUTLINED_WAYPOINT -> "Outlined Waypoint"; + case HIGHLIGHT -> "Highlight"; + case OUTLINED_HIGHLIGHT -> "Outlined Highlight"; + case OUTLINE -> "Outline"; + }; + } + } +} From 4d9329a9388bd366d6853615efbce5cb5c328643 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 23 Oct 2023 21:44:48 -0400 Subject: [PATCH 02/10] Abstract MythologicalRitual Waypoints --- .../skyblock/diana/MythologicalRitual.java | 23 +++++++++++++------ .../dungeon/secrets/SecretWaypoint.java | 4 ++-- .../skyblocker/utils/waypoint/Waypoint.java | 22 ++++++++++-------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java b/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java index c407e9119f..e29627028f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/diana/MythologicalRitual.java @@ -6,6 +6,7 @@ import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; @@ -49,7 +50,7 @@ public class MythologicalRitual { private static final Map griffinBurrows = new HashMap<>(); @Nullable private static BlockPos lastDugBurrowPos; - private static GriffinBurrow previousBurrow = new GriffinBurrow(); + private static GriffinBurrow previousBurrow = new GriffinBurrow(BlockPos.ORIGIN); public static void init() { WorldRenderEvents.AFTER_TRANSLUCENT.register(MythologicalRitual::render); @@ -82,7 +83,7 @@ public static void onParticle(ParticleS2CPacket packet) { if (MinecraftClient.getInstance().world == null || !MinecraftClient.getInstance().world.getBlockState(pos).isOf(Blocks.GRASS_BLOCK)) { return; } - GriffinBurrow burrow = griffinBurrows.computeIfAbsent(pos, pos1 -> new GriffinBurrow()); + GriffinBurrow burrow = griffinBurrows.computeIfAbsent(pos, GriffinBurrow::new); if (ParticleTypes.CRIT.equals(packet.getParameters().getType())) burrow.critParticle++; if (ParticleTypes.ENCHANT.equals(packet.getParameters().getType())) burrow.enchantParticle++; if (burrow.critParticle >= 5 && burrow.enchantParticle >= 5 && burrow.confirmed == TriState.FALSE) { @@ -133,10 +134,9 @@ public static void onParticle(ParticleS2CPacket packet) { public static void render(WorldRenderContext context) { if (isActive()) { - for (Map.Entry burrowEntry : griffinBurrows.entrySet()) { - GriffinBurrow burrow = burrowEntry.getValue(); - if (burrow.confirmed == TriState.TRUE) { - RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, burrowEntry.getKey(), ORANGE_COLOR_COMPONENTS, 0.25F); + for (GriffinBurrow burrow : griffinBurrows.values()) { + if (burrow.shouldRender()) { + burrow.render(context); } if (burrow.confirmed != TriState.FALSE) { if (burrow.nextBurrowPlane != null) { @@ -186,7 +186,7 @@ private static boolean isActive() { return SkyblockerConfigManager.get().general.mythologicalRitual.enableMythologicalRitualHelper && Utils.getLocationRaw().equals("hub"); } - private static class GriffinBurrow { + private static class GriffinBurrow extends Waypoint { private int critParticle; private int enchantParticle; private TriState confirmed = TriState.FALSE; @@ -196,9 +196,18 @@ private static class GriffinBurrow { private Vec3d[] echoBurrowDirection; private Vec3d[] echoBurrowPlane; + private GriffinBurrow(BlockPos pos) { + super(pos, Type.WAYPOINT, ORANGE_COLOR_COMPONENTS, 0.25F); + } + private void init() { confirmed = TriState.TRUE; regression.clear(); } + + @Override + public boolean shouldRender() { + return super.shouldRender() && confirmed == TriState.TRUE; + } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index 72cc5ad8ae..ab6d6f7d36 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -44,7 +44,7 @@ static Predicate getRangePredicate(Entity entity) { } @Override - protected boolean shouldRender() { + public boolean shouldRender() { return super.shouldRender() && category.isEnabled(); } @@ -68,7 +68,7 @@ boolean isBat() { * Renders the secret waypoint, including a filled cube, a beacon beam, the name, and the distance from the player. */ @Override - protected void render(WorldRenderContext context) { + public void render(WorldRenderContext context) { //TODO In the future, shrink the box for wither essence and items so its more realistic super.render(context); diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java index 2cb37e6b5f..26190d60d9 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java @@ -11,18 +11,22 @@ public class Waypoint { protected static final float DEFAULT_HIGHLIGHT_ALPHA = 0.5f; protected static final float DEFAULT_LINE_WIDTH = 5f; protected final BlockPos pos; - protected final Box box; - protected final Supplier typeSupplier; - protected final float[] colorComponents; - protected final float alpha; - protected final float lineWidth; - protected final boolean throughWalls; - protected boolean shouldRender; + private final Box box; + private final Supplier typeSupplier; + private final float[] colorComponents; + private final float alpha; + private final float lineWidth; + private final boolean throughWalls; + private boolean shouldRender; protected Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorComponents) { this(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA); } + protected Waypoint(BlockPos pos, Type type, float[] colorComponents, float alpha) { + this(pos, () -> type, colorComponents, alpha); + } + protected Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorComponents, float alpha) { this(pos, typeSupplier, colorComponents, alpha, DEFAULT_LINE_WIDTH); } @@ -46,7 +50,7 @@ protected Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorCompo this.shouldRender = shouldRender; } - protected boolean shouldRender() { + public boolean shouldRender() { return shouldRender; } @@ -58,7 +62,7 @@ public void setMissing() { this.shouldRender = true; } - protected void render(WorldRenderContext context) { + public void render(WorldRenderContext context) { switch (typeSupplier.get()) { case WAYPOINT -> RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, pos, colorComponents, alpha); case OUTLINED_WAYPOINT -> { From 739eeb014e31aec54ad12b4ef14f95eca4bc2dea Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 23 Oct 2023 22:47:15 -0400 Subject: [PATCH 03/10] Support for adding custom waypoints --- .../dungeon/secrets/DungeonSecrets.java | 51 +++++++++++- .../dungeon/secrets/SecretWaypoint.java | 80 ++++++++++++------- 2 files changed, 98 insertions(+), 33 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index 08b848527e..38dc106038 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -5,13 +5,16 @@ import com.google.gson.JsonObject; import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import it.unimi.dsi.fastutil.objects.Object2ByteMap; import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIntPair; @@ -24,6 +27,8 @@ import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.command.argument.BlockPosArgumentType; +import net.minecraft.command.argument.PosArgument; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AmbientEntity; @@ -33,6 +38,7 @@ import net.minecraft.item.Items; import net.minecraft.item.map.MapState; import net.minecraft.resource.Resource; +import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.Identifier; @@ -101,6 +107,7 @@ public class DungeonSecrets { private static final Map rooms = new HashMap<>(); private static final Map roomsJson = new HashMap<>(); private static final Map waypointsJson = new HashMap<>(); + private static final Map customWaypoints = new HashMap<>(); @Nullable private static CompletableFuture roomsLoaded; /** @@ -154,7 +161,10 @@ public static void init() { .then(literal("markAsFound").then(markSecretsCommand(true))) .then(literal("markAsMissing").then(markSecretsCommand(false))) .then(literal("getRelativePos").executes(context -> getRelativePos(context.getSource()))) - .then(literal("getRelativeTargetPos").executes(context -> getRelativeTargetPos(context.getSource()))))))); + .then(literal("getRelativeTargetPos").executes(context -> getRelativeTargetPos(context.getSource()))) + .then(literal("addWaypoint").then(addWaypointCommand(false))) + .then(literal("addWaypointRelatively").then(addWaypointCommand(true))) + )))); ClientPlayConnectionEvents.JOIN.register(((handler, sender, client) -> reset())); } @@ -253,6 +263,42 @@ private static int getRelativePos(FabricClientCommandSource source, BlockPos pos return Command.SINGLE_SUCCESS; } + private static ArgumentBuilder> addWaypointCommand(boolean relative) { + return argument("pos", BlockPosArgumentType.blockPos()) + .then(argument("secretIndex", IntegerArgumentType.integer()) + .then(argument("category", SecretWaypoint.Category.CategoryArgumentType.category()) + .then(argument("name", StringArgumentType.greedyString()).executes(context -> { + // TODO Less hacky way with custom ClientBlockPosArgumentType + BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); + return relative ? addWaypointRelative(context, pos) : addWaypoint(context, pos); + })) + ) + ); + } + + private static int addWaypoint(CommandContext context, BlockPos pos) { + Room room = getRoomAtPhysical(pos); + if (isRoomMatched(room)) { + addWaypointRelative(context, room, room.actualToRelative(pos)); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static int addWaypointRelative(CommandContext context, BlockPos pos) { + if (isCurrentRoomMatched()) { + addWaypointRelative(context, currentRoom, pos); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static void addWaypointRelative(CommandContext context, Room room, BlockPos pos) { + customWaypoints.put(room.getName(), new SecretWaypoint(IntegerArgumentType.getInteger(context, "secretIndex"), SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"), StringArgumentType.getString(context, "name"), pos)); + } + /** * Updates the dungeon. The general idea is similar to the Dungeon Rooms Mod. *

@@ -326,7 +372,8 @@ private static void update() { } switch (type) { case ENTRANCE, PUZZLE, TRAP, MINIBOSS, FAIRY, BLOOD -> room = newRoom(type, physicalPos); - case ROOM -> room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color))); + case ROOM -> + room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color))); } } if (room != null && currentRoom != room) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index ab6d6f7d36..5fbce68a91 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -1,15 +1,20 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; import com.google.gson.JsonObject; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; +import net.minecraft.command.argument.EnumArgumentType; import net.minecraft.entity.Entity; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import net.minecraft.util.StringIdentifiable; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -28,9 +33,13 @@ public class SecretWaypoint extends Waypoint { private final Vec3d centerPos; SecretWaypoint(int secretIndex, JsonObject waypoint, String name, BlockPos pos) { - super(pos, typeSupplier, Category.get(waypoint).colorComponents); + this(secretIndex, Category.get(waypoint), name, pos); + } + + SecretWaypoint(int secretIndex, Category category, String name, BlockPos pos) { + super(pos, typeSupplier, category.colorComponents); this.secretIndex = secretIndex; - this.category = Category.get(waypoint); + this.category = category; this.name = Text.of(name); this.centerPos = pos.toCenterPos(); } @@ -80,23 +89,26 @@ public void render(WorldRenderContext context) { } } - enum Category { - ENTRANCE(secretWaypoints -> secretWaypoints.enableEntranceWaypoints, 0, 255, 0), - SUPERBOOM(secretWaypoints -> secretWaypoints.enableSuperboomWaypoints, 255, 0, 0), - CHEST(secretWaypoints -> secretWaypoints.enableChestWaypoints, 2, 213, 250), - ITEM(secretWaypoints -> secretWaypoints.enableItemWaypoints, 2, 64, 250), - BAT(secretWaypoints -> secretWaypoints.enableBatWaypoints, 142, 66, 0), - WITHER(secretWaypoints -> secretWaypoints.enableWitherWaypoints, 30, 30, 30), - LEVER(secretWaypoints -> secretWaypoints.enableLeverWaypoints, 250, 217, 2), - FAIRYSOUL(secretWaypoints -> secretWaypoints.enableFairySoulWaypoints, 255, 85, 255), - STONK(secretWaypoints -> secretWaypoints.enableStonkWaypoints, 146, 52, 235), - AOTV(secretWaypoints -> secretWaypoints.enableAotvWaypoints, 252, 98, 3), - PEARL(secretWaypoints -> secretWaypoints.enablePearlWaypoints, 57, 117, 125), - DEFAULT(secretWaypoints -> secretWaypoints.enableDefaultWaypoints, 190, 255, 252); + enum Category implements StringIdentifiable { + ENTRANCE("entrance", secretWaypoints -> secretWaypoints.enableEntranceWaypoints, 0, 255, 0), + SUPERBOOM("superboom", secretWaypoints -> secretWaypoints.enableSuperboomWaypoints, 255, 0, 0), + CHEST("chest", secretWaypoints -> secretWaypoints.enableChestWaypoints, 2, 213, 250), + ITEM("item", secretWaypoints -> secretWaypoints.enableItemWaypoints, 2, 64, 250), + BAT("bat", secretWaypoints -> secretWaypoints.enableBatWaypoints, 142, 66, 0), + WITHER("wither", secretWaypoints -> secretWaypoints.enableWitherWaypoints, 30, 30, 30), + LEVER("lever", secretWaypoints -> secretWaypoints.enableLeverWaypoints, 250, 217, 2), + FAIRYSOUL("fairysoul", secretWaypoints -> secretWaypoints.enableFairySoulWaypoints, 255, 85, 255), + STONK("stonk", secretWaypoints -> secretWaypoints.enableStonkWaypoints, 146, 52, 235), + AOTV("aotv", secretWaypoints -> secretWaypoints.enableAotvWaypoints, 252, 98, 3), + PEARL("pearl", secretWaypoints -> secretWaypoints.enablePearlWaypoints, 57, 117, 125), + DEFAULT("default", secretWaypoints -> secretWaypoints.enableDefaultWaypoints, 190, 255, 252); + private static final Codec CODEC = StringIdentifiable.createCodec(Category::values); + private final String name; private final Predicate enabledPredicate; private final float[] colorComponents; - Category(Predicate enabledPredicate, int... intColorComponents) { + Category(String name, Predicate enabledPredicate, int... intColorComponents) { + this.name = name; this.enabledPredicate = enabledPredicate; colorComponents = new float[intColorComponents.length]; for (int i = 0; i < intColorComponents.length; i++) { @@ -104,21 +116,8 @@ enum Category { } } - private static Category get(JsonObject categoryJson) { - return switch (categoryJson.get("category").getAsString()) { - case "entrance" -> Category.ENTRANCE; - case "superboom" -> Category.SUPERBOOM; - case "chest" -> Category.CHEST; - case "item" -> Category.ITEM; - case "bat" -> Category.BAT; - case "wither" -> Category.WITHER; - case "lever" -> Category.LEVER; - case "fairysoul" -> Category.FAIRYSOUL; - case "stonk" -> Category.STONK; - case "aotv" -> Category.AOTV; - case "pearl" -> Category.PEARL; - default -> Category.DEFAULT; - }; + private static Category get(JsonObject waypointJson) { + return CODEC.parse(JsonOps.INSTANCE, waypointJson.get("category")).resultOrPartial(DungeonSecrets.LOGGER::error).orElseThrow(); } boolean needsInteraction() { @@ -140,5 +139,24 @@ boolean isBat() { boolean isEnabled() { return enabledPredicate.test(SkyblockerConfigManager.get().locations.dungeons.secretWaypoints); } + + @Override + public String asString() { + return name; + } + + static class CategoryArgumentType extends EnumArgumentType { + public CategoryArgumentType() { + super(Category.CODEC, Category::values); + } + + public static CategoryArgumentType category() { + return new CategoryArgumentType(); + } + + public static Category getCategory(CommandContext context, String name) { + return context.getArgument(name, Category.class); + } + } } } From 47d80b6fabe48b5e5aab3ec800046e8cc3b2fdf5 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 23 Oct 2023 23:20:17 -0400 Subject: [PATCH 04/10] Render custom waypoints --- .../skyblock/dungeon/secrets/DungeonSecrets.java | 9 +++++++-- .../hysky/skyblocker/skyblock/dungeon/secrets/Room.java | 3 +++ .../de/hysky/skyblocker/utils/waypoint/Waypoint.java | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index 38dc106038..45eed5954c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -1,5 +1,7 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -14,7 +16,6 @@ import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; -import de.hysky.skyblocker.utils.waypoint.Waypoint; import it.unimi.dsi.fastutil.objects.Object2ByteMap; import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIntPair; @@ -107,7 +108,7 @@ public class DungeonSecrets { private static final Map rooms = new HashMap<>(); private static final Map roomsJson = new HashMap<>(); private static final Map waypointsJson = new HashMap<>(); - private static final Map customWaypoints = new HashMap<>(); + private static final Multimap customWaypoints = MultimapBuilder.hashKeys().arrayListValues().build(); @Nullable private static CompletableFuture roomsLoaded; /** @@ -139,6 +140,10 @@ public static JsonArray getRoomWaypoints(String room) { return waypointsJson.get(room).getAsJsonArray(); } + public static Collection getCustomWaypoints(String room) { + return customWaypoints.get(room); + } + /** * Loads the dungeon secrets asynchronously from {@code /assets/skyblocker/dungeons}. * Use {@link #isRoomsLoaded()} to check for completion of loading. diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index 0d7a444f31..0840c727f2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -307,6 +307,9 @@ private void roomMatched() { BlockPos pos = DungeonMapUtils.relativeToActual(direction, physicalCornerPos, waypoint); secretWaypointsMutable.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); } + for (SecretWaypoint customWaypoint : DungeonSecrets.getCustomWaypoints(name)) { + secretWaypointsMutable.put(customWaypoint.secretIndex, customWaypoint.pos, customWaypoint); + } secretWaypoints = ImmutableTable.copyOf(secretWaypointsMutable); matched = TriState.TRUE; diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java index 26190d60d9..e7858f058b 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java @@ -10,7 +10,7 @@ public class Waypoint { protected static final float DEFAULT_HIGHLIGHT_ALPHA = 0.5f; protected static final float DEFAULT_LINE_WIDTH = 5f; - protected final BlockPos pos; + public final BlockPos pos; private final Box box; private final Supplier typeSupplier; private final float[] colorComponents; From 1f358759f30925726756afa21405396a4ffc23d4 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Tue, 24 Oct 2023 00:08:44 -0400 Subject: [PATCH 05/10] Apply custom waypoint to existing rooms --- .../dungeon/secrets/DungeonSecrets.java | 21 ++++++++++------ .../skyblock/dungeon/secrets/Room.java | 25 +++++++++++++++---- .../dungeon/secrets/SecretWaypoint.java | 8 ++++-- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index 45eed5954c..461cbf68c2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -61,6 +61,7 @@ import java.io.ObjectInputStream; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; import java.util.zip.InflaterInputStream; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; @@ -131,6 +132,10 @@ public static boolean isRoomsLoaded() { return roomsLoaded != null && roomsLoaded.isDone(); } + public static Stream getRoomsStream() { + return rooms.values().stream(); + } + @SuppressWarnings("unused") public static JsonObject getRoomMetadata(String room) { return roomsJson.get(room).getAsJsonObject(); @@ -144,6 +149,11 @@ public static Collection getCustomWaypoints(String room) { return customWaypoints.get(room); } + @SuppressWarnings("UnusedReturnValue") + public static boolean addCustomWaypoint(String room, SecretWaypoint waypoint) { + return customWaypoints.put(room, waypoint); + } + /** * Loads the dungeon secrets asynchronously from {@code /assets/skyblocker/dungeons}. * Use {@link #isRoomsLoaded()} to check for completion of loading. @@ -284,7 +294,7 @@ private static ArgumentBuilder context, BlockPos pos) { Room room = getRoomAtPhysical(pos); if (isRoomMatched(room)) { - addWaypointRelative(context, room, room.actualToRelative(pos)); + room.addWaypoint(context, room.actualToRelative(pos)); } else { context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); } @@ -293,17 +303,13 @@ private static int addWaypoint(CommandContext context private static int addWaypointRelative(CommandContext context, BlockPos pos) { if (isCurrentRoomMatched()) { - addWaypointRelative(context, currentRoom, pos); + currentRoom.addWaypoint(context, pos); } else { context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); } return Command.SINGLE_SUCCESS; } - private static void addWaypointRelative(CommandContext context, Room room, BlockPos pos) { - customWaypoints.put(room.getName(), new SecretWaypoint(IntegerArgumentType.getInteger(context, "secretIndex"), SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"), StringArgumentType.getString(context, "name"), pos)); - } - /** * Updates the dungeon. The general idea is similar to the Dungeon Rooms Mod. *

@@ -377,8 +383,7 @@ private static void update() { } switch (type) { case ENTRANCE, PUZZLE, TRAP, MINIBOSS, FAIRY, BLOOD -> room = newRoom(type, physicalPos); - case ROOM -> - room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color))); + case ROOM -> room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color))); } } if (room != null && currentRoom != room) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index 0840c727f2..c5b374a950 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -1,14 +1,17 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableTable; import com.google.common.collect.Table; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.ints.IntRBTreeSet; import it.unimi.dsi.fastutil.ints.IntSortedSet; import it.unimi.dsi.fastutil.ints.IntSortedSets; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.util.TriState; import net.minecraft.block.BlockState; @@ -153,6 +156,17 @@ private Direction[] getPossibleDirections(IntSortedSet segmentsX, IntSortedSet s }; } + protected void addWaypoint(CommandContext context, BlockPos pos) { + String roomName = getName(); + SecretWaypoint secretWaypoint = new SecretWaypoint(IntegerArgumentType.getInteger(context, "secretIndex"), SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"), StringArgumentType.getString(context, "name"), pos); + DungeonSecrets.addCustomWaypoint(roomName, secretWaypoint); + DungeonSecrets.getRoomsStream().filter(r -> roomName.equals(r.getName())).forEach(r -> { + BlockPos actualPos = r.relativeToActual(pos); + SecretWaypoint actualWaypoint = new SecretWaypoint(secretWaypoint.secretIndex, secretWaypoint.category, secretWaypoint.name, actualPos); + r.secretWaypoints.put(secretWaypoint.secretIndex, actualPos, actualWaypoint); + }); + } + /** * Updates the room. *

@@ -299,18 +313,19 @@ private int posIdToInt(BlockPos pos, byte id) { */ @SuppressWarnings("JavadocReference") private void roomMatched() { - Table secretWaypointsMutable = HashBasedTable.create(); + secretWaypoints = HashBasedTable.create(); for (JsonElement waypointElement : DungeonSecrets.getRoomWaypoints(name)) { JsonObject waypoint = waypointElement.getAsJsonObject(); String secretName = waypoint.get("secretName").getAsString(); int secretIndex = Integer.parseInt(secretName.substring(0, Character.isDigit(secretName.charAt(1)) ? 2 : 1)); BlockPos pos = DungeonMapUtils.relativeToActual(direction, physicalCornerPos, waypoint); - secretWaypointsMutable.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); + secretWaypoints.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); } for (SecretWaypoint customWaypoint : DungeonSecrets.getCustomWaypoints(name)) { - secretWaypointsMutable.put(customWaypoint.secretIndex, customWaypoint.pos, customWaypoint); + BlockPos actualPos = relativeToActual(customWaypoint.pos); + SecretWaypoint actualWaypoint = new SecretWaypoint(customWaypoint.secretIndex, customWaypoint.category, customWaypoint.name, actualPos); + secretWaypoints.put(customWaypoint.secretIndex, actualPos, actualWaypoint); } - secretWaypoints = ImmutableTable.copyOf(secretWaypointsMutable); matched = TriState.TRUE; DungeonSecrets.LOGGER.info("[Skyblocker] Room {} matched after checking {} block(s)", name, checkedBlocks.size()); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index 5fbce68a91..d896bf3532 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -29,7 +29,7 @@ public class SecretWaypoint extends Waypoint { private static final Supplier typeSupplier = () -> config.waypointType; final int secretIndex; final Category category; - private final Text name; + final Text name; private final Vec3d centerPos; SecretWaypoint(int secretIndex, JsonObject waypoint, String name, BlockPos pos) { @@ -37,10 +37,14 @@ public class SecretWaypoint extends Waypoint { } SecretWaypoint(int secretIndex, Category category, String name, BlockPos pos) { + this(secretIndex, category, Text.of(name), pos); + } + + SecretWaypoint(int secretIndex, Category category, Text name, BlockPos pos) { super(pos, typeSupplier, category.colorComponents); this.secretIndex = secretIndex; this.category = category; - this.name = Text.of(name); + this.name = name; this.centerPos = pos.toCenterPos(); } From f29e54360776c0dffbaf4d23b6250e40edcdb2f6 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Tue, 24 Oct 2023 21:50:11 -0400 Subject: [PATCH 06/10] Refactor and add Javadocs --- .../dungeon/secrets/DungeonSecrets.java | 19 +++++--- .../skyblock/dungeon/secrets/Room.java | 45 +++++++++++++------ .../dungeon/secrets/SecretWaypoint.java | 16 ++++--- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index 461cbf68c2..215fa33a05 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -109,6 +109,9 @@ public class DungeonSecrets { private static final Map rooms = new HashMap<>(); private static final Map roomsJson = new HashMap<>(); private static final Map waypointsJson = new HashMap<>(); + /** + * The map of dungeon room names to custom waypoints relative to the room. + */ private static final Multimap customWaypoints = MultimapBuilder.hashKeys().arrayListValues().build(); @Nullable private static CompletableFuture roomsLoaded; @@ -145,10 +148,16 @@ public static JsonArray getRoomWaypoints(String room) { return waypointsJson.get(room).getAsJsonArray(); } + /** + * @see #customWaypoints + */ public static Collection getCustomWaypoints(String room) { return customWaypoints.get(room); } + /** + * @see #customWaypoints + */ @SuppressWarnings("UnusedReturnValue") public static boolean addCustomWaypoint(String room, SecretWaypoint waypoint) { return customWaypoints.put(room, waypoint); @@ -285,25 +294,25 @@ private static ArgumentBuilder { // TODO Less hacky way with custom ClientBlockPosArgumentType BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); - return relative ? addWaypointRelative(context, pos) : addWaypoint(context, pos); + return relative ? addCustomWaypointRelative(context, pos) : addCustomWaypoint(context, pos); })) ) ); } - private static int addWaypoint(CommandContext context, BlockPos pos) { + private static int addCustomWaypoint(CommandContext context, BlockPos pos) { Room room = getRoomAtPhysical(pos); if (isRoomMatched(room)) { - room.addWaypoint(context, room.actualToRelative(pos)); + room.addCustomWaypoint(context, room.actualToRelative(pos)); } else { context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); } return Command.SINGLE_SUCCESS; } - private static int addWaypointRelative(CommandContext context, BlockPos pos) { + private static int addCustomWaypointRelative(CommandContext context, BlockPos pos) { if (isCurrentRoomMatched()) { - currentRoom.addWaypoint(context, pos); + currentRoom.addCustomWaypoint(context, pos); } else { context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index c5b374a950..7430fc0bb4 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -156,15 +156,36 @@ private Direction[] getPossibleDirections(IntSortedSet segmentsX, IntSortedSet s }; } - protected void addWaypoint(CommandContext context, BlockPos pos) { - String roomName = getName(); - SecretWaypoint secretWaypoint = new SecretWaypoint(IntegerArgumentType.getInteger(context, "secretIndex"), SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"), StringArgumentType.getString(context, "name"), pos); - DungeonSecrets.addCustomWaypoint(roomName, secretWaypoint); - DungeonSecrets.getRoomsStream().filter(r -> roomName.equals(r.getName())).forEach(r -> { - BlockPos actualPos = r.relativeToActual(pos); - SecretWaypoint actualWaypoint = new SecretWaypoint(secretWaypoint.secretIndex, secretWaypoint.category, secretWaypoint.name, actualPos); - r.secretWaypoints.put(secretWaypoint.secretIndex, actualPos, actualWaypoint); - }); + /** + * @see #addCustomWaypoint(int, SecretWaypoint.Category, String, BlockPos) + */ + protected void addCustomWaypoint(CommandContext context, BlockPos pos) { + addCustomWaypoint(IntegerArgumentType.getInteger(context, "secretIndex"), SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"), StringArgumentType.getString(context, "name"), pos); + } + + /** + * Adds a custom waypoint relative to this room to {@link DungeonSecrets#customWaypoints} and all existing instances of this room. + * + * @param secretIndex the index of the secret waypoint + * @param category the category of the secret waypoint + * @param waypointName the name of the secret waypoint + * @param pos the position of the secret waypoint relative to this room + */ + @SuppressWarnings("JavadocReference") + private void addCustomWaypoint(int secretIndex, SecretWaypoint.Category category, String waypointName, BlockPos pos) { + SecretWaypoint waypoint = new SecretWaypoint(secretIndex, category, waypointName, pos); + DungeonSecrets.addCustomWaypoint(name, waypoint); + DungeonSecrets.getRoomsStream().filter(r -> name.equals(r.getName())).forEach(r -> r.addCustomWaypoint(waypoint)); + } + + /** + * Adds a custom waypoint relative to this room to this room. + * + * @param relativeWaypoint the secret waypoint relative to this room to add + */ + private void addCustomWaypoint(SecretWaypoint relativeWaypoint) { + SecretWaypoint actualWaypoint = relativeWaypoint.relativeToActual(this); + secretWaypoints.put(actualWaypoint.secretIndex, actualWaypoint.pos, actualWaypoint); } /** @@ -321,11 +342,7 @@ private void roomMatched() { BlockPos pos = DungeonMapUtils.relativeToActual(direction, physicalCornerPos, waypoint); secretWaypoints.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); } - for (SecretWaypoint customWaypoint : DungeonSecrets.getCustomWaypoints(name)) { - BlockPos actualPos = relativeToActual(customWaypoint.pos); - SecretWaypoint actualWaypoint = new SecretWaypoint(customWaypoint.secretIndex, customWaypoint.category, customWaypoint.name, actualPos); - secretWaypoints.put(customWaypoint.secretIndex, actualPos, actualWaypoint); - } + DungeonSecrets.getCustomWaypoints(name).forEach(this::addCustomWaypoint); matched = TriState.TRUE; DungeonSecrets.LOGGER.info("[Skyblocker] Room {} matched after checking {} block(s)", name, checkedBlocks.size()); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index d896bf3532..cb32e6389f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -17,6 +17,7 @@ import net.minecraft.util.StringIdentifiable; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.function.Predicate; @@ -25,8 +26,8 @@ public class SecretWaypoint extends Waypoint { static final List SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman"); - private static final SkyblockerConfig.SecretWaypoints config = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; - private static final Supplier typeSupplier = () -> config.waypointType; + private static final SkyblockerConfig.SecretWaypoints CONFIG = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; + private static final Supplier TYPE_SUPPLIER = () -> CONFIG.waypointType; final int secretIndex; final Category category; final Text name; @@ -41,7 +42,7 @@ public class SecretWaypoint extends Waypoint { } SecretWaypoint(int secretIndex, Category category, Text name, BlockPos pos) { - super(pos, typeSupplier, category.colorComponents); + super(pos, TYPE_SUPPLIER, category.colorComponents); this.secretIndex = secretIndex; this.category = category; this.name = name; @@ -85,7 +86,7 @@ public void render(WorldRenderContext context) { //TODO In the future, shrink the box for wither essence and items so its more realistic super.render(context); - if (config.showSecretText) { + if (CONFIG.showSecretText) { Vec3d posUp = centerPos.add(0, 1, 0); RenderHelper.renderText(context, name, posUp, true); double distance = context.camera().getPos().distanceTo(centerPos); @@ -93,6 +94,11 @@ public void render(WorldRenderContext context) { } } + @NotNull + SecretWaypoint relativeToActual(Room room) { + return new SecretWaypoint(secretIndex, category, name, room.relativeToActual(pos)); + } + enum Category implements StringIdentifiable { ENTRANCE("entrance", secretWaypoints -> secretWaypoints.enableEntranceWaypoints, 0, 255, 0), SUPERBOOM("superboom", secretWaypoints -> secretWaypoints.enableSuperboomWaypoints, 255, 0, 0), @@ -158,7 +164,7 @@ public static CategoryArgumentType category() { return new CategoryArgumentType(); } - public static Category getCategory(CommandContext context, String name) { + public static Category getCategory(CommandContext context, String name) { return context.getArgument(name, Category.class); } } From 0af4be135ad0b5739a53cea9911cf011bc7d5c21 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 25 Oct 2023 09:14:33 -0400 Subject: [PATCH 07/10] Adding custom waypoint feedback --- .../de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java | 7 ++++++- .../skyblock/dungeon/secrets/SecretWaypoint.java | 5 +++++ src/main/resources/assets/skyblocker/lang/en_us.json | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index 7430fc0bb4..f553fbda6b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -24,6 +24,7 @@ import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AmbientEntity; import net.minecraft.registry.Registries; +import net.minecraft.text.Text; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -160,7 +161,11 @@ private Direction[] getPossibleDirections(IntSortedSet segmentsX, IntSortedSet s * @see #addCustomWaypoint(int, SecretWaypoint.Category, String, BlockPos) */ protected void addCustomWaypoint(CommandContext context, BlockPos pos) { - addCustomWaypoint(IntegerArgumentType.getInteger(context, "secretIndex"), SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"), StringArgumentType.getString(context, "name"), pos); + int secretIndex = IntegerArgumentType.getInteger(context, "secretIndex"); + SecretWaypoint.Category category = SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"); + String waypointName = StringArgumentType.getString(context, "name"); + addCustomWaypoint(secretIndex, category, waypointName, pos); + context.getSource().sendFeedback(Text.translatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category, waypointName)); } /** diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index cb32e6389f..aa700cad3f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -150,6 +150,11 @@ boolean isEnabled() { return enabledPredicate.test(SkyblockerConfigManager.get().locations.dungeons.secretWaypoints); } + @Override + public String toString() { + return name; + } + @Override public String asString() { return name; diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 1d000825b7..3ead2954b3 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -273,6 +273,7 @@ "skyblocker.dungeons.secrets.markSecretFoundUnable": "§cUnable to mark secret #%d as found.", "skyblocker.dungeons.secrets.markSecretMissingUnable": "§cUnable to mark secret #%d as missing.", "skyblocker.dungeons.secrets.posMessage": "§rRoom: %s, X: %d, Y: %d, Z: %d", + "skyblocker.dungeons.secrets.customWaypointAdded": "§rAdded a custom waypoint at X: %d, Y: %d, Z: %d for room %s secret #%d of category %s with name '%s'.", "skyblocker.dungeons.secrets.noTarget": "§cNo target block found! (Are you pointing at a block in range?)", "skyblocker.dungeons.secrets.notMatched": "§cThe current room is not matched! (Are you in a dungeon room?)", From 789a87322687a9172522f371ea919f656554a40b Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 26 Oct 2023 19:33:55 -0400 Subject: [PATCH 08/10] Add custom secret waypoints saving and loading --- .../dungeon/secrets/DungeonSecrets.java | 53 ++++++++++++++----- .../dungeon/secrets/SecretWaypoint.java | 8 +++ .../skyblock/item/BackpackPreview.java | 4 +- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index 215fa33a05..77b3192979 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -11,6 +11,7 @@ import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; +import com.mojang.serialization.JsonOps; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Constants; @@ -21,6 +22,7 @@ import it.unimi.dsi.fastutil.objects.ObjectIntPair; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; @@ -57,8 +59,11 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.IOException; import java.io.ObjectInputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; @@ -70,6 +75,7 @@ public class DungeonSecrets { protected static final Logger LOGGER = LoggerFactory.getLogger(DungeonSecrets.class); private static final String DUNGEONS_PATH = "dungeons"; + private static final Path CUSTOM_WAYPOINTS_DIR = SkyblockerMod.CONFIG_DIR.resolve("custom_secret_waypoints.json"); /** * Maps the block identifier string to a custom numeric block id used in dungeon rooms data. * @@ -173,9 +179,10 @@ public static void init() { } // Execute with MinecraftClient as executor since we need to wait for MinecraftClient#resourceManager to be set CompletableFuture.runAsync(DungeonSecrets::load, MinecraftClient.getInstance()).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets", e); return null; }); + ClientLifecycleEvents.CLIENT_STOPPING.register(DungeonSecrets::saveCustomWaypoints); Scheduler.INSTANCE.scheduleCyclic(DungeonSecrets::update, 10); WorldRenderEvents.AFTER_TRANSLUCENT.register(DungeonSecrets::render); ClientReceiveMessageEvents.GAME.register(DungeonSecrets::onChatMessage); @@ -198,7 +205,7 @@ private static void load() { for (Map.Entry resourceEntry : MinecraftClient.getInstance().getResourceManager().findResources(DUNGEONS_PATH, id -> id.getPath().endsWith(".skeleton")).entrySet()) { String[] path = resourceEntry.getKey().getPath().split("/"); if (path.length != 4) { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets, invalid resource identifier {}", resourceEntry.getKey()); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets, invalid resource identifier {}", resourceEntry.getKey()); break; } String dungeon = path[1]; @@ -211,9 +218,9 @@ private static void load() { synchronized (roomsMap) { roomsMap.put(room, rooms); } - LOGGER.debug("[Skyblocker] Loaded dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room); }).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room, e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets dungeon {} room shape {} room {}", dungeon, roomShape, room, e); return null; })); } @@ -221,16 +228,37 @@ private static void load() { try (BufferedReader roomsReader = MinecraftClient.getInstance().getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "dungeons/dungeonrooms.json")); BufferedReader waypointsReader = MinecraftClient.getInstance().getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "dungeons/secretlocations.json"))) { loadJson(roomsReader, roomsJson); loadJson(waypointsReader, waypointsJson); - LOGGER.debug("[Skyblocker] Loaded dungeon secrets json"); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded dungeon secret waypoints json"); } catch (Exception e) { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets json", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secret waypoints json", e); } })); - roomsLoaded = CompletableFuture.allOf(dungeonFutures.toArray(CompletableFuture[]::new)).thenRun(() -> LOGGER.info("[Skyblocker] Loaded dungeon secrets for {} dungeon(s), {} room shapes, and {} rooms total in {} ms", ROOMS_DATA.size(), ROOMS_DATA.values().stream().mapToInt(Map::size).sum(), ROOMS_DATA.values().stream().map(Map::values).flatMap(Collection::stream).mapToInt(Map::size).sum(), System.currentTimeMillis() - startTime)).exceptionally(e -> { - LOGGER.error("[Skyblocker] Failed to load dungeon secrets", e); + dungeonFutures.add(CompletableFuture.runAsync(() -> { + try (BufferedReader customWaypointsReader = Files.newBufferedReader(CUSTOM_WAYPOINTS_DIR)) { + SkyblockerMod.GSON.fromJson(customWaypointsReader, JsonObject.class).asMap().forEach( + (room, jsonElement) -> addCustomWaypoint(room, SecretWaypoint.CODEC.parse(JsonOps.INSTANCE, jsonElement).resultOrPartial(LOGGER::error).orElseThrow()) + ); + LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded custom dungeon secret waypoints"); + } catch (Exception e) { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load custom dungeon secret waypoints", e); + } + })); + roomsLoaded = CompletableFuture.allOf(dungeonFutures.toArray(CompletableFuture[]::new)).thenRun(() -> LOGGER.info("[Skyblocker Dungeon Secrets] Loaded dungeon secrets for {} dungeon(s), {} room shapes, {} rooms, and {} custom secret waypoints total in {} ms", ROOMS_DATA.size(), ROOMS_DATA.values().stream().mapToInt(Map::size).sum(), ROOMS_DATA.values().stream().map(Map::values).flatMap(Collection::stream).mapToInt(Map::size).sum(), customWaypoints.size(), System.currentTimeMillis() - startTime)).exceptionally(e -> { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to load dungeon secrets", e); return null; }); - LOGGER.info("[Skyblocker] Started loading dungeon secrets in (blocked main thread for) {} ms", System.currentTimeMillis() - startTime); + LOGGER.info("[Skyblocker Dungeon Secrets] Started loading dungeon secrets in (blocked main thread for) {} ms", System.currentTimeMillis() - startTime); + } + + private static void saveCustomWaypoints(MinecraftClient client) { + try (BufferedWriter writer = Files.newBufferedWriter(CUSTOM_WAYPOINTS_DIR)) { + JsonArray customWaypointsArray = new JsonArray(); + customWaypoints.forEach((room, waypoint) -> customWaypointsArray.add(SecretWaypoint.CODEC.encodeStart(JsonOps.INSTANCE, waypoint).resultOrPartial(LOGGER::error).orElseThrow())); + SkyblockerMod.GSON.toJson(customWaypointsArray, writer); + LOGGER.info("[Skyblocker Dungeon Secrets] Saved custom dungeon secret waypoints"); + } catch (Exception e) { + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to save custom dungeon secret waypoints", e); + } } private static int[] readRoom(Resource resource) throws RuntimeException { @@ -379,7 +407,7 @@ private static void update() { } mapEntrancePos = mapEntrancePosAndSize.left(); mapRoomSize = mapEntrancePosAndSize.rightInt(); - LOGGER.info("[Skyblocker] Started dungeon with map room size {}, map entrance pos {}, player pos {}, and physical entrance pos {}", mapRoomSize, mapEntrancePos, client.player.getPos(), physicalEntrancePos); + LOGGER.info("[Skyblocker Dungeon Secrets] Started dungeon with map room size {}, map entrance pos {}, player pos {}, and physical entrance pos {}", mapRoomSize, mapEntrancePos, client.player.getPos(), physicalEntrancePos); } Vector2ic physicalPos = DungeonMapUtils.getPhysicalRoomPos(client.player.getPos()); @@ -392,7 +420,8 @@ private static void update() { } switch (type) { case ENTRANCE, PUZZLE, TRAP, MINIBOSS, FAIRY, BLOOD -> room = newRoom(type, physicalPos); - case ROOM -> room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color))); + case ROOM -> + room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color))); } } if (room != null && currentRoom != room) { @@ -417,7 +446,7 @@ private static Room newRoom(Room.Type type, Vector2ic... physicalPositions) { } return newRoom; } catch (IllegalArgumentException e) { - LOGGER.error("[Skyblocker] Failed to create room", e); + LOGGER.error("[Skyblocker Dungeon Secrets] Failed to create room", e); } return null; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index aa700cad3f..96d81a3000 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.render.RenderHelper; @@ -15,6 +16,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.StringIdentifiable; +import net.minecraft.util.dynamic.Codecs; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.NotNull; @@ -25,6 +27,12 @@ import java.util.function.ToDoubleFunction; public class SecretWaypoint extends Waypoint { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("secretIndex").forGetter(secretWaypoint -> secretWaypoint.secretIndex), + Category.CODEC.fieldOf("category").forGetter(secretWaypoint -> secretWaypoint.category), + Codecs.TEXT.fieldOf("name").forGetter(secretWaypoint -> secretWaypoint.name), + BlockPos.CODEC.fieldOf("pos").forGetter(secretWaypoint -> secretWaypoint.pos) + ).apply(instance, SecretWaypoint::new)); static final List SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman"); private static final SkyblockerConfig.SecretWaypoints CONFIG = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; private static final Supplier TYPE_SUPPLIER = () -> CONFIG.waypointType; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/BackpackPreview.java b/src/main/java/de/hysky/skyblocker/skyblock/item/BackpackPreview.java index d621d38808..8782440c94 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/BackpackPreview.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/BackpackPreview.java @@ -1,10 +1,10 @@ package de.hysky.skyblocker.skyblock.item; import com.mojang.blaze3d.systems.RenderSystem; +import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; -import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -60,7 +60,7 @@ public static void tick() { // update save dir based on sb profile id String id = MinecraftClient.getInstance().getSession().getUuidOrNull().toString().replaceAll("-", "") + "/" + Utils.getProfileId(); if (!id.equals(loaded)) { - saveDir = FabricLoader.getInstance().getConfigDir().resolve("skyblocker/backpack-preview/" + id); + saveDir = SkyblockerMod.CONFIG_DIR.resolve("backpack-preview/" + id); //noinspection ResultOfMethodCallIgnored saveDir.toFile().mkdirs(); // load storage again because profile id changed From 58ba4ddfdca59d359100c0e42c97a0e6727ea9fa Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:41:56 -0400 Subject: [PATCH 09/10] Fix serialization --- .../dungeon/secrets/DungeonSecrets.java | 49 ++++++++++++------- .../skyblock/dungeon/secrets/Room.java | 5 +- .../dungeon/secrets/SecretWaypoint.java | 1 + 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index 77b3192979..81e73e1a41 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -118,7 +118,7 @@ public class DungeonSecrets { /** * The map of dungeon room names to custom waypoints relative to the room. */ - private static final Multimap customWaypoints = MultimapBuilder.hashKeys().arrayListValues().build(); + private static final Table customWaypoints = HashBasedTable.create(); @Nullable private static CompletableFuture roomsLoaded; /** @@ -157,16 +157,25 @@ public static JsonArray getRoomWaypoints(String room) { /** * @see #customWaypoints */ - public static Collection getCustomWaypoints(String room) { - return customWaypoints.get(room); + public static Map getCustomWaypoints(String room) { + return customWaypoints.row(room); } /** * @see #customWaypoints */ @SuppressWarnings("UnusedReturnValue") - public static boolean addCustomWaypoint(String room, SecretWaypoint waypoint) { - return customWaypoints.put(room, waypoint); + public static SecretWaypoint addCustomWaypoint(String room, SecretWaypoint waypoint) { + return customWaypoints.put(room, waypoint.pos, waypoint); + } + + /** + * @see #customWaypoints + */ + public static void addCustomWaypoints(String room, Collection waypoints) { + for (SecretWaypoint waypoint : waypoints) { + addCustomWaypoint(room, waypoint); + } } /** @@ -191,8 +200,8 @@ public static void init() { ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("secrets") .then(literal("markAsFound").then(markSecretsCommand(true))) .then(literal("markAsMissing").then(markSecretsCommand(false))) - .then(literal("getRelativePos").executes(context -> getRelativePos(context.getSource()))) - .then(literal("getRelativeTargetPos").executes(context -> getRelativeTargetPos(context.getSource()))) + .then(literal("getRelativePos").executes(DungeonSecrets::getRelativePos)) + .then(literal("getRelativeTargetPos").executes(DungeonSecrets::getRelativeTargetPos)) .then(literal("addWaypoint").then(addWaypointCommand(false))) .then(literal("addWaypointRelatively").then(addWaypointCommand(true))) )))); @@ -235,8 +244,8 @@ private static void load() { })); dungeonFutures.add(CompletableFuture.runAsync(() -> { try (BufferedReader customWaypointsReader = Files.newBufferedReader(CUSTOM_WAYPOINTS_DIR)) { - SkyblockerMod.GSON.fromJson(customWaypointsReader, JsonObject.class).asMap().forEach( - (room, jsonElement) -> addCustomWaypoint(room, SecretWaypoint.CODEC.parse(JsonOps.INSTANCE, jsonElement).resultOrPartial(LOGGER::error).orElseThrow()) + SkyblockerMod.GSON.fromJson(customWaypointsReader, JsonObject.class).asMap().forEach((room, waypointsJson) -> + addCustomWaypoints(room, SecretWaypoint.LIST_CODEC.parse(JsonOps.INSTANCE, waypointsJson).resultOrPartial(LOGGER::error).orElseThrow()) ); LOGGER.debug("[Skyblocker Dungeon Secrets] Loaded custom dungeon secret waypoints"); } catch (Exception e) { @@ -252,9 +261,11 @@ private static void load() { private static void saveCustomWaypoints(MinecraftClient client) { try (BufferedWriter writer = Files.newBufferedWriter(CUSTOM_WAYPOINTS_DIR)) { - JsonArray customWaypointsArray = new JsonArray(); - customWaypoints.forEach((room, waypoint) -> customWaypointsArray.add(SecretWaypoint.CODEC.encodeStart(JsonOps.INSTANCE, waypoint).resultOrPartial(LOGGER::error).orElseThrow())); - SkyblockerMod.GSON.toJson(customWaypointsArray, writer); + JsonObject customWaypointsJson = new JsonObject(); + customWaypoints.rowMap().forEach((room, waypoints) -> + customWaypointsJson.add(room, SecretWaypoint.LIST_CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseThrow()) + ); + SkyblockerMod.GSON.toJson(customWaypointsJson, writer); LOGGER.info("[Skyblocker Dungeon Secrets] Saved custom dungeon secret waypoints"); } catch (Exception e) { LOGGER.error("[Skyblocker Dungeon Secrets] Failed to save custom dungeon secret waypoints", e); @@ -291,15 +302,15 @@ private static ArgumentBuilder context) { + return getRelativePos(context.getSource(), context.getSource().getPlayer().getBlockPos()); } - private static int getRelativeTargetPos(FabricClientCommandSource source) { + private static int getRelativeTargetPos(CommandContext context) { if (MinecraftClient.getInstance().crosshairTarget instanceof BlockHitResult blockHitResult && blockHitResult.getType() == HitResult.Type.BLOCK) { - return getRelativePos(source, blockHitResult.getBlockPos()); + return getRelativePos(context.getSource(), blockHitResult.getBlockPos()); } else { - source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.noTarget"))); + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.noTarget"))); } return Command.SINGLE_SUCCESS; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index f553fbda6b..7b7fe4c02d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -7,6 +7,7 @@ import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.ints.IntRBTreeSet; import it.unimi.dsi.fastutil.ints.IntSortedSet; @@ -165,7 +166,7 @@ protected void addCustomWaypoint(CommandContext conte SecretWaypoint.Category category = SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"); String waypointName = StringArgumentType.getString(context, "name"); addCustomWaypoint(secretIndex, category, waypointName, pos); - context.getSource().sendFeedback(Text.translatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category, waypointName)); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category, waypointName))); } /** @@ -347,7 +348,7 @@ private void roomMatched() { BlockPos pos = DungeonMapUtils.relativeToActual(direction, physicalCornerPos, waypoint); secretWaypoints.put(secretIndex, pos, new SecretWaypoint(secretIndex, waypoint, secretName, pos)); } - DungeonSecrets.getCustomWaypoints(name).forEach(this::addCustomWaypoint); + DungeonSecrets.getCustomWaypoints(name).values().forEach(this::addCustomWaypoint); matched = TriState.TRUE; DungeonSecrets.LOGGER.info("[Skyblocker] Room {} matched after checking {} block(s)", name, checkedBlocks.size()); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index 96d81a3000..0c2d1b3452 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -33,6 +33,7 @@ public class SecretWaypoint extends Waypoint { Codecs.TEXT.fieldOf("name").forGetter(secretWaypoint -> secretWaypoint.name), BlockPos.CODEC.fieldOf("pos").forGetter(secretWaypoint -> secretWaypoint.pos) ).apply(instance, SecretWaypoint::new)); + public static final Codec> LIST_CODEC = CODEC.listOf(); static final List SECRET_ITEMS = List.of("Decoy", "Defuse Kit", "Dungeon Chest Key", "Healing VIII", "Inflatable Jerry", "Spirit Leap", "Training Weights", "Trap", "Treasure Talisman"); private static final SkyblockerConfig.SecretWaypoints CONFIG = SkyblockerConfigManager.get().locations.dungeons.secretWaypoints; private static final Supplier TYPE_SUPPLIER = () -> CONFIG.waypointType; From 16467d786b89cc628e932b7e2091ab304d1b6b46 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:53:38 -0400 Subject: [PATCH 10/10] Add custom waypoints removing --- .../dungeon/secrets/DungeonSecrets.java | 55 ++++++++++++++++--- .../skyblock/dungeon/secrets/Room.java | 47 ++++++++++++++-- .../assets/skyblocker/lang/en_us.json | 4 +- 3 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index 81e73e1a41..eda08cf6be 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -7,7 +7,6 @@ import com.google.gson.JsonObject; import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.IntegerArgumentType; -import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; @@ -32,6 +31,7 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.command.argument.BlockPosArgumentType; import net.minecraft.command.argument.PosArgument; +import net.minecraft.command.argument.TextArgumentType; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AmbientEntity; @@ -178,6 +178,14 @@ public static void addCustomWaypoints(String room, Collection wa } } + /** + * @see #customWaypoints + */ + @Nullable + public static SecretWaypoint removeCustomWaypoint(String room, BlockPos pos) { + return customWaypoints.remove(room, pos); + } + /** * Loads the dungeon secrets asynchronously from {@code /assets/skyblocker/dungeons}. * Use {@link #isRoomsLoaded()} to check for completion of loading. @@ -202,8 +210,10 @@ public static void init() { .then(literal("markAsMissing").then(markSecretsCommand(false))) .then(literal("getRelativePos").executes(DungeonSecrets::getRelativePos)) .then(literal("getRelativeTargetPos").executes(DungeonSecrets::getRelativeTargetPos)) - .then(literal("addWaypoint").then(addWaypointCommand(false))) - .then(literal("addWaypointRelatively").then(addWaypointCommand(true))) + .then(literal("addWaypoint").then(addCustomWaypointCommand(false))) + .then(literal("addWaypointRelatively").then(addCustomWaypointCommand(true))) + .then(literal("removeWaypoint").then(removeCustomWaypointCommand(false))) + .then(literal("removeWaypointRelatively").then(removeCustomWaypointCommand(true))) )))); ClientPlayConnectionEvents.JOIN.register(((handler, sender, client) -> reset())); } @@ -291,8 +301,8 @@ private static void loadJson(BufferedReader reader, Map map } private static ArgumentBuilder> markSecretsCommand(boolean found) { - return argument("secret", IntegerArgumentType.integer()).executes(context -> { - int secretIndex = IntegerArgumentType.getInteger(context, "secret"); + return argument("secretIndex", IntegerArgumentType.integer()).executes(context -> { + int secretIndex = IntegerArgumentType.getInteger(context, "secretIndex"); if (markSecrets(secretIndex, found)) { context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable(found ? "skyblocker.dungeons.secrets.markSecretFound" : "skyblocker.dungeons.secrets.markSecretMissing", secretIndex))); } else { @@ -326,11 +336,11 @@ private static int getRelativePos(FabricClientCommandSource source, BlockPos pos return Command.SINGLE_SUCCESS; } - private static ArgumentBuilder> addWaypointCommand(boolean relative) { + private static ArgumentBuilder> addCustomWaypointCommand(boolean relative) { return argument("pos", BlockPosArgumentType.blockPos()) .then(argument("secretIndex", IntegerArgumentType.integer()) .then(argument("category", SecretWaypoint.Category.CategoryArgumentType.category()) - .then(argument("name", StringArgumentType.greedyString()).executes(context -> { + .then(argument("name", TextArgumentType.text()).executes(context -> { // TODO Less hacky way with custom ClientBlockPosArgumentType BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); return relative ? addCustomWaypointRelative(context, pos) : addCustomWaypoint(context, pos); @@ -358,6 +368,34 @@ private static int addCustomWaypointRelative(CommandContext> removeCustomWaypointCommand(boolean relative) { + return argument("pos", BlockPosArgumentType.blockPos()) + .executes(context -> { + // TODO Less hacky way with custom ClientBlockPosArgumentType + BlockPos pos = context.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(new ServerCommandSource(null, context.getSource().getPosition(), context.getSource().getRotation(), null, 0, null, null, null, null)); + return relative ? removeCustomWaypointRelative(context, pos) : removeCustomWaypoint(context, pos); + }); + } + + private static int removeCustomWaypoint(CommandContext context, BlockPos pos) { + Room room = getRoomAtPhysical(pos); + if (isRoomMatched(room)) { + room.removeCustomWaypoint(context, room.actualToRelative(pos)); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + + private static int removeCustomWaypointRelative(CommandContext context, BlockPos pos) { + if (isCurrentRoomMatched()) { + currentRoom.removeCustomWaypoint(context, pos); + } else { + context.getSource().sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); + } + return Command.SINGLE_SUCCESS; + } + /** * Updates the dungeon. The general idea is similar to the Dungeon Rooms Mod. *

@@ -431,8 +469,7 @@ private static void update() { } switch (type) { case ENTRANCE, PUZZLE, TRAP, MINIBOSS, FAIRY, BLOOD -> room = newRoom(type, physicalPos); - case ROOM -> - room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color))); + case ROOM -> room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color))); } } if (room != null && currentRoom != room) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index 7b7fe4c02d..ecfcf496db 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -5,7 +5,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.brigadier.arguments.IntegerArgumentType; -import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.scheduler.Scheduler; @@ -32,6 +31,7 @@ import org.apache.commons.lang3.tuple.MutableTriple; import org.apache.commons.lang3.tuple.Triple; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.joml.Vector2i; import org.joml.Vector2ic; @@ -159,12 +159,12 @@ private Direction[] getPossibleDirections(IntSortedSet segmentsX, IntSortedSet s } /** - * @see #addCustomWaypoint(int, SecretWaypoint.Category, String, BlockPos) + * @see #addCustomWaypoint(int, SecretWaypoint.Category, Text, BlockPos) */ protected void addCustomWaypoint(CommandContext context, BlockPos pos) { int secretIndex = IntegerArgumentType.getInteger(context, "secretIndex"); SecretWaypoint.Category category = SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"); - String waypointName = StringArgumentType.getString(context, "name"); + Text waypointName = context.getArgument("name", Text.class); addCustomWaypoint(secretIndex, category, waypointName, pos); context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category, waypointName))); } @@ -178,14 +178,14 @@ protected void addCustomWaypoint(CommandContext conte * @param pos the position of the secret waypoint relative to this room */ @SuppressWarnings("JavadocReference") - private void addCustomWaypoint(int secretIndex, SecretWaypoint.Category category, String waypointName, BlockPos pos) { + private void addCustomWaypoint(int secretIndex, SecretWaypoint.Category category, Text waypointName, BlockPos pos) { SecretWaypoint waypoint = new SecretWaypoint(secretIndex, category, waypointName, pos); DungeonSecrets.addCustomWaypoint(name, waypoint); DungeonSecrets.getRoomsStream().filter(r -> name.equals(r.getName())).forEach(r -> r.addCustomWaypoint(waypoint)); } /** - * Adds a custom waypoint relative to this room to this room. + * Adds a custom waypoint relative to this room to this instance of the room. * * @param relativeWaypoint the secret waypoint relative to this room to add */ @@ -194,6 +194,43 @@ private void addCustomWaypoint(SecretWaypoint relativeWaypoint) { secretWaypoints.put(actualWaypoint.secretIndex, actualWaypoint.pos, actualWaypoint); } + /** + * @see #removeCustomWaypoint(BlockPos) + */ + protected void removeCustomWaypoint(CommandContext context, BlockPos pos) { + SecretWaypoint waypoint = removeCustomWaypoint(pos); + if (waypoint != null) { + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointRemoved", pos.getX(), pos.getY(), pos.getZ(), name, waypoint.secretIndex, waypoint.category, waypoint.name))); + } else { + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointNotFound", pos.getX(), pos.getY(), pos.getZ(), name))); + } + } + + /** + * Removes a custom waypoint relative to this room from {@link DungeonSecrets#customWaypoints} and all existing instances of this room. + * @param pos the position of the secret waypoint relative to this room + * @return the removed secret waypoint or {@code null} if there was no secret waypoint at the given position + */ + @SuppressWarnings("JavadocReference") + @Nullable + private SecretWaypoint removeCustomWaypoint(BlockPos pos) { + SecretWaypoint waypoint = DungeonSecrets.removeCustomWaypoint(name, pos); + if (waypoint != null) { + DungeonSecrets.getRoomsStream().filter(r -> name.equals(r.getName())).forEach(r -> r.removeCustomWaypoint(waypoint.secretIndex, pos)); + } + return waypoint; + } + + /** + * Removes a custom waypoint relative to this room from this instance of the room. + * @param secretIndex the index of the secret waypoint + * @param relativePos the position of the secret waypoint relative to this room + */ + private void removeCustomWaypoint(int secretIndex, BlockPos relativePos) { + BlockPos actualPos = relativeToActual(relativePos); + secretWaypoints.remove(secretIndex, actualPos); + } + /** * Updates the room. *

diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 3ead2954b3..8665ce459a 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -273,9 +273,11 @@ "skyblocker.dungeons.secrets.markSecretFoundUnable": "§cUnable to mark secret #%d as found.", "skyblocker.dungeons.secrets.markSecretMissingUnable": "§cUnable to mark secret #%d as missing.", "skyblocker.dungeons.secrets.posMessage": "§rRoom: %s, X: %d, Y: %d, Z: %d", - "skyblocker.dungeons.secrets.customWaypointAdded": "§rAdded a custom waypoint at X: %d, Y: %d, Z: %d for room %s secret #%d of category %s with name '%s'.", "skyblocker.dungeons.secrets.noTarget": "§cNo target block found! (Are you pointing at a block in range?)", "skyblocker.dungeons.secrets.notMatched": "§cThe current room is not matched! (Are you in a dungeon room?)", + "skyblocker.dungeons.secrets.customWaypointAdded": "§rAdded a custom waypoint at X: %d, Y: %d, Z: %d for room %s secret #%d of category %s with name '%s'.", + "skyblocker.dungeons.secrets.customWaypointRemoved": "§rRemoved custom waypoint at X: %d, Y: %d, Z: %d for room %s secret #%d of category %s with name '%s'.", + "skyblocker.dungeons.secrets.customWaypointNotFound": "§cNo custom waypoint found at X: %d, Y: %d, Z: %d for room %s.", "skyblocker.fishing.reelNow": "Reel in now!", "skyblocker.rift.healNow": "Heal now!",