diff options
author | Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> | 2023-12-21 14:53:52 +0800 |
---|---|---|
committer | Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> | 2023-12-21 14:53:52 +0800 |
commit | 003834e36b145791dd603858c924926be70e1281 (patch) | |
tree | f8fff7b26d3d3880259498c2f3ab18738d20184e /src | |
parent | 66b6be50ed9480d2d6e442c21ad16ed4bd48b2d6 (diff) | |
download | Skyblocker-003834e36b145791dd603858c924926be70e1281.tar.gz Skyblocker-003834e36b145791dd603858c924926be70e1281.tar.bz2 Skyblocker-003834e36b145791dd603858c924926be70e1281.zip |
Refactor puzzle solvers
Diffstat (limited to 'src')
15 files changed, 197 insertions, 108 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index d1aa3153..9ce0df8d 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -5,7 +5,13 @@ import com.google.gson.GsonBuilder; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.debug.Debug; import de.hysky.skyblocker.skyblock.*; -import de.hysky.skyblocker.skyblock.dungeon.*; +import de.hysky.skyblocker.skyblock.dungeon.DungeonMap; +import de.hysky.skyblocker.skyblock.dungeon.FireFreezeStaffTimer; +import de.hysky.skyblocker.skyblock.dungeon.GuardianHealth; +import de.hysky.skyblocker.skyblock.dungeon.LividColor; +import de.hysky.skyblocker.skyblock.dungeon.puzzle.CreeperBeams; +import de.hysky.skyblocker.skyblock.dungeon.puzzle.DungeonBlaze; +import de.hysky.skyblocker.skyblock.dungeon.puzzle.TicTacToe; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.skyblock.dungeon.secrets.SecretsTracker; import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud; 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 aabef183..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,14 +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.events.DungeonEvents; 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.networking.v1.ClientPlayConnectionEvents; 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; @@ -26,33 +22,30 @@ 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 boolean inBlaze; 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() { - DungeonEvents.PUZZLE_MATCHED.register(room -> { - if (room.getName().startsWith("blaze-room")) { - inBlaze = true; - } - }); - Scheduler.INSTANCE.scheduleCyclic(DungeonBlaze::update, 4); - WorldRenderEvents.BEFORE_DEBUG_RENDER.register(DungeonBlaze::blazeRenderer); - ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> inBlaze = false); } /** * Updates the state of Blaze entities and triggers the rendering process if necessary. */ - public static void update() { - if (!inBlaze) { + @Override + public void tick() { + if (!shouldSolve()) { return; } ClientWorld world = MinecraftClient.getInstance().world; @@ -116,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 2bb3e4e0..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,14 +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.events.DungeonEvents; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; -import de.hysky.skyblocker.utils.scheduler.Scheduler; import de.hysky.skyblocker.utils.tictactoe.TicTacToeUtils; -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; @@ -28,25 +24,22 @@ 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 boolean inTicTacToe; + 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() { - DungeonEvents.PUZZLE_MATCHED.register(room -> { - if (room.getName().startsWith("tic-tac-toe")) { - inTicTacToe = true; - } - }); - Scheduler.INSTANCE.scheduleCyclic(TicTacToe::tick, 4); - WorldRenderEvents.BEFORE_DEBUG_RENDER.register(TicTacToe::solutionRenderer); - ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> inTicTacToe = false); } - public static void tick() { - if (!inTicTacToe) { + @Override + public void tick() { + if (!shouldSolve()) { return; } @@ -139,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 index b686607b..931d1d69 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DebugRoom.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DebugRoom.java @@ -1,26 +1,38 @@ 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.jetbrains.annotations.NotNull; import org.joml.Vector2ic; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; public class DebugRoom extends Room { private final List<Waypoint> checkedBlocks = Collections.synchronizedList(new ArrayList<>()); - public DebugRoom(@NotNull Type type, @NotNull Vector2ic... physicalPositions) { + 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()); @@ -37,7 +49,7 @@ public class DebugRoom extends Room { } @Override - protected void render(WorldRenderContext context) { + public void render(WorldRenderContext context) { super.render(context); synchronized (checkedBlocks) { for (Waypoint checkedBlock : checkedBlocks) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java index 52915b98..722ecd85 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java @@ -18,9 +18,6 @@ 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; -import it.unimi.dsi.fastutil.ints.IntRBTreeSet; -import it.unimi.dsi.fastutil.ints.IntSortedSet; -import it.unimi.dsi.fastutil.ints.IntSortedSets; import it.unimi.dsi.fastutil.objects.Object2ByteMap; import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIntPair; @@ -43,6 +40,7 @@ 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; @@ -59,7 +57,6 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import net.minecraft.world.World; -import org.apache.commons.lang3.tuple.MutableTriple; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -200,6 +197,10 @@ public class DungeonManager { 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. @@ -232,12 +233,13 @@ public class DungeonManager { 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("clearSubRooms").executes(context -> { + .then(literal("clearSubProcesses").executes(context -> { if (currentRoom != null) { - currentRoom.subRooms.clear(); - context.getSource().sendFeedback(Constants.PREFIX.get().append("§rCleared sub rooms in the current room")); + 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")); + context.getSource().sendError(Constants.PREFIX.get().append("§cCurrent room is null.")); } return Command.SINGLE_SUCCESS; })) @@ -427,57 +429,58 @@ public class DungeonManager { 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")); + 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")); + 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")); + 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")); + 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 = null; - int[] roomData; - if ((roomData = ROOMS_DATA.get("catacombs").get(Room.Shape.PUZZLE.shape).get(roomName)) != null) { - room = new DebugRoom(Room.Type.PUZZLE, DungeonMapUtils.getPhysicalRoomPos(client.player.getPos())); - } else if ((roomData = ROOMS_DATA.get("catacombs").get(Room.Shape.TRAP.shape).get(roomName)) != null) { - room = new DebugRoom(Room.Type.TRAP, DungeonMapUtils.getPhysicalRoomPos(client.player.getPos())); - } 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 = new DebugRoom(Room.Type.ROOM, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, DungeonMapUtils.getMapRoomPos(map, mapEntrancePos, mapRoomSize), mapRoomSize, Room.Type.ROOM.color))); - } - + 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)); + context.getSource().sendError(Constants.PREFIX.get().append("§cFailed to find room with name " + roomName + ".")); return Command.SINGLE_SUCCESS; } - 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))); if (currentRoom != null) { - currentRoom.subRooms.add(room); - context.getSource().sendFeedback(Constants.PREFIX.get().append("§rMatching room " + roomName + " with direction " + direction + " against current room")); + 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")); + 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> @@ -499,7 +502,7 @@ public class DungeonManager { * <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") @@ -553,7 +556,7 @@ public class DungeonManager { if (room != null && currentRoom != room) { currentRoom = room; } - currentRoom.update(); + currentRoom.tick(); } /** 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 40488717..d59bf7bf 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 @@ -11,7 +11,9 @@ import com.mojang.serialization.Codec; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.events.DungeonEvents; import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.Tickable; import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.Renderable; import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.ints.IntRBTreeSet; import it.unimi.dsi.fastutil.ints.IntSortedSet; @@ -49,7 +51,7 @@ import java.util.concurrent.CompletableFuture; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class Room { +public class Room implements Tickable, Renderable { private static final Pattern SECRET_INDEX = Pattern.compile("^(\\d+)"); private static final Pattern SECRETS = Pattern.compile("§7(\\d{1,2})/(\\d{1,2}) Secrets"); private static final Vec3d DOOR_SIZE = new Vec3d(3, 4, 3); @@ -80,7 +82,7 @@ public class Room { /** * The task that is used to check blocks. This is used to ensure only one such task can run at a time. */ - private CompletableFuture<Void> findRoom; + protected CompletableFuture<Void> findRoom; private int doubleCheckBlocks; /** * Represents the matching state of the room with the following possible values: @@ -95,7 +97,8 @@ public class Room { private Direction direction; private Vector2ic physicalCornerPos; - protected List<Room> subRooms = new ArrayList<>(); + protected List<Tickable> tickables = new ArrayList<>(); + protected List<Renderable> renderables = new ArrayList<>(); @Nullable private BlockPos doorPos; @Nullable @@ -266,6 +269,11 @@ public class Room { secretWaypoints.remove(secretIndex, actualPos); } + public <T extends Tickable & Renderable> void addSubProcess(T process) { + tickables.add(process); + renderables.add(process); + } + /** * Updates the room. * <p></p> @@ -285,15 +293,16 @@ public class Room { * </ul> */ @SuppressWarnings("JavadocReference") - protected void update() { + @Override + public void tick() { MinecraftClient client = MinecraftClient.getInstance(); ClientWorld world = client.world; if (world == null) { return; } - for (Room subRoom : subRooms) { - subRoom.update(); + for (Tickable tickable : tickables) { + tickable.tick(); } // Wither and blood door @@ -506,9 +515,10 @@ public class Room { /** * Calls {@link SecretWaypoint#render(WorldRenderContext)} on {@link #secretWaypoints all secret waypoints} and renders a highlight around the wither or blood door, if it exists. */ - protected void render(WorldRenderContext context) { - for (Room subRoom : subRooms) { - subRoom.render(context); + @Override + public void render(WorldRenderContext context) { + for (Renderable renderable : renderables) { + renderable.render(context); } if (SkyblockerConfigManager.get().locations.dungeons.secretWaypoints.enableSecretWaypoints && isMatched()) { diff --git a/src/main/java/de/hysky/skyblocker/utils/Tickable.java b/src/main/java/de/hysky/skyblocker/utils/Tickable.java new file mode 100644 index 00000000..9b7b2e3f --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/Tickable.java @@ -0,0 +1,5 @@ +package de.hysky.skyblocker.utils; + +public interface Tickable { + void tick(); +} diff --git a/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java b/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java index 2c75ef0a..42f890b7 100644 --- a/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java +++ b/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java @@ -5,8 +5,8 @@ import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.skyblock.barn.HungryHiker; import de.hysky.skyblocker.skyblock.barn.TreasureHunter; import de.hysky.skyblocker.skyblock.dungeon.Reparty; -import de.hysky.skyblocker.skyblock.dungeon.ThreeWeirdos; -import de.hysky.skyblocker.skyblock.dungeon.Trivia; +import de.hysky.skyblocker.skyblock.dungeon.puzzle.ThreeWeirdos; +import de.hysky.skyblocker.skyblock.dungeon.puzzle.Trivia; import de.hysky.skyblocker.skyblock.dwarven.Fetchur; import de.hysky.skyblocker.skyblock.dwarven.Puzzler; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; diff --git a/src/main/java/de/hysky/skyblocker/utils/render/Renderable.java b/src/main/java/de/hysky/skyblocker/utils/render/Renderable.java new file mode 100644 index 00000000..b7743153 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/render/Renderable.java @@ -0,0 +1,7 @@ +package de.hysky.skyblocker.utils.render; + +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; + +public interface Renderable { + void render(WorldRenderContext context); +} diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/ThreeWeirdosTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdosTest.java index 3772fd75..22683698 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/ThreeWeirdosTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/ThreeWeirdosTest.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.skyblock.dungeon; +package de.hysky.skyblocker.skyblock.dungeon.puzzle; import de.hysky.skyblocker.utils.chat.ChatPatternListenerTest; import org.junit.jupiter.api.Test; diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/TriviaTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TriviaTest.java index 1df5a8e1..55a59a68 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/TriviaTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/TriviaTest.java @@ -1,4 +1,4 @@ -package de.hysky.skyblocker.skyblock.dungeon; +package de.hysky.skyblocker.skyblock.dungeon.puzzle; import de.hysky.skyblocker.utils.chat.ChatPatternListenerTest; import org.junit.jupiter.api.Test; |