From 2ffb38db700cabd13438e04b6d04811294230230 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 31 Jan 2024 22:59:34 -0500 Subject: Add solvers --- .../skyblock/dungeon/puzzle/Boulder.java | 21 +++++++++++++++++++++ .../skyblock/dungeon/puzzle/IceFill.java | 9 +++++++++ .../skyblock/dungeon/puzzle/Silverfish.java | 22 ++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Boulder.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Boulder.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Boulder.java new file mode 100644 index 00000000..8987599a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Boulder.java @@ -0,0 +1,21 @@ +package de.hysky.skyblocker.skyblock.dungeon.puzzle; + +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.client.MinecraftClient; + +// right: 5, 63, 8 +// left: 25, 63, 8 +// jungle, birch +public class Boulder extends DungeonPuzzle { + public Boulder() { + super("Boulder", "boxes-room"); + } + + @Override + public void tick(MinecraftClient client) { + } + + @Override + public void render(WorldRenderContext context) { + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java new file mode 100644 index 00000000..069b565e --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java @@ -0,0 +1,9 @@ +package de.hysky.skyblocker.skyblock.dungeon.puzzle; + +// 1: 15, 69, 7 +// 2: 15, 70, 12 +// 3: 15, 71, 19 +// ice -> packed_ice +// polished andesite +public class IceFill { +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java new file mode 100644 index 00000000..0784f4ed --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java @@ -0,0 +1,22 @@ +package de.hysky.skyblocker.skyblock.dungeon.puzzle; + +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.client.MinecraftClient; + +//right: 7, 66, 8 +//left: 23, 66, 8 +//right back: 7, 66, 24 +//polished andesite +public class Silverfish extends DungeonPuzzle { + public Silverfish() { + super("Silverfish", "ice-silverfish-room"); + } + + @Override + public void tick(MinecraftClient client) { + } + + @Override + public void render(WorldRenderContext context) { + } +} -- cgit From 443753ad8ed3e9e98e70881a733003a9b6386499 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:35:25 -0500 Subject: Add silverfish board parsing --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 8 +- .../hysky/skyblocker/config/SkyblockerConfig.java | 6 + .../skyblock/dungeon/puzzle/Boulder.java | 21 --- .../skyblock/dungeon/puzzle/IceFill.java | 25 ++- .../skyblock/dungeon/puzzle/Silverfish.java | 177 ++++++++++++++++++++- 5 files changed, 209 insertions(+), 28 deletions(-) delete mode 100644 src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Boulder.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index b8722fc6..dca41bd1 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -8,18 +8,16 @@ import de.hysky.skyblocker.skyblock.*; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; import de.hysky.skyblocker.skyblock.dungeon.*; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; +import de.hysky.skyblocker.skyblock.dungeon.puzzle.*; import de.hysky.skyblocker.skyblock.dungeon.puzzle.boulder.Boulder; -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.puzzle.waterboard.Waterboard; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.skyblock.dungeon.secrets.SecretsTracker; import de.hysky.skyblocker.skyblock.dwarven.CrystalsHud; import de.hysky.skyblocker.skyblock.dwarven.CrystalsLocationsManager; import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud; -import de.hysky.skyblocker.skyblock.end.TheEnd; import de.hysky.skyblocker.skyblock.end.BeaconHighlighter; +import de.hysky.skyblocker.skyblock.end.TheEnd; import de.hysky.skyblocker.skyblock.item.*; import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; @@ -117,6 +115,8 @@ public class SkyblockerMod implements ClientModInitializer { DungeonManager.init(); DungeonBlaze.init(); Waterboard.init(); + Silverfish.init(); + IceFill.init(); DungeonScore.init(); PartyFinderScreen.initClass(); ChestValue.init(); diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index b5ddcf5d..78458291 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -722,6 +722,12 @@ public class SkyblockerConfig { @SerialEntry public boolean solveBoulder = true; + @SerialEntry + public boolean solveIceFill = true; + + @SerialEntry + public boolean solveSilverfish = true; + @SerialEntry public boolean fireFreezeStaffTimer = true; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Boulder.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Boulder.java deleted file mode 100644 index 8987599a..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Boulder.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.hysky.skyblocker.skyblock.dungeon.puzzle; - -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; -import net.minecraft.client.MinecraftClient; - -// right: 5, 63, 8 -// left: 25, 63, 8 -// jungle, birch -public class Boulder extends DungeonPuzzle { - public Boulder() { - super("Boulder", "boxes-room"); - } - - @Override - public void tick(MinecraftClient client) { - } - - @Override - public void render(WorldRenderContext context) { - } -} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java index 069b565e..3eee8a7c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java @@ -1,9 +1,32 @@ package de.hysky.skyblocker.skyblock.dungeon.puzzle; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.client.MinecraftClient; + // 1: 15, 69, 7 // 2: 15, 70, 12 // 3: 15, 71, 19 // ice -> packed_ice // polished andesite -public class IceFill { +public class IceFill extends DungeonPuzzle { + public static final IceFill INSTANCE = new IceFill(); + + public IceFill() { + super("ice-fill", "ice-path"); + } + + public static void init() {} + + @Override + public void tick(MinecraftClient client) { + if (!SkyblockerConfigManager.get().locations.dungeons.solveIceFill) { + return; + } + } + + @Override + public void render(WorldRenderContext context) { + + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java index 0784f4ed..195e38f7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java @@ -1,22 +1,195 @@ package de.hysky.skyblocker.skyblock.dungeon.puzzle; +import com.mojang.brigadier.Command; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.debug.Debug; +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.render.RenderHelper; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.mob.SilverfishEntity; +import net.minecraft.util.DyeColor; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import org.joml.Vector2i; +import org.joml.Vector2ic; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; //right: 7, 66, 8 //left: 23, 66, 8 //right back: 7, 66, 24 //polished andesite public class Silverfish extends DungeonPuzzle { - public Silverfish() { - super("Silverfish", "ice-silverfish-room"); + private static final Logger LOGGER = LoggerFactory.getLogger(Silverfish.class); + public static final Silverfish INSTANCE = new Silverfish(); + private static final float[] LIME_COLOR_COMPONENTS = DyeColor.LIME.getColorComponents(); + private final boolean[][] silverfishBoard = new boolean[17][17]; + private Vector2ic silverfishPos; + private final List silverfishPath = new ArrayList<>(); + + private Silverfish() { + super("silverfish", "ice-silverfish-room"); + if (Debug.debugEnabled()) { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("puzzle").then(literal(puzzleName) + .then(literal("printBoard").executes(context -> { + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(silverfishBoard))); + return Command.SINGLE_SUCCESS; + })).then(literal("printPath").executes(context -> { + context.getSource().sendFeedback(Constants.PREFIX.get().append(silverfishPath.toString())); + return Command.SINGLE_SUCCESS; + })) + ))))); + } + } + + public static void init() {} + + private static String boardToString(boolean[][] silverfishBoard) { + StringBuilder sb = new StringBuilder(); + for (boolean[] row : silverfishBoard) { + sb.append("\n"); + for (boolean cell : row) { + sb.append(cell ? '#' : '.'); + } + } + return sb.toString(); } @Override public void tick(MinecraftClient client) { + if (!SkyblockerConfigManager.get().locations.dungeons.solveSilverfish || client.world == null || !DungeonManager.isCurrentRoomMatched()) { + return; + } + Room room = DungeonManager.getCurrentRoom(); + + boolean boardChanged = false; + BlockPos.Mutable pos = new BlockPos.Mutable(23, 67, 24); + for (int row = 0; row < silverfishBoard.length; pos.move(silverfishBoard[row].length, 0, -1), row++) { + for (int col = 0; col < silverfishBoard[row].length; pos.move(Direction.WEST), col++) { + boolean isBlock = !client.world.getBlockState(room.relativeToActual(pos)).isAir(); + if (silverfishBoard[row][col] != isBlock) { + silverfishBoard[row][col] = isBlock; + boardChanged = true; + } + } + } + + BlockPos blockPos = room.relativeToActual(new BlockPos(16, 16, 16)); + List entities = client.world.getEntitiesByClass(SilverfishEntity.class, Box.of(Vec3d.ofCenter(blockPos), 32, 32, 32), silverfishEntity -> true); + if (entities.isEmpty()) { + return; + } + BlockPos newSilverfishBlockPos = room.actualToRelative(entities.get(0).getBlockPos()); + Vector2ic newSilverfishPos = new Vector2i(23 - newSilverfishBlockPos.getX(), 24 - newSilverfishBlockPos.getZ()); + if (newSilverfishPos.x() < 0 || newSilverfishPos.x() >= 17 || newSilverfishPos.y() < 0 || newSilverfishPos.y() >= 17) { + return; + } + boolean silverfishChanged = !newSilverfishPos.equals(silverfishPos); + if (silverfishChanged) { + silverfishPos = newSilverfishPos; + } + if (silverfishChanged || boardChanged) { + solve(); + } + } + + private void solve() { + if (silverfishPos == null) { + return; + } + Set visited = new HashSet<>(); + Queue> queue = new ArrayDeque<>(); + queue.add(List.of(silverfishPos)); + while (!queue.isEmpty()) { + List path = queue.poll(); + Vector2ic pos = path.get(path.size() - 1); + if (pos.equals(8, 0)) { + silverfishPath.clear(); + silverfishPath.addAll(path); + return; + } + + Vector2i posMutable = new Vector2i(pos); + while (posMutable.x() < 17 && !silverfishBoard[posMutable.x()][posMutable.y()]) { + posMutable.add(1, 0); + } + posMutable.add(-1, 0); + if (!visited.contains(posMutable)) { + ArrayList newPath = new ArrayList<>(path); + newPath.add(new Vector2i(posMutable)); + queue.add(newPath); + visited.add(posMutable); + } + + posMutable.set(pos); + while (posMutable.x() >= 0 && !silverfishBoard[posMutable.x()][posMutable.y()]) { + posMutable.add(-1, 0); + } + posMutable.add(1, 0); + if (!visited.contains(posMutable)) { + ArrayList newPath = new ArrayList<>(path); + newPath.add(new Vector2i(posMutable)); + queue.add(newPath); + visited.add(posMutable); + } + + posMutable.set(pos); + while (posMutable.y() < 17 && !silverfishBoard[posMutable.x()][posMutable.y()]) { + posMutable.add(0, 1); + } + posMutable.add(0, -1); + if (!visited.contains(posMutable)) { + ArrayList newPath = new ArrayList<>(path); + newPath.add(new Vector2i(posMutable)); + queue.add(newPath); + visited.add(posMutable); + } + + posMutable.set(pos); + while (posMutable.y() >= 0 && !silverfishBoard[posMutable.x()][posMutable.y()]) { + posMutable.add(0, -1); + } + posMutable.add(0, 1); + if (!visited.contains(posMutable)) { + ArrayList newPath = new ArrayList<>(path); + newPath.add(new Vector2i(posMutable)); + queue.add(newPath); + visited.add(posMutable); + } + } } @Override public void render(WorldRenderContext context) { + if (!SkyblockerConfigManager.get().locations.dungeons.solveSilverfish || !DungeonManager.isCurrentRoomMatched() || silverfishPath.isEmpty()) { + return; + } + Room room = DungeonManager.getCurrentRoom(); + BlockPos.Mutable pos = new BlockPos.Mutable(); + for (int i = 0; i < silverfishPath.size() - 1; i++) { + Vec3d start = Vec3d.ofCenter(room.relativeToActual(pos.set(23 - silverfishPath.get(i).x(), 67, 24 - silverfishPath.get(i).y()))); + Vec3d end = Vec3d.ofCenter(room.relativeToActual(pos.set(23 - silverfishPath.get(i + 1).x(), 67, 24 - silverfishPath.get(i + 1).y()))); + RenderHelper.renderLinesFromPoints(context, new Vec3d[]{start, end}, LIME_COLOR_COMPONENTS, 1f, 5f, true); + } + } + + @Override + public void reset() { + super.reset(); + for (boolean[] silverfishBoardRow : silverfishBoard) { + Arrays.fill(silverfishBoardRow, false); + } + silverfishPos = null; } } -- cgit From ca61d618df013434bce4fb6995bc40aec4dc07dc Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 2 Feb 2024 16:40:24 -0500 Subject: Finish silverfish and ice fill solvers --- .../skyblock/dungeon/puzzle/IceFill.java | 171 ++++++++++++++++++++- .../skyblock/dungeon/puzzle/Silverfish.java | 82 ++++------ .../dungeon/puzzle/waterboard/Waterboard.java | 14 +- .../skyblock/dungeon/puzzle/SilverfishTest.java | 40 +++++ 4 files changed, 244 insertions(+), 63 deletions(-) create mode 100644 src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/SilverfishTest.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java index 3eee8a7c..7ab96d78 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java @@ -1,32 +1,187 @@ package de.hysky.skyblocker.skyblock.dungeon.puzzle; +import com.google.common.primitives.Booleans; +import com.mojang.brigadier.Command; +import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.debug.Debug; +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.render.RenderHelper; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; +import net.minecraft.util.DyeColor; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.joml.Vector2i; +import org.joml.Vector2ic; + +import java.util.*; +import java.util.concurrent.CompletableFuture; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; -// 1: 15, 69, 7 -// 2: 15, 70, 12 -// 3: 15, 71, 19 -// ice -> packed_ice -// polished andesite public class IceFill extends DungeonPuzzle { public static final IceFill INSTANCE = new IceFill(); + private static final float[] RED_COLOR_COMPONENTS = DyeColor.RED.getColorComponents(); + private static final BlockPos BOARD_1_ORIGIN = new BlockPos(16, 70, 9); + private static final BlockPos BOARD_2_ORIGIN = new BlockPos(17, 71, 16); + private static final BlockPos BOARD_3_ORIGIN = new BlockPos(18, 72, 25); + private CompletableFuture solve; + private final boolean[][] iceFillBoard1 = new boolean[3][3]; + private final boolean[][] iceFillBoard2 = new boolean[5][5]; + private final boolean[][] iceFillBoard3 = new boolean[7][7]; + private final List iceFillPath1 = new ArrayList<>(); + private final List iceFillPath2 = new ArrayList<>(); + private final List iceFillPath3 = new ArrayList<>(); - public IceFill() { + private IceFill() { super("ice-fill", "ice-path"); } - public static void init() {} + public static void init() { + if (Debug.debugEnabled()) { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("puzzle").then(literal(INSTANCE.puzzleName) + .then(literal("printBoard1").executes(context -> { + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoard1))); + return Command.SINGLE_SUCCESS; + })).then(literal("printBoard2").executes(context -> { + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoard2))); + return Command.SINGLE_SUCCESS; + })).then(literal("printBoard3").executes(context -> { + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoard3))); + return Command.SINGLE_SUCCESS; + })).then(literal("printPath1").executes(context -> { + context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPath1.toString())); + return Command.SINGLE_SUCCESS; + })).then(literal("printPath2").executes(context -> { + context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPath2.toString())); + return Command.SINGLE_SUCCESS; + })).then(literal("printPath3").executes(context -> { + context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPath3.toString())); + return Command.SINGLE_SUCCESS; + })) + ))))); + } + } + + private static String boardToString(boolean[][] iceFillBoard) { + StringBuilder sb = new StringBuilder(); + for (boolean[] row : iceFillBoard) { + sb.append("\n"); + for (boolean cell : row) { + sb.append(cell ? '#' : '.'); + } + } + return sb.toString(); + } @Override public void tick(MinecraftClient client) { - if (!SkyblockerConfigManager.get().locations.dungeons.solveIceFill) { + if (!SkyblockerConfigManager.get().locations.dungeons.solveIceFill || client.world == null || !DungeonManager.isCurrentRoomMatched() || solve != null && !solve.isDone()) { return; } + Room room = DungeonManager.getCurrentRoom(); + + solve = CompletableFuture.runAsync(() -> { + BlockPos.Mutable pos = new BlockPos.Mutable(); + boolean board1Changed = updateBoard(client.world, room, iceFillBoard1, pos.set(BOARD_1_ORIGIN)); + boolean board2Changed = updateBoard(client.world, room, iceFillBoard2, pos.set(BOARD_2_ORIGIN)); + boolean board3Changed = updateBoard(client.world, room, iceFillBoard3, pos.set(BOARD_3_ORIGIN)); + + if (board1Changed) { + solve(iceFillBoard1, iceFillPath1); + } + if (board2Changed) { + solve(iceFillBoard2, iceFillPath2); + } + if (board3Changed) { + solve(iceFillBoard3, iceFillPath3); + } + }); + } + + private boolean updateBoard(World world, Room room, boolean[][] iceFillBoard, BlockPos.Mutable pos) { + boolean boardChanged = false; + for (int row = 0; row < iceFillBoard.length; pos.move(iceFillBoard[row].length, 0, -1), row++) { + for (int col = 0; col < iceFillBoard[row].length; pos.move(Direction.WEST), col++) { + BlockPos actualPos = room.relativeToActual(pos); + boolean isBlock = !world.getBlockState(actualPos).isAir(); + if (iceFillBoard[row][col] != isBlock) { + iceFillBoard[row][col] = isBlock; + boardChanged = true; + } + } + } + return boardChanged; + } + + private void solve(boolean[][] iceFillBoard, List iceFillPath) { + Vector2ic start = new Vector2i(iceFillBoard.length - 1, iceFillBoard[0].length / 2); + int count = iceFillBoard.length * iceFillBoard[0].length - Arrays.stream(iceFillBoard).mapToInt(Booleans::countTrue).sum(); + + Queue> queue = new ArrayDeque<>(); + queue.add(List.of(start)); + while (!queue.isEmpty()) { + List path = queue.poll(); + Vector2ic pos = path.get(path.size() - 1); + if (pos.x() == 0 && pos.y() == iceFillBoard[0].length / 2 && path.size() == count) { + iceFillPath.clear(); + iceFillPath.addAll(path); + return; + } + + Vector2i posMutable = pos.add(1, 0, new Vector2i()); + if (posMutable.x() < iceFillBoard.length && !iceFillBoard[posMutable.x()][posMutable.y()]) { + addQueue(queue, path, posMutable); + } + + posMutable = pos.add(-1, 0, new Vector2i()); + if (posMutable.x() >= 0 && !iceFillBoard[posMutable.x()][posMutable.y()]) { + addQueue(queue, path, posMutable); + } + + posMutable = pos.add(0, 1, new Vector2i()); + if (posMutable.y() < iceFillBoard[0].length && !iceFillBoard[posMutable.x()][posMutable.y()]) { + addQueue(queue, path, posMutable); + } + + posMutable = pos.add(0, -1, new Vector2i()); + if (posMutable.y() >= 0 && !iceFillBoard[posMutable.x()][posMutable.y()]) { + addQueue(queue, path, posMutable); + } + } + } + + private void addQueue(Queue> queue, List path, Vector2ic newPos) { + if (!path.contains(newPos)) { + List newPath = new ArrayList<>(path); + newPath.add(newPos); + queue.add(newPath); + } } @Override public void render(WorldRenderContext context) { + if (!SkyblockerConfigManager.get().locations.dungeons.solveIceFill || !DungeonManager.isCurrentRoomMatched()) { + return; + } + Room room = DungeonManager.getCurrentRoom(); + renderPath(context, room, iceFillPath1, BOARD_1_ORIGIN); + renderPath(context, room, iceFillPath2, BOARD_2_ORIGIN); + renderPath(context, room, iceFillPath3, BOARD_3_ORIGIN); + } + private void renderPath(WorldRenderContext context, Room room, List iceFillPath, BlockPos originPos) { + BlockPos.Mutable pos = new BlockPos.Mutable(); + for (int i = 0; i < iceFillPath.size() - 1; i++) { + Vec3d start = Vec3d.ofCenter(room.relativeToActual(pos.set(originPos).move(-iceFillPath.get(i).y(), 0, -iceFillPath.get(i).x()))); + Vec3d end = Vec3d.ofCenter(room.relativeToActual(pos.set(originPos).move(-iceFillPath.get(i + 1).y(), 0, -iceFillPath.get(i + 1).x()))); + RenderHelper.renderLinesFromPoints(context, new Vec3d[]{start, end}, RED_COLOR_COMPONENTS, 1f, 5f, true); + } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java index 195e38f7..b5cbc8ee 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/Silverfish.java @@ -26,35 +26,32 @@ import java.util.*; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; -//right: 7, 66, 8 -//left: 23, 66, 8 -//right back: 7, 66, 24 -//polished andesite public class Silverfish extends DungeonPuzzle { private static final Logger LOGGER = LoggerFactory.getLogger(Silverfish.class); public static final Silverfish INSTANCE = new Silverfish(); - private static final float[] LIME_COLOR_COMPONENTS = DyeColor.LIME.getColorComponents(); - private final boolean[][] silverfishBoard = new boolean[17][17]; - private Vector2ic silverfishPos; - private final List silverfishPath = new ArrayList<>(); + private static final float[] RED_COLOR_COMPONENTS = DyeColor.RED.getColorComponents(); + final boolean[][] silverfishBoard = new boolean[17][17]; + Vector2ic silverfishPos; + final List silverfishPath = new ArrayList<>(); private Silverfish() { super("silverfish", "ice-silverfish-room"); + } + + public static void init() { if (Debug.debugEnabled()) { - ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("puzzle").then(literal(puzzleName) + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("puzzle").then(literal(INSTANCE.puzzleName) .then(literal("printBoard").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(silverfishBoard))); + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.silverfishBoard))); return Command.SINGLE_SUCCESS; })).then(literal("printPath").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(silverfishPath.toString())); + context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.silverfishPath.toString())); return Command.SINGLE_SUCCESS; })) ))))); } } - public static void init() {} - private static String boardToString(boolean[][] silverfishBoard) { StringBuilder sb = new StringBuilder(); for (boolean[] row : silverfishBoard) { @@ -85,13 +82,12 @@ public class Silverfish extends DungeonPuzzle { } } - BlockPos blockPos = room.relativeToActual(new BlockPos(16, 16, 16)); - List entities = client.world.getEntitiesByClass(SilverfishEntity.class, Box.of(Vec3d.ofCenter(blockPos), 32, 32, 32), silverfishEntity -> true); + List entities = client.world.getEntitiesByClass(SilverfishEntity.class, Box.of(Vec3d.ofCenter(room.relativeToActual(new BlockPos(15, 66, 16))), 16, 16, 16), silverfishEntity -> true); if (entities.isEmpty()) { return; } BlockPos newSilverfishBlockPos = room.actualToRelative(entities.get(0).getBlockPos()); - Vector2ic newSilverfishPos = new Vector2i(23 - newSilverfishBlockPos.getX(), 24 - newSilverfishBlockPos.getZ()); + Vector2ic newSilverfishPos = new Vector2i(24 - newSilverfishBlockPos.getZ(), 23 - newSilverfishBlockPos.getX()); if (newSilverfishPos.x() < 0 || newSilverfishPos.x() >= 17 || newSilverfishPos.y() < 0 || newSilverfishPos.y() >= 17) { return; } @@ -104,17 +100,18 @@ public class Silverfish extends DungeonPuzzle { } } - private void solve() { + void solve() { if (silverfishPos == null) { return; } Set visited = new HashSet<>(); Queue> queue = new ArrayDeque<>(); queue.add(List.of(silverfishPos)); + visited.add(silverfishPos); while (!queue.isEmpty()) { List path = queue.poll(); Vector2ic pos = path.get(path.size() - 1); - if (pos.equals(8, 0)) { + if (pos.x() == 0 && pos.y() >= 7 && pos.y() <= 9) { silverfishPath.clear(); silverfishPath.addAll(path); return; @@ -125,48 +122,37 @@ public class Silverfish extends DungeonPuzzle { posMutable.add(1, 0); } posMutable.add(-1, 0); - if (!visited.contains(posMutable)) { - ArrayList newPath = new ArrayList<>(path); - newPath.add(new Vector2i(posMutable)); - queue.add(newPath); - visited.add(posMutable); - } + addQueue(visited, queue, path, posMutable); - posMutable.set(pos); + posMutable = new Vector2i(pos); while (posMutable.x() >= 0 && !silverfishBoard[posMutable.x()][posMutable.y()]) { posMutable.add(-1, 0); } posMutable.add(1, 0); - if (!visited.contains(posMutable)) { - ArrayList newPath = new ArrayList<>(path); - newPath.add(new Vector2i(posMutable)); - queue.add(newPath); - visited.add(posMutable); - } + addQueue(visited, queue, path, posMutable); - posMutable.set(pos); + posMutable = new Vector2i(pos); while (posMutable.y() < 17 && !silverfishBoard[posMutable.x()][posMutable.y()]) { posMutable.add(0, 1); } posMutable.add(0, -1); - if (!visited.contains(posMutable)) { - ArrayList newPath = new ArrayList<>(path); - newPath.add(new Vector2i(posMutable)); - queue.add(newPath); - visited.add(posMutable); - } + addQueue(visited, queue, path, posMutable); - posMutable.set(pos); + posMutable = new Vector2i(pos); while (posMutable.y() >= 0 && !silverfishBoard[posMutable.x()][posMutable.y()]) { posMutable.add(0, -1); } posMutable.add(0, 1); - if (!visited.contains(posMutable)) { - ArrayList newPath = new ArrayList<>(path); - newPath.add(new Vector2i(posMutable)); - queue.add(newPath); - visited.add(posMutable); - } + addQueue(visited, queue, path, posMutable); + } + } + + private void addQueue(Set visited, Queue> queue, List path, Vector2ic newPos) { + if (!visited.contains(newPos)) { + List newPath = new ArrayList<>(path); + newPath.add(newPos); + queue.add(newPath); + visited.add(newPos); } } @@ -178,9 +164,9 @@ public class Silverfish extends DungeonPuzzle { Room room = DungeonManager.getCurrentRoom(); BlockPos.Mutable pos = new BlockPos.Mutable(); for (int i = 0; i < silverfishPath.size() - 1; i++) { - Vec3d start = Vec3d.ofCenter(room.relativeToActual(pos.set(23 - silverfishPath.get(i).x(), 67, 24 - silverfishPath.get(i).y()))); - Vec3d end = Vec3d.ofCenter(room.relativeToActual(pos.set(23 - silverfishPath.get(i + 1).x(), 67, 24 - silverfishPath.get(i + 1).y()))); - RenderHelper.renderLinesFromPoints(context, new Vec3d[]{start, end}, LIME_COLOR_COMPONENTS, 1f, 5f, true); + Vec3d start = Vec3d.ofCenter(room.relativeToActual(pos.set(23 - silverfishPath.get(i).y(), 67, 24 - silverfishPath.get(i).x()))); + Vec3d end = Vec3d.ofCenter(room.relativeToActual(pos.set(23 - silverfishPath.get(i + 1).y(), 67, 24 - silverfishPath.get(i + 1).x()))); + RenderHelper.renderLinesFromPoints(context, new Vec3d[]{start, end}, RED_COLOR_COMPONENTS, 1f, 5f, true); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java index 3244996a..ba4b9a5f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/waterboard/Waterboard.java @@ -88,17 +88,20 @@ public class Waterboard extends DungeonPuzzle { private Waterboard() { super("waterboard", "water-puzzle"); - UseBlockCallback.EVENT.register(this::onUseBlock); + } + + public static void init() { + UseBlockCallback.EVENT.register(INSTANCE::onUseBlock); if (Debug.debugEnabled()) { - ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("puzzle").then(literal(puzzleName) + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("puzzle").then(literal(INSTANCE.puzzleName) .then(literal("printBoard").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(cells))); + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.cells))); return Command.SINGLE_SUCCESS; })).then(literal("printDoors").executes(context -> { context.getSource().sendFeedback(Constants.PREFIX.get().append(Integer.toBinaryString(INSTANCE.doors))); return Command.SINGLE_SUCCESS; })).then(literal("printSimulationResults").then(argument("combination", IntegerArgumentType.integer(0, 63)).executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(results[IntegerArgumentType.getInteger(context, "combination")].toString())); + context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.results[IntegerArgumentType.getInteger(context, "combination")].toString())); return Command.SINGLE_SUCCESS; }))).then(literal("printCurrentCombination").executes(context -> { context.getSource().sendFeedback(Constants.PREFIX.get().append(Integer.toBinaryString(INSTANCE.currentCombination))); @@ -111,9 +114,6 @@ public class Waterboard extends DungeonPuzzle { } } - public static void init() { - } - private static String boardToString(Cell[][] cells) { StringBuilder sb = new StringBuilder(); for (Cell[] row : cells) { diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/SilverfishTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/SilverfishTest.java new file mode 100644 index 00000000..cc6178e1 --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/SilverfishTest.java @@ -0,0 +1,40 @@ +package de.hysky.skyblocker.skyblock.dungeon.puzzle; + +import org.joml.Vector2i; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class SilverfishTest { + private static final boolean[][] silverfishBoard = new boolean[][]{ + {false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false}, + {false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false}, + {true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false}, + {false, true, false, false, false, false, false, false, false, false, true, false, false, false, false, true, false}, + {false, false, true, false, false, false, false, false, false, false, false, true, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false}, + {false, false, true, false, false, false, false, false, false, false, false, false, false, true, false, false, false} + }; + + @Test + void testSilverfishSolve() { + for (int i = 0; i < silverfishBoard.length; i++) { + System.arraycopy(silverfishBoard[i], 0, Silverfish.INSTANCE.silverfishBoard[i], 0, silverfishBoard[i].length); + } + Silverfish.INSTANCE.silverfishPos = new Vector2i(15, 15); + Silverfish.INSTANCE.solve(); + List expectedSilverfishPath = List.of(new Vector2i(15, 15), new Vector2i(15, 11), new Vector2i(16, 11), new Vector2i(16, 3), new Vector2i(0, 3), new Vector2i(0, 4), new Vector2i(1, 4), new Vector2i(1, 2), new Vector2i(10, 2), new Vector2i(10, 9), new Vector2i(0, 9)); + Assertions.assertEquals(expectedSilverfishPath, Silverfish.INSTANCE.silverfishPath); + } +} -- cgit From b3132a89b5036e27d7efbb5dbe47f96e520bf851 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sat, 3 Feb 2024 11:55:32 -0500 Subject: Add config --- .../skyblocker/config/categories/DungeonsCategory.java | 14 ++++++++++++++ src/main/resources/assets/skyblocker/lang/en_us.json | 6 ++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/main/java') 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 5eb9a066..3ebd5d76 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -416,6 +416,20 @@ public class DungeonsCategory { newValue -> config.locations.dungeons.solveBoulder = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.solveIceFill")) + .binding(defaults.locations.dungeons.solveIceFill, + () -> config.locations.dungeons.solveIceFill, + newValue -> config.locations.dungeons.solveIceFill = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.solveSilverfish")) + .binding(defaults.locations.dungeons.solveSilverfish, + () -> config.locations.dungeons.solveSilverfish, + newValue -> config.locations.dungeons.solveSilverfish = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .option(Option.createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.fireFreezeStaffTimer")) .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.dungeons.fireFreezeStaffTimer.@Tooltip"))) diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 3c6c6349..7587ad51 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -271,6 +271,8 @@ "text.autoconfig.skyblocker.option.locations.dungeons.solveWaterboard.@Tooltip": "Click the levers with green boxes to solve the puzzle.", "text.autoconfig.skyblocker.option.locations.dungeons.solveBoulder": "Solve Boulder Puzzle", "text.autoconfig.skyblocker.option.locations.dungeons.solveBoulder.@Tooltip": "Draws a line to the chest and highlight button", + "text.autoconfig.skyblocker.option.locations.dungeons.solveIceFill": "Solve Waterboard Puzzle", + "text.autoconfig.skyblocker.option.locations.dungeons.solveSilverfish": "Solve Waterboard Puzzle", "text.autoconfig.skyblocker.option.locations.dungeons.mimicMessage": "Mimic Message", "text.autoconfig.skyblocker.option.locations.dungeons.mimicMessage.sendMimicMessage": "Enable Mimic Message", "text.autoconfig.skyblocker.option.locations.dungeons.mimicMessage.sendMimicMessage.@Tooltip": "Sends a message in chat upon killing a mimic for other players' score calculation mods.", @@ -408,7 +410,7 @@ "skyblocker.dungeons.secrets.customWaypointNotFound": "§cNo custom waypoint found at X: %d, Y: %d, Z: %d for room %s.", "skyblocker.dungeons.dungeonScore.scoreText": "Score: %s", "skyblocker.dungeons.puzzle.boulder.noSolution": "No solution found!", - + "skyblocker.dungeons.secretsTracker.feedback": "%s§f found %s§f secrets. %s", "skyblocker.dungeons.secretsTracker.failFeedback": "§cUnable to calculate the amount of secrets everybody did this run!", @@ -526,7 +528,7 @@ "skyblocker.partyFinder.yourParty": "Your party", "skyblocker.partyFinder.deList": "Click to de-list", "skyblocker.partyFinder.join": "Click to join", - + "skyblocker.crimson.kuudra.noArrowPoison": "No Arrow Poison!", "skyblocker.crimson.kuudra.lowArrowPoison": "Low on Arrow Poison!", -- cgit From 2fa902328a4a4a76f5ae300db7810530183b47d2 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sat, 3 Feb 2024 13:43:41 -0500 Subject: Change IceFill from bfs to dfs --- .../skyblock/dungeon/puzzle/IceFill.java | 137 ++++++++++++++++----- .../skyblock/dungeon/puzzle/IceFillTest.java | 27 ++++ 2 files changed, 136 insertions(+), 28 deletions(-) create mode 100644 src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java index 7ab96d78..166047b2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java @@ -120,50 +120,131 @@ public class IceFill extends DungeonPuzzle { return boardChanged; } - private void solve(boolean[][] iceFillBoard, List iceFillPath) { + void solve(boolean[][] iceFillBoard, List iceFillPath) { Vector2ic start = new Vector2i(iceFillBoard.length - 1, iceFillBoard[0].length / 2); int count = iceFillBoard.length * iceFillBoard[0].length - Arrays.stream(iceFillBoard).mapToInt(Booleans::countTrue).sum(); - Queue> queue = new ArrayDeque<>(); - queue.add(List.of(start)); - while (!queue.isEmpty()) { - List path = queue.poll(); - Vector2ic pos = path.get(path.size() - 1); - if (pos.x() == 0 && pos.y() == iceFillBoard[0].length / 2 && path.size() == count) { - iceFillPath.clear(); - iceFillPath.addAll(path); - return; - } + List newPath = solveDfs(iceFillBoard, count - 1, new ArrayList<>(List.of(start))); + if (newPath != null) { + iceFillPath.clear(); + iceFillPath.addAll(newPath); + } + } - Vector2i posMutable = pos.add(1, 0, new Vector2i()); - if (posMutable.x() < iceFillBoard.length && !iceFillBoard[posMutable.x()][posMutable.y()]) { - addQueue(queue, path, posMutable); + private List solveDfs(boolean[][] iceFillBoard, int count, List path) { + Vector2ic pos = path.get(path.size() - 1); + if (pos.x() == 0 && pos.y() == iceFillBoard[0].length / 2 && count == 0) { + return path; + } + + Vector2ic newPos = pos.add(1, 0, new Vector2i()); + if (newPos.x() < iceFillBoard.length && !iceFillBoard[newPos.x()][newPos.y()] && !path.contains(newPos)) { + path.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path); + if (newPath != null) { + return newPath; + } else { + path.remove(path.size() - 1); } + } - posMutable = pos.add(-1, 0, new Vector2i()); - if (posMutable.x() >= 0 && !iceFillBoard[posMutable.x()][posMutable.y()]) { - addQueue(queue, path, posMutable); + newPos = pos.add(-1, 0, new Vector2i()); + if (newPos.x() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !path.contains(newPos)) { + path.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path); + if (newPath != null) { + return newPath; + } else { + path.remove(path.size() - 1); } + } - posMutable = pos.add(0, 1, new Vector2i()); - if (posMutable.y() < iceFillBoard[0].length && !iceFillBoard[posMutable.x()][posMutable.y()]) { - addQueue(queue, path, posMutable); + newPos = pos.add(0, 1, new Vector2i()); + if (newPos.y() < iceFillBoard[0].length && !iceFillBoard[newPos.x()][newPos.y()] && !path.contains(newPos)) { + path.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path); + if (newPath != null) { + return newPath; + } else { + path.remove(path.size() - 1); } + } - posMutable = pos.add(0, -1, new Vector2i()); - if (posMutable.y() >= 0 && !iceFillBoard[posMutable.x()][posMutable.y()]) { - addQueue(queue, path, posMutable); + newPos = pos.add(0, -1, new Vector2i()); + if (newPos.y() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !path.contains(newPos)) { + path.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path); + if (newPath != null) { + return newPath; + } else { + path.remove(path.size() - 1); } } + + return null; + } + + /* + void solve(boolean[][] iceFillBoard, List iceFillPath) { + Vector2ic start = new Vector2i(iceFillBoard.length - 1, iceFillBoard[0].length / 2); + int count = iceFillBoard.length * iceFillBoard[0].length - Arrays.stream(iceFillBoard).mapToInt(Booleans::countTrue).sum(); + + Vector2ic[] newPath = solveDfs(iceFillBoard, count - 1, new Vector2ic[]{start}); + if (newPath != null) { + iceFillPath.clear(); + iceFillPath.addAll(Arrays.asList(newPath)); + } } - private void addQueue(Queue> queue, List path, Vector2ic newPos) { - if (!path.contains(newPos)) { - List newPath = new ArrayList<>(path); - newPath.add(newPos); - queue.add(newPath); + private Vector2ic[] solveDfs(boolean[][] iceFillBoard, int count, Vector2ic[] path) { + Vector2ic pos = path[path.length - 1]; + if (pos.x() == 0 && pos.y() == iceFillBoard[0].length / 2 && count == 0) { + return path; + } + + Vector2ic newPos = pos.add(1, 0, new Vector2i()); + if (newPos.x() < iceFillBoard.length && !iceFillBoard[newPos.x()][newPos.y()] && !ArrayUtils.contains(path, newPos)) { + Vector2ic[] newPath = Arrays.copyOf(path, path.length + 1); + newPath[path.length] = newPos; + newPath = solveDfs(iceFillBoard, count - 1, newPath); + if (newPath != null) { + return newPath; + } + } + + newPos = pos.add(-1, 0, new Vector2i()); + if (newPos.x() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !ArrayUtils.contains(path, newPos)) { + Vector2ic[] newPath = Arrays.copyOf(path, path.length + 1); + newPath[path.length] = newPos; + newPath = solveDfs(iceFillBoard, count - 1, newPath); + if (newPath != null) { + return newPath; + } + } + + newPos = pos.add(0, 1, new Vector2i()); + if (newPos.y() < iceFillBoard[0].length && !iceFillBoard[newPos.x()][newPos.y()] && !ArrayUtils.contains(path, newPos)) { + Vector2ic[] newPath = Arrays.copyOf(path, path.length + 1); + newPath[path.length] = newPos; + newPath = solveDfs(iceFillBoard, count - 1, newPath); + if (newPath != null) { + return newPath; + } } + + newPos = pos.add(0, -1, new Vector2i()); + if (newPos.y() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !ArrayUtils.contains(path, newPos)) { + Vector2ic[] newPath = Arrays.copyOf(path, path.length + 1); + newPath[path.length] = newPos; + newPath = solveDfs(iceFillBoard, count - 1, newPath); + if (newPath != null) { + return newPath; + } + } + + return null; } + */ @Override public void render(WorldRenderContext context) { diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java new file mode 100644 index 00000000..511d1148 --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java @@ -0,0 +1,27 @@ +package de.hysky.skyblocker.skyblock.dungeon.puzzle; + +import org.joml.Vector2ic; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +public class IceFillTest { + private static final boolean[][] iceFillBoard = new boolean[][]{ + {false, false, true, false, false, false, false}, + {false, false, false, false, false, false, false}, + {false, false, false, true, true, false, false}, + {false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false}, + {true, false, false, false, false, false, false}, + }; + private static final List iceFillPath = new ArrayList<>(); + + @Test + void testIceFillSolve() { + IceFill.INSTANCE.solve(iceFillBoard, iceFillPath); + System.out.println(iceFillPath); + System.out.println(iceFillPath.size()); + } +} -- cgit From b463261d5d1e70d6f0f350bc2a2507e4483d31c3 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sat, 3 Feb 2024 16:15:47 -0500 Subject: Optimize ice fill --- .../skyblock/dungeon/puzzle/IceFill.java | 110 ++++++--------------- .../skyblock/dungeon/puzzle/IceFillTest.java | 6 +- 2 files changed, 32 insertions(+), 84 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java index 166047b2..9b6e7b1f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java @@ -124,127 +124,73 @@ public class IceFill extends DungeonPuzzle { Vector2ic start = new Vector2i(iceFillBoard.length - 1, iceFillBoard[0].length / 2); int count = iceFillBoard.length * iceFillBoard[0].length - Arrays.stream(iceFillBoard).mapToInt(Booleans::countTrue).sum(); - List newPath = solveDfs(iceFillBoard, count - 1, new ArrayList<>(List.of(start))); + List newPath = solveDfs(iceFillBoard, count - 1, new ArrayList<>(List.of(start)), new HashSet<>(List.of(start))); if (newPath != null) { iceFillPath.clear(); iceFillPath.addAll(newPath); } } - private List solveDfs(boolean[][] iceFillBoard, int count, List path) { + private List solveDfs(boolean[][] iceFillBoard, int count, List path, Set visited) { Vector2ic pos = path.get(path.size() - 1); - if (pos.x() == 0 && pos.y() == iceFillBoard[0].length / 2 && count == 0) { - return path; + if (count == 0) { + if (pos.x() == 0 && pos.y() == iceFillBoard[0].length / 2) { + return path; + } else { + return null; + } } Vector2ic newPos = pos.add(1, 0, new Vector2i()); - if (newPos.x() < iceFillBoard.length && !iceFillBoard[newPos.x()][newPos.y()] && !path.contains(newPos)) { + if (newPos.x() < iceFillBoard.length && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { path.add(newPos); - List newPath = solveDfs(iceFillBoard, count - 1, path); + visited.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path, visited); if (newPath != null) { return newPath; - } else { - path.remove(path.size() - 1); } + path.remove(path.size() - 1); + visited.remove(newPos); } newPos = pos.add(-1, 0, new Vector2i()); - if (newPos.x() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !path.contains(newPos)) { + if (newPos.x() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { path.add(newPos); - List newPath = solveDfs(iceFillBoard, count - 1, path); + visited.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path, visited); if (newPath != null) { return newPath; - } else { - path.remove(path.size() - 1); } + path.remove(path.size() - 1); + visited.remove(newPos); } newPos = pos.add(0, 1, new Vector2i()); - if (newPos.y() < iceFillBoard[0].length && !iceFillBoard[newPos.x()][newPos.y()] && !path.contains(newPos)) { + if (newPos.y() < iceFillBoard[0].length && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { path.add(newPos); - List newPath = solveDfs(iceFillBoard, count - 1, path); + visited.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path, visited); if (newPath != null) { return newPath; - } else { - path.remove(path.size() - 1); } + path.remove(path.size() - 1); + visited.remove(newPos); } newPos = pos.add(0, -1, new Vector2i()); - if (newPos.y() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !path.contains(newPos)) { + if (newPos.y() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { path.add(newPos); - List newPath = solveDfs(iceFillBoard, count - 1, path); - if (newPath != null) { - return newPath; - } else { - path.remove(path.size() - 1); - } - } - - return null; - } - - /* - void solve(boolean[][] iceFillBoard, List iceFillPath) { - Vector2ic start = new Vector2i(iceFillBoard.length - 1, iceFillBoard[0].length / 2); - int count = iceFillBoard.length * iceFillBoard[0].length - Arrays.stream(iceFillBoard).mapToInt(Booleans::countTrue).sum(); - - Vector2ic[] newPath = solveDfs(iceFillBoard, count - 1, new Vector2ic[]{start}); - if (newPath != null) { - iceFillPath.clear(); - iceFillPath.addAll(Arrays.asList(newPath)); - } - } - - private Vector2ic[] solveDfs(boolean[][] iceFillBoard, int count, Vector2ic[] path) { - Vector2ic pos = path[path.length - 1]; - if (pos.x() == 0 && pos.y() == iceFillBoard[0].length / 2 && count == 0) { - return path; - } - - Vector2ic newPos = pos.add(1, 0, new Vector2i()); - if (newPos.x() < iceFillBoard.length && !iceFillBoard[newPos.x()][newPos.y()] && !ArrayUtils.contains(path, newPos)) { - Vector2ic[] newPath = Arrays.copyOf(path, path.length + 1); - newPath[path.length] = newPos; - newPath = solveDfs(iceFillBoard, count - 1, newPath); - if (newPath != null) { - return newPath; - } - } - - newPos = pos.add(-1, 0, new Vector2i()); - if (newPos.x() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !ArrayUtils.contains(path, newPos)) { - Vector2ic[] newPath = Arrays.copyOf(path, path.length + 1); - newPath[path.length] = newPos; - newPath = solveDfs(iceFillBoard, count - 1, newPath); - if (newPath != null) { - return newPath; - } - } - - newPos = pos.add(0, 1, new Vector2i()); - if (newPos.y() < iceFillBoard[0].length && !iceFillBoard[newPos.x()][newPos.y()] && !ArrayUtils.contains(path, newPos)) { - Vector2ic[] newPath = Arrays.copyOf(path, path.length + 1); - newPath[path.length] = newPos; - newPath = solveDfs(iceFillBoard, count - 1, newPath); - if (newPath != null) { - return newPath; - } - } - - newPos = pos.add(0, -1, new Vector2i()); - if (newPos.y() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !ArrayUtils.contains(path, newPos)) { - Vector2ic[] newPath = Arrays.copyOf(path, path.length + 1); - newPath[path.length] = newPos; - newPath = solveDfs(iceFillBoard, count - 1, newPath); + visited.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path, visited); if (newPath != null) { return newPath; } + path.remove(path.size() - 1); + visited.remove(newPos); } return null; } - */ @Override public void render(WorldRenderContext context) { diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java index 511d1148..a3cbb93f 100644 --- a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFillTest.java @@ -1,6 +1,8 @@ package de.hysky.skyblocker.skyblock.dungeon.puzzle; +import org.joml.Vector2i; import org.joml.Vector2ic; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -21,7 +23,7 @@ public class IceFillTest { @Test void testIceFillSolve() { IceFill.INSTANCE.solve(iceFillBoard, iceFillPath); - System.out.println(iceFillPath); - System.out.println(iceFillPath.size()); + List expectedIceFillPath = List.of(new Vector2i(6, 3), new Vector2i(5, 3), new Vector2i(4, 3), new Vector2i(3, 3), new Vector2i(3, 2), new Vector2i(4, 2), new Vector2i(5, 2), new Vector2i(6, 2), new Vector2i(6, 1), new Vector2i(5, 1), new Vector2i(5, 0), new Vector2i(4, 0), new Vector2i(4, 1), new Vector2i(3, 1), new Vector2i(3, 0), new Vector2i(2, 0), new Vector2i(1, 0), new Vector2i(0, 0), new Vector2i(0, 1), new Vector2i(1, 1), new Vector2i(2, 1), new Vector2i(2, 2), new Vector2i(1, 2), new Vector2i(1, 3), new Vector2i(1, 4), new Vector2i(1, 5), new Vector2i(2, 5), new Vector2i(3, 5), new Vector2i(3, 4), new Vector2i(4, 4), new Vector2i(5, 4), new Vector2i(6, 4), new Vector2i(6, 5), new Vector2i(6, 6), new Vector2i(5, 6), new Vector2i(5, 5), new Vector2i(4, 5), new Vector2i(4, 6), new Vector2i(3, 6), new Vector2i(2, 6), new Vector2i(1, 6), new Vector2i(0, 6), new Vector2i(0, 5), new Vector2i(0, 4), new Vector2i(0, 3)); + Assertions.assertEquals(expectedIceFillPath, iceFillPath); } } -- cgit From 15268d52e7529c11dd4734005ae7b0815c68b7a4 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 15 Feb 2024 11:38:12 -0500 Subject: Refactor IceFill --- .../skyblock/dungeon/puzzle/IceFill.java | 106 ++++++--------------- 1 file changed, 31 insertions(+), 75 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java index 9b6e7b1f..57386674 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/IceFill.java @@ -28,16 +28,14 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.lit public class IceFill extends DungeonPuzzle { public static final IceFill INSTANCE = new IceFill(); private static final float[] RED_COLOR_COMPONENTS = DyeColor.RED.getColorComponents(); - private static final BlockPos BOARD_1_ORIGIN = new BlockPos(16, 70, 9); - private static final BlockPos BOARD_2_ORIGIN = new BlockPos(17, 71, 16); - private static final BlockPos BOARD_3_ORIGIN = new BlockPos(18, 72, 25); + private static final BlockPos[] BOARD_ORIGINS = { + new BlockPos(16, 70, 9), + new BlockPos(17, 71, 16), + new BlockPos(18, 72, 25) + }; private CompletableFuture solve; - private final boolean[][] iceFillBoard1 = new boolean[3][3]; - private final boolean[][] iceFillBoard2 = new boolean[5][5]; - private final boolean[][] iceFillBoard3 = new boolean[7][7]; - private final List iceFillPath1 = new ArrayList<>(); - private final List iceFillPath2 = new ArrayList<>(); - private final List iceFillPath3 = new ArrayList<>(); + private final boolean[][][] iceFillBoards = {new boolean[3][3], new boolean[5][5], new boolean[7][7]}; + private final List> iceFillPaths = List.of(new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); private IceFill() { super("ice-fill", "ice-path"); @@ -47,22 +45,22 @@ public class IceFill extends DungeonPuzzle { if (Debug.debugEnabled()) { ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("dungeons").then(literal("puzzle").then(literal(INSTANCE.puzzleName) .then(literal("printBoard1").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoard1))); + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoards[0]))); return Command.SINGLE_SUCCESS; })).then(literal("printBoard2").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoard2))); + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoards[1]))); return Command.SINGLE_SUCCESS; })).then(literal("printBoard3").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoard3))); + context.getSource().sendFeedback(Constants.PREFIX.get().append(boardToString(INSTANCE.iceFillBoards[2]))); return Command.SINGLE_SUCCESS; })).then(literal("printPath1").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPath1.toString())); + context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPaths.get(0).toString())); return Command.SINGLE_SUCCESS; })).then(literal("printPath2").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPath2.toString())); + context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPaths.get(1).toString())); return Command.SINGLE_SUCCESS; })).then(literal("printPath3").executes(context -> { - context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPath3.toString())); + context.getSource().sendFeedback(Constants.PREFIX.get().append(INSTANCE.iceFillPaths.get(2).toString())); return Command.SINGLE_SUCCESS; })) ))))); @@ -89,18 +87,10 @@ public class IceFill extends DungeonPuzzle { solve = CompletableFuture.runAsync(() -> { BlockPos.Mutable pos = new BlockPos.Mutable(); - boolean board1Changed = updateBoard(client.world, room, iceFillBoard1, pos.set(BOARD_1_ORIGIN)); - boolean board2Changed = updateBoard(client.world, room, iceFillBoard2, pos.set(BOARD_2_ORIGIN)); - boolean board3Changed = updateBoard(client.world, room, iceFillBoard3, pos.set(BOARD_3_ORIGIN)); - - if (board1Changed) { - solve(iceFillBoard1, iceFillPath1); - } - if (board2Changed) { - solve(iceFillBoard2, iceFillPath2); - } - if (board3Changed) { - solve(iceFillBoard3, iceFillPath3); + for (int i = 0; i < 3; i++) { + if (updateBoard(client.world, room, iceFillBoards[i], pos.set(BOARD_ORIGINS[i]))) { + solve(iceFillBoards[i], iceFillPaths.get(i)); + } } }); } @@ -141,52 +131,18 @@ public class IceFill extends DungeonPuzzle { } } - Vector2ic newPos = pos.add(1, 0, new Vector2i()); - if (newPos.x() < iceFillBoard.length && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { - path.add(newPos); - visited.add(newPos); - List newPath = solveDfs(iceFillBoard, count - 1, path, visited); - if (newPath != null) { - return newPath; - } - path.remove(path.size() - 1); - visited.remove(newPos); - } - - newPos = pos.add(-1, 0, new Vector2i()); - if (newPos.x() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { - path.add(newPos); - visited.add(newPos); - List newPath = solveDfs(iceFillBoard, count - 1, path, visited); - if (newPath != null) { - return newPath; - } - path.remove(path.size() - 1); - visited.remove(newPos); - } - - newPos = pos.add(0, 1, new Vector2i()); - if (newPos.y() < iceFillBoard[0].length && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { - path.add(newPos); - visited.add(newPos); - List newPath = solveDfs(iceFillBoard, count - 1, path, visited); - if (newPath != null) { - return newPath; - } - path.remove(path.size() - 1); - visited.remove(newPos); - } - - newPos = pos.add(0, -1, new Vector2i()); - if (newPos.y() >= 0 && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { - path.add(newPos); - visited.add(newPos); - List newPath = solveDfs(iceFillBoard, count - 1, path, visited); - if (newPath != null) { - return newPath; + Vector2ic[] newPosArray = {pos.add(1, 0, new Vector2i()), pos.add(-1, 0, new Vector2i()), pos.add(0, 1, new Vector2i()), pos.add(0, -1, new Vector2i())}; + for (Vector2ic newPos : newPosArray) { + if (newPos.x() >= 0 && newPos.x() < iceFillBoard.length && newPos.y() >= 0 && newPos.y() < iceFillBoard[0].length && !iceFillBoard[newPos.x()][newPos.y()] && !visited.contains(newPos)) { + path.add(newPos); + visited.add(newPos); + List newPath = solveDfs(iceFillBoard, count - 1, path, visited); + if (newPath != null) { + return newPath; + } + path.remove(path.size() - 1); + visited.remove(newPos); } - path.remove(path.size() - 1); - visited.remove(newPos); } return null; @@ -198,9 +154,9 @@ public class IceFill extends DungeonPuzzle { return; } Room room = DungeonManager.getCurrentRoom(); - renderPath(context, room, iceFillPath1, BOARD_1_ORIGIN); - renderPath(context, room, iceFillPath2, BOARD_2_ORIGIN); - renderPath(context, room, iceFillPath3, BOARD_3_ORIGIN); + for (int i = 0; i < 3; i++) { + renderPath(context, room, iceFillPaths.get(i), BOARD_ORIGINS[i]); + } } private void renderPath(WorldRenderContext context, Room room, List iceFillPath, BlockPos originPos) { -- cgit