diff options
| author | Aaron <51387595+AzureAaron@users.noreply.github.com> | 2023-12-23 16:47:32 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-12-23 16:47:32 -0500 |
| commit | f690b55477a7ee617c09bdc44de7d5410c07b587 (patch) | |
| tree | 1134fe22ab8732381df6f09d2ec2641fc34c9afa /src/main/java/de/hysky/skyblocker/skyblock | |
| parent | e2a13ec7171f6dd21641650a30604e4d3b3361c2 (diff) | |
| parent | a04ba10ad3a43fd4c5624e192f488ac7c77a633d (diff) | |
| download | Skyblocker-f690b55477a7ee617c09bdc44de7d5410c07b587.tar.gz Skyblocker-f690b55477a7ee617c09bdc44de7d5410c07b587.tar.bz2 Skyblocker-f690b55477a7ee617c09bdc44de7d5410c07b587.zip | |
Merge pull request #454 from kevinthegreat1/dungeon-puzzle
Update Dungeon Puzzles
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock')
11 files changed, 414 insertions, 126 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/CreeperBeams.java index 5c7a01f9..8de1e3fe 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CreeperBeams.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/CreeperBeams.java @@ -1,13 +1,10 @@ -package de.hysky.skyblocker.skyblock.dungeon; +package de.hysky.skyblocker.skyblock.dungeon.puzzle; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; -import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.objects.ObjectDoublePair; -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.block.Block; import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; @@ -27,8 +24,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; -public class CreeperBeams { - +public class CreeperBeams extends DungeonPuzzle { private static final Logger LOGGER = LoggerFactory.getLogger(CreeperBeams.class.getName()); private static final float[][] COLORS = { @@ -41,27 +37,30 @@ public class CreeperBeams { private static final int FLOOR_Y = 68; private static final int BASE_Y = 74; + private static final CreeperBeams INSTANCE = new CreeperBeams("creeper", "creeper-room"); private static ArrayList<Beam> beams = new ArrayList<>(); private static BlockPos base = null; - private static boolean solved = false; + + private CreeperBeams(String puzzleName, String... roomName) { + super(puzzleName, roomName); + } public static void init() { - Scheduler.INSTANCE.scheduleCyclic(CreeperBeams::update, 20); - WorldRenderEvents.BEFORE_DEBUG_RENDER.register(CreeperBeams::render); - ClientPlayConnectionEvents.JOIN.register(((handler, sender, client) -> reset())); } - private static void reset() { + @Override + public void reset() { + super.reset(); beams.clear(); base = null; - solved = false; } - private static void update() { + @Override + public void tick() { // don't do anything if the room is solved - if (solved) { + if (!shouldSolve()) { return; } @@ -90,7 +89,7 @@ public class CreeperBeams { // check if the room is solved if (!isTarget(world, base)) { - solved = true; + reset(); } } @@ -176,10 +175,11 @@ public class CreeperBeams { return result; } - private static void render(WorldRenderContext wrc) { + @Override + public void render(WorldRenderContext wrc) { // don't render if solved or disabled - if (solved || !SkyblockerConfigManager.get().locations.dungeons.creeperSolver) { + if (!shouldSolve() || !SkyblockerConfigManager.get().locations.dungeons.creeperSolver) { return; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/DungeonBlaze.java index f49a2f2e..5774eaef 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonBlaze.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/DungeonBlaze.java @@ -1,12 +1,10 @@ -package de.hysky.skyblocker.skyblock.dungeon; +package de.hysky.skyblocker.skyblock.dungeon.puzzle; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; -import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.objects.ObjectIntPair; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; @@ -24,25 +22,32 @@ import java.util.List; /** * This class provides functionality to render outlines around Blaze entities */ -public class DungeonBlaze { +public class DungeonBlaze extends DungeonPuzzle { private static final Logger LOGGER = LoggerFactory.getLogger(DungeonBlaze.class.getName()); private static final float[] GREEN_COLOR_COMPONENTS = {0.0F, 1.0F, 0.0F}; private static final float[] WHITE_COLOR_COMPONENTS = {1.0f, 1.0f, 1.0f}; + private static final DungeonBlaze INSTANCE = new DungeonBlaze("blaze", "blaze-room-1-high", "blaze-room-1-low"); private static ArmorStandEntity highestBlaze = null; private static ArmorStandEntity lowestBlaze = null; private static ArmorStandEntity nextHighestBlaze = null; private static ArmorStandEntity nextLowestBlaze = null; + private DungeonBlaze(String puzzleName, String... roomName) { + super(puzzleName, roomName); + } + public static void init() { - Scheduler.INSTANCE.scheduleCyclic(DungeonBlaze::update, 4); - WorldRenderEvents.BEFORE_DEBUG_RENDER.register(DungeonBlaze::blazeRenderer); } /** * Updates the state of Blaze entities and triggers the rendering process if necessary. */ - public static void update() { + @Override + public void tick() { + if (!shouldSolve()) { + return; + } ClientWorld world = MinecraftClient.getInstance().world; ClientPlayerEntity player = MinecraftClient.getInstance().player; if (world == null || player == null || !Utils.isInDungeons()) return; @@ -104,7 +109,8 @@ public class DungeonBlaze { * * @param wrc The WorldRenderContext used for rendering. */ - public static void blazeRenderer(WorldRenderContext wrc) { + @Override + public void render(WorldRenderContext wrc) { try { if (highestBlaze != null && lowestBlaze != null && highestBlaze.isAlive() && lowestBlaze.isAlive() && SkyblockerConfigManager.get().locations.dungeons.blazeSolver) { if (highestBlaze.getY() < 69) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/DungeonPuzzle.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/DungeonPuzzle.java new file mode 100644 index 00000000..04446e60 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/DungeonPuzzle.java @@ -0,0 +1,58 @@ +package de.hysky.skyblocker.skyblock.dungeon.puzzle; + +import com.mojang.brigadier.Command; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.events.DungeonEvents; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; +import de.hysky.skyblocker.skyblock.dungeon.secrets.Room; +import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.Tickable; +import de.hysky.skyblocker.utils.render.Renderable; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public abstract class DungeonPuzzle implements Tickable, Renderable { + private final String puzzleName; + @NotNull + private final Set<String> roomNames; + private boolean shouldSolve; + + public DungeonPuzzle(String puzzleName, String... roomName) { + this(puzzleName, Set.of(roomName)); + } + + public DungeonPuzzle(String puzzleName, @NotNull Set<String> roomNames) { + this.puzzleName = puzzleName; + this.roomNames = roomNames; + DungeonEvents.PUZZLE_MATCHED.register(room -> { + if (roomNames.contains(room.getName())) { + room.addSubProcess(this); + shouldSolve = true; + } + }); + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("solvePuzzle").then(literal(puzzleName).executes(context -> { + Room currentRoom = DungeonManager.getCurrentRoom(); + if (currentRoom != null) { + currentRoom.addSubProcess(this); + context.getSource().sendFeedback(Constants.PREFIX.get().append("§aSolving " + puzzleName + " puzzle in the current room.")); + } else { + context.getSource().sendError(Constants.PREFIX.get().append("§cCurrent room is null.")); + } + return Command.SINGLE_SUCCESS; + })))))); + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset()); + } + + public boolean shouldSolve() { + return shouldSolve; + } + + public void reset() { + shouldSolve = false; + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/ThreeWeirdos.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdos.java index e1ab2fa8..c5e55f93 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/ThreeWeirdos.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdos.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.skyblock.dungeon; +package de.hysky.skyblocker.skyblock.dungeon.puzzle; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.chat.ChatFilterResult; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TicTacToe.java index 7f249e7d..90028a4f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/TicTacToe.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TicTacToe.java @@ -1,11 +1,10 @@ -package de.hysky.skyblocker.skyblock.dungeon; +package de.hysky.skyblocker.skyblock.dungeon.puzzle; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.tictactoe.TicTacToeUtils; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.block.Block; import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; @@ -25,16 +24,25 @@ import java.util.List; /** * Thanks to Danker for a reference implementation! */ -public class TicTacToe { +public class TicTacToe extends DungeonPuzzle { private static final Logger LOGGER = LoggerFactory.getLogger(TicTacToe.class); private static final float[] RED_COLOR_COMPONENTS = {1.0F, 0.0F, 0.0F}; + private static final TicTacToe INSTANCE = new TicTacToe("tic-tac-toe", "tic-tac-toe-1"); private static Box nextBestMoveToMake = null; + private TicTacToe(String puzzleName, String... roomName) { + super(puzzleName, roomName); + } + public static void init() { - WorldRenderEvents.BEFORE_DEBUG_RENDER.register(TicTacToe::solutionRenderer); } - public static void tick() { + @Override + public void tick() { + if (!shouldSolve()) { + return; + } + MinecraftClient client = MinecraftClient.getInstance(); ClientWorld world = client.world; ClientPlayerEntity player = client.player; @@ -124,7 +132,8 @@ public class TicTacToe { } } - private static void solutionRenderer(WorldRenderContext context) { + @Override + public void render(WorldRenderContext context) { try { if (SkyblockerConfigManager.get().locations.dungeons.solveTicTacToe && nextBestMoveToMake != null) { RenderHelper.renderOutline(context, nextBestMoveToMake, RED_COLOR_COMPONENTS, 5, false); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Trivia.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Trivia.java index 21bbdce0..0f73457c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Trivia.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Trivia.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.skyblock.dungeon; +package de.hysky.skyblocker.skyblock.dungeon.puzzle; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.waypoint.FairySouls; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DebugRoom.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DebugRoom.java new file mode 100644 index 00000000..931d1d69 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DebugRoom.java @@ -0,0 +1,60 @@ +package de.hysky.skyblocker.skyblock.dungeon.secrets; + +import de.hysky.skyblocker.utils.waypoint.Waypoint; +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.rendering.v1.WorldRenderContext; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.registry.Registries; +import net.minecraft.util.math.BlockPos; +import org.apache.commons.lang3.tuple.MutableTriple; +import org.joml.Vector2ic; + +import java.util.*; + +public class DebugRoom extends Room { + private final List<Waypoint> checkedBlocks = Collections.synchronizedList(new ArrayList<>()); + + public DebugRoom(Type type, Vector2ic... physicalPositions) { + super(type, physicalPositions); + } + + public static DebugRoom ofSinglePossibleRoom(Type type, Vector2ic physicalPositions, String roomName, int[] roomData, Direction direction) { + return ofSinglePossibleRoom(type, new Vector2ic[]{physicalPositions}, roomName, roomData, direction); + } + + public static DebugRoom ofSinglePossibleRoom(Type type, Vector2ic[] physicalPositions, String roomName, int[] roomData, Direction direction) { + DebugRoom room = new DebugRoom(type, physicalPositions); + IntSortedSet segmentsX = IntSortedSets.unmodifiable(new IntRBTreeSet(room.segments.stream().mapToInt(Vector2ic::x).toArray())); + IntSortedSet segmentsY = IntSortedSets.unmodifiable(new IntRBTreeSet(room.segments.stream().mapToInt(Vector2ic::y).toArray())); + room.roomsData = Map.of(roomName, roomData); + room.possibleRooms = List.of(MutableTriple.of(direction, DungeonMapUtils.getPhysicalCornerPos(direction, segmentsX, segmentsY), List.of(roomName))); + return room; + } + + @Override + protected boolean checkBlock(ClientWorld world, BlockPos pos) { + byte id = DungeonManager.NUMERIC_ID.getByte(Registries.BLOCK.getId(world.getBlockState(pos).getBlock()).toString()); + if (id == 0) { + return false; + } + for (MutableTriple<Direction, Vector2ic, List<String>> directionRooms : possibleRooms) { + int block = posIdToInt(DungeonMapUtils.actualToRelative(directionRooms.getLeft(), directionRooms.getMiddle(), pos), id); + for (String room : directionRooms.getRight()) { + checkedBlocks.add(new Waypoint(pos, SecretWaypoint.TYPE_SUPPLIER, Arrays.binarySearch(roomsData.get(room), block) >= 0 ? Room.GREEN_COLOR_COMPONENTS : Room.RED_COLOR_COMPONENTS)); + } + } + return false; + } + + @Override + public void render(WorldRenderContext context) { + super.render(context); + synchronized (checkedBlocks) { + for (Waypoint checkedBlock : checkedBlocks) { + checkedBlock.render(context); + } + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java index 7f401fdb..70a0fd8c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java @@ -7,12 +7,14 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.IntegerArgumentType; -import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.arguments.StringArgumentType; 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.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.debug.Debug; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; @@ -27,8 +29,9 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.command.CommandSource; import net.minecraft.command.argument.BlockPosArgumentType; import net.minecraft.command.argument.PosArgument; import net.minecraft.command.argument.TextArgumentType; @@ -37,10 +40,12 @@ import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AmbientEntity; import net.minecraft.entity.passive.BatEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.FilledMapItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.map.MapState; +import net.minecraft.registry.Registry; import net.minecraft.resource.Resource; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; @@ -75,15 +80,15 @@ import java.util.zip.InflaterInputStream; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; -public class DungeonSecrets { - protected static final Logger LOGGER = LoggerFactory.getLogger(DungeonSecrets.class); +public class DungeonManager { + protected static final Logger LOGGER = LoggerFactory.getLogger(DungeonManager.class); private static final String DUNGEONS_PATH = "dungeons"; private static final Path CUSTOM_WAYPOINTS_DIR = SkyblockerMod.CONFIG_DIR.resolve("custom_secret_waypoints.json"); private static final Pattern KEY_FOUND = Pattern.compile("^(?:\\[.+] )?(?<name>\\w+) has obtained (?<type>Wither|Blood) Key!$"); /** * Maps the block identifier string to a custom numeric block id used in dungeon rooms data. * - * @implNote Not using {@link net.minecraft.registry.Registry#getId(Object) Registry#getId(Block)} and {@link net.minecraft.block.Blocks Blocks} since this is also used by {@link de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonRoomsDFU DungeonRoomsDFU}, which runs outside of Minecraft. + * @implNote Not using {@link Registry#getId(Object) Registry#getId(Block)} and {@link Blocks Blocks} since this is also used by {@link de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonRoomsDFU DungeonRoomsDFU}, which runs outside of Minecraft. */ @SuppressWarnings("JavadocReference") protected static final Object2ByteMap<String> NUMERIC_ID = new Object2ByteOpenHashMap<>(Map.ofEntries( @@ -151,11 +156,13 @@ public class DungeonSecrets { @SuppressWarnings("unused") public static JsonObject getRoomMetadata(String room) { - return roomsJson.get(room).getAsJsonObject(); + JsonElement value = roomsJson.get(room); + return value != null ? value.getAsJsonObject() : null; } public static JsonArray getRoomWaypoints(String room) { - return waypointsJson.get(room).getAsJsonArray(); + JsonElement value = waypointsJson.get(room); + return value != null ? value.getAsJsonArray() : null; } /** @@ -190,35 +197,54 @@ public class DungeonSecrets { return customWaypoints.remove(room, pos); } + public static Room getCurrentRoom() { + return currentRoom; + } + /** * Loads the dungeon secrets asynchronously from {@code /assets/skyblocker/dungeons}. * Use {@link #isRoomsLoaded()} to check for completion of loading. */ public static void init() { - if (SkyblockerConfigManager.get().locations.dungeons.secretWaypoints.noInitSecretWaypoints) { + if (!SkyblockerConfigManager.get().locations.dungeons.secretWaypoints.enableRoomMatching) { return; } // Execute with MinecraftClient as executor since we need to wait for MinecraftClient#resourceManager to be set - CompletableFuture.runAsync(DungeonSecrets::load, MinecraftClient.getInstance()).exceptionally(e -> { + CompletableFuture.runAsync(DungeonManager::load, MinecraftClient.getInstance()).exceptionally(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); - ClientReceiveMessageEvents.GAME_CANCELED.register(DungeonSecrets::onChatMessage); + ClientLifecycleEvents.CLIENT_STOPPING.register(DungeonManager::saveCustomWaypoints); + Scheduler.INSTANCE.scheduleCyclic(DungeonManager::update, 5); + WorldRenderEvents.AFTER_TRANSLUCENT.register(DungeonManager::render); + ClientReceiveMessageEvents.GAME.register(DungeonManager::onChatMessage); + ClientReceiveMessageEvents.GAME_CANCELED.register(DungeonManager::onChatMessage); UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> onUseBlock(world, hitResult)); 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(DungeonSecrets::getRelativePos)) - .then(literal("getRelativeTargetPos").executes(DungeonSecrets::getRelativeTargetPos)) + .then(literal("getRelativePos").executes(DungeonManager::getRelativePos)) + .then(literal("getRelativeTargetPos").executes(DungeonManager::getRelativeTargetPos)) .then(literal("addWaypoint").then(addCustomWaypointCommand(false))) .then(literal("addWaypointRelatively").then(addCustomWaypointCommand(true))) .then(literal("removeWaypoint").then(removeCustomWaypointCommand(false))) .then(literal("removeWaypointRelatively").then(removeCustomWaypointCommand(true))) )))); + if (Debug.debugEnabled()) { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("secrets") + .then(literal("matchAgainst").then(matchAgainstCommand())) + .then(literal("clearSubProcesses").executes(context -> { + if (currentRoom != null) { + currentRoom.tickables.clear(); + currentRoom.renderables.clear(); + context.getSource().sendFeedback(Constants.PREFIX.get().append("§rCleared sub processes in the current room.")); + } else { + context.getSource().sendError(Constants.PREFIX.get().append("§cCurrent room is null.")); + } + return Command.SINGLE_SUCCESS; + })) + )))); + } ClientPlayConnectionEvents.JOIN.register(((handler, sender, client) -> reset())); } @@ -304,7 +330,7 @@ public class DungeonSecrets { SkyblockerMod.GSON.fromJson(reader, JsonObject.class).asMap().forEach((room, jsonElement) -> map.put(room.toLowerCase().replaceAll(" ", "-"), jsonElement)); } - private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, Integer>> markSecretsCommand(boolean found) { + private static RequiredArgumentBuilder<FabricClientCommandSource, Integer> markSecretsCommand(boolean found) { return argument("secretIndex", IntegerArgumentType.integer()).executes(context -> { int secretIndex = IntegerArgumentType.getInteger(context, "secretIndex"); if (markSecrets(secretIndex, found)) { @@ -333,14 +359,14 @@ public class DungeonSecrets { Room room = getRoomAtPhysical(pos); if (isRoomMatched(room)) { BlockPos relativePos = currentRoom.actualToRelative(pos); - source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.posMessage", currentRoom.getName(), relativePos.getX(), relativePos.getY(), relativePos.getZ()))); + source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.posMessage", currentRoom.getName(), currentRoom.getDirection().asString(), relativePos.getX(), relativePos.getY(), relativePos.getZ()))); } else { source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.notMatched"))); } return Command.SINGLE_SUCCESS; } - private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, PosArgument>> addCustomWaypointCommand(boolean relative) { + private static RequiredArgumentBuilder<FabricClientCommandSource, PosArgument> addCustomWaypointCommand(boolean relative) { return argument("pos", BlockPosArgumentType.blockPos()) .then(argument("secretIndex", IntegerArgumentType.integer()) .then(argument("category", SecretWaypoint.Category.CategoryArgumentType.category()) @@ -372,7 +398,7 @@ public class DungeonSecrets { return Command.SINGLE_SUCCESS; } - private static ArgumentBuilder<FabricClientCommandSource, RequiredArgumentBuilder<FabricClientCommandSource, PosArgument>> removeCustomWaypointCommand(boolean relative) { + private static RequiredArgumentBuilder<FabricClientCommandSource, PosArgument> removeCustomWaypointCommand(boolean relative) { return argument("pos", BlockPosArgumentType.blockPos()) .executes(context -> { // TODO Less hacky way with custom ClientBlockPosArgumentType @@ -400,6 +426,61 @@ public class DungeonSecrets { return Command.SINGLE_SUCCESS; } + private static RequiredArgumentBuilder<FabricClientCommandSource, String> matchAgainstCommand() { + return argument("room", StringArgumentType.string()).suggests((context, builder) -> CommandSource.suggestMatching(ROOMS_DATA.values().stream().map(Map::values).flatMap(Collection::stream).map(Map::keySet).flatMap(Collection::stream), builder)).then(argument("direction", Room.Direction.DirectionArgumentType.direction()).executes(context -> { + if (physicalEntrancePos == null || mapEntrancePos == null || mapRoomSize == 0) { + context.getSource().sendError(Constants.PREFIX.get().append("§cYou are not in a dungeon.")); + return Command.SINGLE_SUCCESS; + } + MinecraftClient client = MinecraftClient.getInstance(); + if (client.player == null || client.world == null) { + context.getSource().sendError(Constants.PREFIX.get().append("§cFailed to get player or world.")); + return Command.SINGLE_SUCCESS; + } + ItemStack stack = client.player.getInventory().main.get(8); + if (!stack.isOf(Items.FILLED_MAP)) { + context.getSource().sendError(Constants.PREFIX.get().append("§cFailed to get dungeon map.")); + return Command.SINGLE_SUCCESS; + } + MapState map = FilledMapItem.getMapState(FilledMapItem.getMapId(stack), client.world); + if (map == null) { + context.getSource().sendError(Constants.PREFIX.get().append("§cFailed to get dungeon map state.")); + return Command.SINGLE_SUCCESS; + } + + String roomName = StringArgumentType.getString(context, "room"); + Room.Direction direction = Room.Direction.DirectionArgumentType.getDirection(context, "direction"); + + Room room = newDebugRoom(roomName, direction, client.player, map); + if (room == null) { + context.getSource().sendError(Constants.PREFIX.get().append("§cFailed to find room with name " + roomName + ".")); + return Command.SINGLE_SUCCESS; + } + if (currentRoom != null) { + currentRoom.addSubProcess(room); + context.getSource().sendFeedback(Constants.PREFIX.get().append("§rMatching room " + roomName + " with direction " + direction + " against current room.")); + } else { + context.getSource().sendError(Constants.PREFIX.get().append("§cCurrent room is null.")); + } + + return Command.SINGLE_SUCCESS; + })); + } + + @Nullable + private static Room newDebugRoom(String roomName, Room.Direction direction, PlayerEntity player, MapState map) { + Room room = null; + int[] roomData; + if ((roomData = ROOMS_DATA.get("catacombs").get(Room.Shape.PUZZLE.shape).get(roomName)) != null) { + room = DebugRoom.ofSinglePossibleRoom(Room.Type.PUZZLE, DungeonMapUtils.getPhysicalRoomPos(player.getPos()), roomName, roomData, direction); + } else if ((roomData = ROOMS_DATA.get("catacombs").get(Room.Shape.TRAP.shape).get(roomName)) != null) { + room = DebugRoom.ofSinglePossibleRoom(Room.Type.TRAP, DungeonMapUtils.getPhysicalRoomPos(player.getPos()), roomName, roomData, direction); + } else if ((roomData = ROOMS_DATA.get("catacombs").values().stream().map(Map::entrySet).flatMap(Collection::stream).filter(entry -> entry.getKey().equals(roomName)).findAny().map(Map.Entry::getValue).orElse(null)) != null) { + room = DebugRoom.ofSinglePossibleRoom(Room.Type.ROOM, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, DungeonMapUtils.getMapRoomPos(map, mapEntrancePos, mapRoomSize), mapRoomSize, Room.Type.ROOM.color)), roomName, roomData, direction); + } + return room; + } + /** * Updates the dungeon. The general idea is similar to the Dungeon Rooms Mod. * <p></p> @@ -421,14 +502,11 @@ public class DungeonSecrets { * <li> Create a new room. </li> * </ul> * <li> Sets {@link #currentRoom} to the current room, either created from the previous step or from {@link #rooms}. </li> - * <li> Calls {@link Room#update()} on {@link #currentRoom}. </li> + * <li> Calls {@link Room#tick()} on {@link #currentRoom}. </li> * </ul> */ @SuppressWarnings("JavadocReference") private static void update() { - if (!SkyblockerConfigManager.get().locations.dungeons.secretWaypoints.enableSecretWaypoints) { - return; - } if (!Utils.isInDungeons()) { if (mapEntrancePos != null) { reset(); @@ -436,16 +514,15 @@ public class DungeonSecrets { return; } MinecraftClient client = MinecraftClient.getInstance(); - ClientPlayerEntity player = client.player; - if (player == null || client.world == null) { + if (client.player == null || client.world == null) { return; } if (physicalEntrancePos == null) { - Vec3d playerPos = player.getPos(); + Vec3d playerPos = client.player.getPos(); physicalEntrancePos = DungeonMapUtils.getPhysicalRoomPos(playerPos); currentRoom = newRoom(Room.Type.ENTRANCE, physicalEntrancePos); } - ItemStack stack = player.getInventory().main.get(8); + ItemStack stack = client.player.getInventory().main.get(8); if (!stack.isOf(Items.FILLED_MAP)) { return; } @@ -477,9 +554,13 @@ public class DungeonSecrets { } } if (room != null && currentRoom != room) { + if (currentRoom != null && room.getType() == Room.Type.FAIRY) { + currentRoom.nextRoom = room; + room.keyFound = currentRoom.keyFound; + } currentRoom = room; } - currentRoom.update(); + currentRoom.tick(); } /** @@ -663,12 +744,12 @@ public class DungeonSecrets { } /** - * Checks if the player is in a dungeon and {@link de.hysky.skyblocker.config.SkyblockerConfig.Dungeons#secretWaypoints Secret Waypoints} is enabled. + * Checks if {@link SkyblockerConfig.SecretWaypoints#enableRoomMatching room matching} is enabled and the player is in a dungeon. * - * @return whether dungeon secrets should be processed + * @return whether room matching and dungeon secrets should be processed */ private static boolean shouldProcess() { - return SkyblockerConfigManager.get().locations.dungeons.secretWaypoints.enableSecretWaypoints && Utils.isInDungeons(); |
